Ngoài trường hợp thiết bị được cấp nguồn hoặc người dùng nhấn vào nút Reset của thiết bị thì ARM cung cấp hàm NVIC_SystemReset() để thực hiện khởi động lại vi xử lý. Trong ứng dụng cập nhật chương trình từ xa, hàm này sẽ được gọi tại chương trình ứng dụng khi phát hiện một phiên bản chương trình mới và tại chương trình OTA khi thực hiện xong quá trình OTA. Sau khi hàm NVIC_SystemReset() được thực thi thì vi xử lý sẽ khởi động lại và thực hiện chương trình Bootloader. Trong bài viết này, mình sẽ trình bày cho các bạn về thiết kế Bootloader cho vi điều khiển STM32 trong ứng dụng cập nhật chương trình từ xa theo thiết kế thực tế mà mình đã thực hiện.
Để hiểu rõ về cập nhật chương trình từ xa và các nội dung của bài viết này, mời các bạn xem trước các bài viết có liên quan:
- Cập nhật chương trình từ xa – Một tính năng quan trọng
- Mô hình và quá trình cập nhật chương trình từ xa cho thiết bị nhúng, IoT
- Tổ chức bộ nhớ vi điều khiển lõi ARM Cortex M3/4 – Áp dụng FOTA cho STM32
- Cấu trúc chương trình trong bộ nhớ vi điều khiển khi triển khai cập nhật chương trình từ xa
Nhiệm vụ chính quan trọng hàng đầu của chương trình Bootloader là kiểm tra các điều kiện tại các biến liên kết để lựa chọn thực thi một trong các chương trình: Chương trình cập nhật từ xa OTA, Chương trình ứng dụng A hoặc Chương trình ứng dụng B mỗi khi CPU khởi động.
Ví dụ đối với trường hợp thử nghiệm cập nhật chương trình từ xa do mình thực hiện. Sau khi khởi động, tại chương trình Bootloader sẽ kiểm tra giá trị biến FW_Selection, nếu:
- FW_Selection == 0x00000000 thì Vi xử lý sẽ thực thi chương trình OTA được lưu từ địa chỉ 0x08004000
- FW_Selection == 0x00000001 thì Vi xử lý sẽ thực thi chương trình Ứng dụng FWA được lưu từ địa chỉ 0x08020000
- FW_Selection == 0x00000002 thì Vi xử lý sẽ thực thi chương trình Ứng dụng FWB được lưu từ địa chỉ 0x08040000
Hình 1. Sơ đồ trạng thái các chương trình trong vi điều khiển
Bên cạnh việc kiểm tra giá trị biến FW_Selection để quyết định chương trình được thực thi thì Bootloader còn được mình thiết kế để đảm bảo phát hiện lỗi chương trình ứng dụng sau khi cập nhật, từ đó chương trình Bootloader sẽ lựa chọn thực thi chương trình ứng dụng chạy được trước đó – quay trở về (rollback) phiên bản cũ.
Nếu chương trình ứng dụng FWA hoặc FWB mới được cập nhật tồn tại lỗi làm cho thiết bị khởi động lại liên tục (fwfailtime) quá 3 lần thì thuật toán đảm bảo thiết bị hoạt động với phiên bản trước của chương trình để đảm bảo các chức năng ứng dụng và có khả năng cập nhật bảng mới hơn [1][2]. Mỗi lần khởi động, chương trình Bootloader sẽ tăng fwfailtime lên 1 đơn vị, nếu chương trình ứng dụng chạy thành công đến cuối chương trình thì xem như chương trình được chạy thành công và đặt lại giá trị fwfailtime là 0.
[HỌC ONLINE TẠI TAPIT: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]
Vị trí của chương trình Bootloader thường được bắt đầu tại địa chỉ đầu tiên của bộ nhớ Flash, đây là địa chỉ mặc định sẽ được CPU thực thi sau khi reset. Với dòng vi điều khiển STM32 thì vị trí bắt đầu của bộ nhớ Flash là 0x0800_0000. Chương trình Booloader này sẽ được người dùng lập trình và nạp thủ công vào vi điều khiển. Thuật toán khởi động vi điều khiển phải được thiết kế như sau:
Bước 1: Khi thiết bị khởi động, chương trình Bootloader sẽ được thực hiện. Tại Bootloader, tăng biến đếm fwfailtime lên 1 đơn vị.
Hình 2. Giản đồ quy trình kiểm tra và làm việc với biến fwfailtime
Bước 2: Xác định chương trình cần chạy trong lần khởi động này là chương trình nào thông qua giá trị biến liên kết được đọc ra từ bộ nhớ Flash.
Bước 3: Xác định địa chỉ chương trình cần chạy: Kiểm tra giá trị fwfailtime, nếu giá trị fwfailtime bé hơn 3 thì tùy vào giá trị ở bước 2 sẽ xác định được địa chỉ bắt đầu của chương trình cần nhảy đến. Nếu giá trị fwfailtime bằng 3 thì địa chỉ bắt đầu của chương trình cần nhảy đến là địa chỉ chương trình của phiên bản trước.
Hình 3. Giản đồ quy trình lựa chọn chương trình cần thực thi
Bước 4: Thưc hiện theo các chỉ dẫn của ARM [3] để nhảy đến và thực thi chương trình đã xác định bao gồm:
- Tắt hết các ngoại vi, các ngoại lệ.
- Bật bộ dao động nội tần số thấp để cấp cho ngoại vi RTC.
- Đặt giá trị Main Stack Pointer
- Gán địa chỉ của hàm main() của chương trình đó cho thanh ghi PC
Hình 4. Giản đồ quy trình nhảy đến một chương trình khác từ bootloader
Qua bài viết này, mình đã chia sẻ một trường hợp thiết kế xây dựng Bootloader thực tế ứng dụng cho tính năng cập nhật chương trình từ xa, ngoài tính năng chính là lựa chọn chương trình thực thi thì bootloader còn được thiết kế để đảm bảo thiết bị vẫn hoạt động khi cập nhật một chương trình lỗi chương trình bị lỗi.
Tài liệu tham khảo
[1] Keller, Brent, John Sotack, and Alan Hayter. “Failsafe firmware updates.” U.S. Patent No. 8,595,716. 26 Nov. 2013.
[2] Unterschütz, Stefan, and Volker Turau. “Fail-safe over-the-air programming and error recovery in wireless networks” Proceedings of the 10th International Workshop on Intelligent Solutions in Embedded Systems. IEEE, 2012.
[3] ARM, MCU booting process, https://www.keil.com/
Chúc các bạn thành công!
Thuong Nguyen