Trình tải khởi động là gì và tôi sẽ phát triển nó như thế nào?


53

Tôi đã gặp nhiều dự án trong đó một bộ vi điều khiển AVR sử dụng với bộ tải khởi động (như Arduino), nhưng tôi không hiểu rõ về khái niệm này.

Làm cách nào để tạo bộ nạp khởi động (cho bất kỳ vi điều khiển nào)?

Sau khi viết bộ tải khởi động của tôi, làm thế nào nó được lập trình cho vi điều khiển (giống như bất kỳ chương trình .hex nào bị cháy trên flash rom của AVR, hoặc một số phương pháp khác)?


10
Bạn đã gắn thẻ nó với thẻ bootloader , bạn đã đọc qua điều đó chưa? Nếu vậy, bạn đã đọc Arduino Bootloader , Arduino Bootloader Follow On , Arduino Bootloader , Các công cụ hay phương pháp tốt để hiểu cấu trúc của bootloaderArduino Bootloader Chi tiết câu hỏi? Đó là tất cả các phần địa chỉ của câu hỏi ban đầu của bạn. Tôi đã cắt nó xuống những thứ mới.
Kevin Vermeer

Một bài viết về Phương pháp thiết kế BootLoader: beningo.com/wp-content/uploads/images/Papers/ triệt
yahya tawil

2
@KevinVermeer Tôi nghĩ câu hỏi của anh ấy đơn giản hơn.
richieqianle

Câu trả lời:


103

Bootloader là một chương trình chạy trong vi điều khiển được lập trình. Nó nhận thông tin chương trình mới bên ngoài thông qua một số phương tiện giao tiếp và ghi thông tin đó vào bộ nhớ chương trình của bộ xử lý.

Điều này trái ngược với cách thông thường để đưa chương trình vào vi điều khiển, thông qua phần cứng đặc biệt được tích hợp vào vi mô cho mục đích đó. Trên PIC, đây là giao diện giống SPI. Nếu tôi nhớ đúng, các AVR sử dụng Jtag, hoặc ít nhất một số trong số họ làm. Dù bằng cách nào, điều này đòi hỏi một số phần cứng bên ngoài làm rung các chân lập trình vừa phải để ghi thông tin vào bộ nhớ chương trình. Tệp HEX mô tả nội dung bộ nhớ chương trình bắt nguồn từ một máy tính có mục đích chung, do đó phần cứng này kết nối với máy tính ở một bên và các chân lập trình đặc biệt của micro ở bên kia. Công ty của tôi làm cho các lập trình viên PIC trong số những thứ khác như một phụ kiện, vì vậy tôi khá quen thuộc với quy trình này trên PIC.

Điểm quan trọng của lập trình bên ngoài thông qua phần cứng chuyên dụng là nó hoạt động bất kể nội dung hiện có của bộ nhớ chương trình. Bộ vi điều khiển bắt đầu với bộ nhớ chương trình bị xóa hoặc ở trạng thái không xác định, vì vậy lập trình bên ngoài là phương tiện duy nhất để đưa chương trình đầu tiên vào vi mô.

Nếu bạn chắc chắn về chương trình bạn muốn tải vào sản phẩm của mình và khối lượng của bạn đủ cao, bạn có thể có nhà sản xuất hoặc chip chương trình phân phối cho bạn. Con chip được hàn vào bảng như mọi con chip khác, và thiết bị đã sẵn sàng hoạt động. Điều này có thể thích hợp cho một cái gì đó như một món đồ chơi, ví dụ. Khi phần sụn được hoàn thành, nó đã được thực hiện khá nhiều và nó sẽ được sản xuất với khối lượng lớn.

Nếu khối lượng của bạn thấp hơn hoặc quan trọng hơn, bạn mong đợi sự phát triển phần sụn và sửa lỗi đang diễn ra, bạn không muốn mua chip được lập trình sẵn. Trong trường hợp này, chip trống được gắn trên bo mạch và phần sụn phải được tải lên chip như một phần của quy trình sản xuất. Trong trường hợp đó, các dòng lập trình phần cứng phải được cung cấp bằng cách nào đó. Điều này có thể thông qua một đầu nối rõ ràng hoặc các miếng pin pogo nếu bạn sẵn sàng tạo ra một vật cố thử nghiệm sản xuất. Thông thường các sản phẩm như vậy phải được kiểm tra và có thể được hiệu chỉnh bằng mọi giá, vì vậy chi phí bổ sung để viết chương trình cho bộ xử lý thường là tối thiểu. Đôi khi, khi các bộ xử lý nhỏ được sử dụng, phần sụn thử nghiệm sản xuất đặc biệt sẽ được nạp vào bộ xử lý trước tiên. Điều này được sử dụng để tạo điều kiện cho việc kiểm tra và hiệu chỉnh thiết bị, sau đó phần sụn thực sự được tải sau khi phần cứng được biết là tốt. Trong trường hợp này, có một số cân nhắc thiết kế mạch để cho phép truy cập vào các dòng lập trình đủ để quá trình lập trình hoạt động nhưng cũng không gây bất tiện cho mạch quá nhiều. Để biết thêm chi tiết về điều này, xem của tôilập trình trong mạch viết.

Cho đến nay là tốt, và không cần bootloader. Tuy nhiên, hãy xem xét một sản phẩm có phần sụn tương đối phức tạp mà bạn muốn nâng cấp trường hoặc thậm chí cho phép khách hàng cuối cùng nâng cấp. Bạn không thể mong đợi khách hàng cuối cùng có một tiện ích lập trình viên, hoặc biết cách sử dụng đúng cách ngay cả khi bạn cung cấp một tiện ích. Trên thực tế một trong những khách hàng của tôi làm điều này. Nếu bạn mua tùy chọn tùy chỉnh trường đặc biệt của họ, bạn sẽ có được một trong những lập trình viên của tôi với sản phẩm.

Tuy nhiên, trong hầu hết các trường hợp, bạn chỉ muốn khách hàng chạy chương trình trên PC và có phần sụn được cập nhật một cách kỳ diệu. Đây là nơi có bộ tải khởi động, đặc biệt nếu sản phẩm của bạn đã có cổng giao tiếp có thể dễ dàng giao tiếp với PC, như USB, RS-232 hoặc ethernet. Khách hàng chạy chương trình PC nói chuyện với bộ tải khởi động đã có trong micro. Điều này sẽ gửi nhị phân mới đến bộ nạp khởi động, nó ghi nó vào bộ nhớ chương trình và sau đó làm cho mã mới được chạy.

Nghe có vẻ đơn giản, nhưng không, ít nhất là không nếu bạn muốn quá trình này diễn ra mạnh mẽ. Điều gì xảy ra nếu một lỗi giao tiếp xảy ra và phần sụn mới bị hỏng theo thời gian nó đến bộ nạp khởi động? Điều gì xảy ra nếu nguồn điện bị gián đoạn trong quá trình khởi động? Điều gì xảy ra nếu bootloader có lỗi và craps trên chính nó?

Một kịch bản đơn giản là bộ nạp khởi động luôn chạy từ thiết lập lại. Nó cố gắng giao tiếp với chủ nhà. Nếu máy chủ trả lời, thì nó sẽ báo cho bộ tải khởi động, nó không có gì mới, hoặc gửi cho nó mã mới. Khi mã mới đến, mã cũ bị ghi đè. Bạn luôn bao gồm một tổng kiểm tra với mã được tải lên, vì vậy bộ tải khởi động có thể cho biết ứng dụng mới có còn nguyên vẹn hay không. Nếu không, nó vẫn ở trong bộ tải khởi động liên tục yêu cầu tải lên cho đến khi một cái gì đó có tổng kiểm tra hợp lệ được tải vào bộ nhớ. Điều này có thể được chấp nhận đối với một thiết bị luôn được kết nối và có thể là nơi một tác vụ nền được chạy trên máy chủ đáp ứng các yêu cầu của bộ tải khởi động. Sơ đồ này không tốt cho các đơn vị chủ yếu tự chủ và chỉ thỉnh thoảng kết nối với máy tính chủ.

Thông thường bộ tải khởi động đơn giản như mô tả ở trên không được chấp nhận vì không có lỗi an toàn. Nếu hình ảnh ứng dụng mới không được nhận nguyên vẹn, bạn muốn thiết bị tiếp tục chạy hình ảnh cũ, không bị chết cho đến khi tải lên thành công được thực hiện. Vì lý do này, thông thường có hai mô-đun đặc biệt trong phần sụn, trình tải lên và bộ tải khởi động. Trình tải lên là một phần của ứng dụng chính. Là một phần của giao tiếp thường xuyên với máy chủ, hình ảnh ứng dụng mới có thể được tải lên. Điều này đòi hỏi bộ nhớ riêng biệt từ hình ảnh ứng dụng chính, như EEPROM bên ngoài hoặc sử dụng bộ xử lý lớn hơn để có thể phân bổ một nửa không gian bộ nhớ chương trình để lưu trữ hình ảnh ứng dụng mới. Trình tải lên chỉ ghi hình ảnh ứng dụng mới nhận được ở đâu đó, nhưng không chạy nó. Khi bộ xử lý được đặt lại, điều này có thể xảy ra với lệnh từ máy chủ sau khi tải lên, bộ nạp khởi động chạy. Đây là một chương trình hoàn toàn khép kín, không cần khả năng giao tiếp bên ngoài. Nó so sánh các phiên bản ứng dụng hiện tại và đã tải lên, kiểm tra tổng kiểm tra của chúng và sao chép hình ảnh mới vào khu vực ứng dụng nếu các phiên bản khác nhau và kiểm tra tổng kiểm tra hình ảnh mới. Nếu hình ảnh mới bị hỏng, nó chỉ đơn giản là chạy ứng dụng cũ như trước đây.

Tôi đã thực hiện rất nhiều bộ tải khởi động, và không có hai cái nào giống nhau. Không có bộ tải khởi động cho mục đích chung, mặc dù những gì một số công ty vi điều khiển muốn bạn tin tưởng. Mỗi thiết bị có yêu cầu riêng và hoàn cảnh đặc biệt trong giao dịch với máy chủ. Đây chỉ là một số cấu hình của bộ tải khởi động và đôi khi là trình tải lên mà tôi đã sử dụng:

  1. Bộ tải khởi động cơ bản. Thiết bị này có một đường nối tiếp và sẽ được kết nối với máy chủ và bật khi cần thiết. Bộ tải khởi động đã chạy từ thiết lập lại và gửi một vài phản hồi yêu cầu tải lên máy chủ lưu trữ. Nếu chương trình tải lên đang chạy, nó sẽ phản hồi và gửi hình ảnh ứng dụng mới. Nếu nó không phản hồi trong vòng 500 ms, bộ tải khởi động sẽ từ bỏ và chạy ứng dụng hiện có. Do đó, để cập nhật chương trình cơ sở, trước tiên bạn phải chạy ứng dụng cập nhật trên máy chủ, sau đó kết nối và bật nguồn cho thiết bị.

  2. Trình tải lên bộ nhớ chương trình. Ở đây chúng tôi sử dụng PIC kích thước tiếp theo có bộ nhớ chương trình gấp đôi. Bộ nhớ chương trình được chia thành 49% ứng dụng chính, 49% hình ảnh ứng dụng mới và 2% bộ tải khởi động. Bộ tải khởi động sẽ chạy từ thiết lập lại và sao chép hình ảnh ứng dụng mới vào hình ảnh ứng dụng hiện tại trong các điều kiện phù hợp.

  3. Hình ảnh EEPROM bên ngoài. Giống như # 2 ngoại trừ việc sử dụng EEPROM bên ngoài để lưu trữ hình ảnh ứng dụng mới. Trong trường hợp này, bộ xử lý có nhiều bộ nhớ hơn cũng sẽ lớn hơn về mặt vật lý và trong một phân họ khác không có sự kết hợp của các thiết bị ngoại vi mà chúng ta cần.

  4. Bộ tải khởi động TCP. Đây là phức tạp nhất của tất cả chúng. Một PIC 18F lớn đã được sử dụng. 1/4 bộ nhớ cuối cùng giữ bộ tải khởi động, có bản sao hoàn chỉnh của ngăn xếp mạng TCP. Bộ tải khởi động đã chạy từ thiết lập lại và cố gắng kết nối với một máy chủ tải lên đặc biệt tại một cổng được biết đến tại một địa chỉ IP được cấu hình trước đó. Điều này là cho các cài đặt lớn, nơi luôn có một máy chủ chuyên dụng cho toàn bộ hệ thống. Mỗi thiết bị nhỏ sẽ đăng ký với máy chủ tải lên sau khi đặt lại và sẽ được cung cấp một bản sao ứng dụng mới khi thích hợp. Bộ tải khởi động sẽ ghi đè lên ứng dụng hiện có với bản sao mới, nhưng chỉ chạy nó nếu kiểm tra tổng kiểm tra. Nếu không, nó sẽ quay trở lại máy chủ tải lên và thử lại.

    Do bộ tải khởi động tự nó là một đoạn mã phức tạp chứa một ngăn xếp mạng TCP đầy đủ, nên nó cũng phải được nâng cấp trường. Họ đã làm như vậy là để máy chủ tải lên cung cấp cho nó một ứng dụng đặc biệt với mục đích duy nhất là ghi đè lên bộ tải khởi động khi nó được thực thi, sau đó đặt lại máy để bộ tải khởi động mới chạy, điều này sẽ khiến máy chủ tải lên gửi hình ảnh ứng dụng chính mới nhất. Về mặt kỹ thuật, một trục trặc về năng lượng trong vài mili giây, ứng dụng đặc biệt này đã sao chép một hình ảnh mới qua bộ tải khởi động sẽ là một thất bại không thể phục hồi. Trong thực tế điều này không bao giờ xảy ra. Chúng tôi rất ổn với khả năng rất khó xảy ra vì các thiết bị này là một phần của các cài đặt lớn, nơi đã có những người sẽ bảo trì hệ thống, điều này đôi khi có nghĩa là thay thế các thiết bị nhúng vì lý do khác.

Hy vọng rằng bạn có thể thấy rằng có một số khả năng khác, mỗi khả năng có sự đánh đổi rủi ro, tốc độ, chi phí, dễ sử dụng, thời gian chết, v.v.


1
Tất cả các AVR ngoại trừ họ Xmega (có giao diện 2 dây mới) đều sử dụng giao diện SPI trong khi được giữ lại. Những cái lớn hơn cũng có JTAG, một số có lập trình song song và những cái nhỏ hơn có thể yêu cầu điện áp cao nếu thiết lập lại đã được cấu hình lại thành I / O. Một số MCU, như Parallax Propeller và Motorola / Freescale 68HC08, không có phần cứng lập trình tối thiểu mà chỉ có bộ tải khởi động trong ROM.
Yann Vernier

Nó so sánh các phiên bản ứng dụng hiện tại và đã tải lên, kiểm tra tổng kiểm tra của chúng và sao chép hình ảnh mới vào khu vực ứng dụng nếu các phiên bản khác nhau và kiểm tra tổng kiểm tra hình ảnh mới. Có nhưng điều gì sẽ xảy ra nếu nguồn điện bị gián đoạn ở giữa hành động này, sẽ có một hình ảnh bị hỏng trong "khu vực ứng dụng". Tôi cho rằng có thể tốt hơn khi có ứng dụng bootloader-failafe-app viết ứng dụng mới trong flash mcu và nếu tổng kiểm tra hợp lệ, nó cũng viết một nơi nào đó "ok để khởi động ứng dụng mới". Vì vậy, khi bắt đầu, nó sẽ kiểm tra xem có khởi động ứng dụng mới hay không, nếu nó không tiếp tục tự thực thi (ứng dụng
failafe

@Erv: Nếu mất điện giữa lúc sao chép phiên bản mới vào hiện tại, thì tổng kiểm tra phiên bản hiện tại sẽ thất bại khi nguồn điện trở lại và bộ tải khởi động chạy lại. Tôi thường đặt từ tổng kiểm tra ở cuối hình ảnh để bất kỳ ghi một phần nào cũng có khả năng thất bại rất cao.
Olin Lathrop

Chào. Tôi có thể khuyên bạn nên bộ nạp khởi động loại 5 - thay vì ngăn xếp TCP, bạn có thể triển khai UDP. Sau đó sử dụng TFTP để tải xuống bản cập nhật hoặc giao thức gốc.
i486

22

Khái niệm về bộ nạp khởi động là gì?

Hình dung kịch bản này: Bạn có một lượng lưu trữ hợp lý trên vi điều khiển của mình - đủ để lưu trữ hơn 2-3 chương trình hoặc ứng dụng độc lập với nhau. Giả sử rằng khi bạn khởi động thiết bị của mình, bạn có thể muốn chọn thiết bị nào để chạy. Vì vậy, những gì bạn sẽ cần để hỗ trợ này? Bạn sẽ cần một chương trình bắt đầu, sau đó cho phép bạn chọn giữa các chương trình khác vào lúc khởi động.

Làm thế nào nó hoạt động?

Bộ tải khởi động là chương trình đó - đó là thứ đầu tiên chạy và có thể tải các ứng dụng khác vào các vị trí cụ thể trong bộ nhớ (có thể tồn tại như FLASH, hoặc dễ bay hơi như RAM) và sau đó nhảy đến chương trình mong muốn, nơi nó sẽ tiếp tục thực thi từ đó .

Làm thế nào để tạo một bộ tải khởi động avr (hoặc cho bất kỳ vi điều khiển nào)?

Tôi chưa bao giờ tạo bootloader nhưng đây là cách tôi nghĩ tôi sẽ thực hiện: bắt đầu viết chương trình phần mềm như bình thường - nhưng hãy chắc chắn rằng nó được đặt trong một khu vực sao cho nó luôn là thứ đầu tiên chạy khi thiết bị khởi động. Ngoài đỉnh đầu, một số chức năng tôi muốn có từ chương trình nhỏ này: khả năng tải chương trình mới lên một vị trí có sẵn trong bộ nhớ, xóa chương trình đã tải lên trước đó, chọn chương trình nào sẽ chạy (nếu có nhiều hơn một) và có một số loại cấu trúc dữ liệu lưu trữ (bảng nhảy có thể phát triển?) để có thể nhớ các chương trình khác đang ở đâu và nhảy đến chúng. Tương tác có thể được thực hiện qua UART nơi nó có thể hiển thị cho bạn một menu thiết bị đầu cuối rất đơn giản và khả năng tải lên chương trình cơ sở trên cùng một kênh.

Làm thế nào nó được lập trình cho vi điều khiển (giống như bất kỳ chương trình .hex nào bị cháy trên flash rom của avr, hoặc một số phương thức khác)?

Nếu đó là một con chip hoàn toàn trống không có bộ tải khởi động hiện có có thể tự cập nhật, thì bạn sẽ cần phải ghi vào FLASH giống như bạn đã mô tả bằng cách sử dụng bất kỳ kỹ thuật nào được yêu cầu để thực hiện điều đó (ICSP trong trường hợp của AVR).

Điều này không có nghĩa là toàn diện về "bộ nạp khởi động" là gì. Tùy thuộc vào những gì bạn muốn từ một hoặc hệ thống mà họ thiết kế, bạn có thể thiết kế một để tải nội dung lên một vị trí được chỉ định trong RAM thay vì FLASH và bắt đầu thực hiện tại bất kỳ vị trí bộ nhớ tùy ý nào. Hoặc có thể bạn muốn một cái có khả năng chọn hệ điều hành nào sẽ tải khi PC của bạn khởi động (xem ví dụ về grub ). Bộ tải khởi động cho vi điều khiển 8 bit có xu hướng rất đơn giản.

Lưu ý về Arduino: Bộ tải khởi động này chỉ quản lý một chương trình AFAIK, nó cũng chiếm cổng nối tiếp để quản lý tải lên phần sụn và các thứ khác .


FYI, câu trả lời đã được viết để giải quyết các gạch đầu dòng hiện đã được chỉnh sửa.
Jon L

3

Khái niệm về bộ tải "khởi động" tương tự như khái niệm "mồi" máy bơm. Nói cách khác, bạn cần "một cái gì đó" tải một chương trình đến một địa chỉ nhất định và sau đó bắt đầu thực hiện chương trình tại địa chỉ đó. Đó là một cái gì đó, là bộ tải khởi động. Trong trường hợp đơn giản nhất, bộ tải khởi động "xuất hiện" tại địa chỉ bắt đầu được chỉ định của CPU (không, rất có thể), tải chương trình vào phân đoạn bộ nhớ cần thiết, chuyển điều khiển sang nó và "biến mất". Sự xuất hiện và biến mất được kiểm soát bởi phần cứng "bên ngoài". Một cách thực hiện có thể là bằng cách sử dụng ROM được kích hoạt thông qua thiết lập lại "phần cứng" và hủy kích hoạt bằng thiết lập lại "phần mềm". Trình tải trong ROM có thể đơn giản hoặc phức tạp theo yêu cầu, và cần phải được viết ở dạng nhị phân mà CPU cụ thể hiểu được. Nếu không cần địa chỉ được sử dụng bởi ROM, việc hủy kích hoạt ROM sẽ không được yêu cầu. Rõ ràng, EEPROM, ePROM, flash PROM, v.v. có thể được sử dụng thay cho ROM.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.