Cập nhật chương trình từ xa trên vi điều khiển STM32 – Firmware Over The Air (FOTA) – P3

Trong 2 phần trước của chuỗi bài viết hướng dẫn cập nhật chương trình từ xa (FOTA) cho dòng vi điều khiển STM32F103 mình đã trình bày về tổng quan, các điều kiện và phân chia chức bộ nhớ của MCU để thực hiện FOTA ở Phần 1 cũng như hướng dẫn cách viết một chương trình Bootloader ở Phần 2. Trong phần này mình sẽ giải thích về tập tin chứa nội dung chương trình (firmware) ở định dạng Intel HEX mà chúng ta sẽ sử dụng trong quá trình FOTA. Các bạn nên đọc qua phần 1 và phần 2 trước để nắm toàn bộ ý tưởng, nội dung của chuỗi bài viết này. Những hướng dẫn của mình cũng có thể được tham khảo để áp dụng cho những dòng vi điều khiển khác.

[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]

Phần 3: Hiểu tập tin chương trình ở định dạng Intel HEX được sử dụng trong quá trình FOTA

1. Tập tin chương ở định dạng Intel HEX là gì?

Nó là một tập tin chứa nội dung chương trình cùng các thông tin chỉ dẫn với 6 loại HEX record khác nhau theo định dạng Intel HEX. Mỗi record sẽ bao gồm nhiều ký tự ASCII biểu diễn các giá trị theo mã hexadecimal. Trong quá trình FOTA, từ File Intel HEX chúng ta phải tách nội dung chương trình ra và lưu vào bộ nhớ flash của vi điều khiển theo các chỉ dẫn địa chỉ đi kèm trong file.

Khi mở file firmware chúng ta nhìn thấy một loạt các chuỗi kí tự tương tự như sau:

Chúng ta cần phải hiểu được cấu trúc của chuỗi kí tự này mới có thể cập nhật được chương trình cho thiết bị. Bắt đầu thôi!

Mỗi record (hàng) sẽ thường sẽ có 6 trường (field), mỗi trường sẽ có nhiệm vụ riêng. Mỗi hàng có thể kết thúc bằng kí tự CR(0x13)/LF(0x0A)/NULL(0x00).

  • Start code
    Số lượng kí tự: 1

    Dấu hai chấm ( : ) trong bảng ASCII.
  • Byte count
    Số lượng kí tự: 2

    Đại diện cho số lượng các byte sẽ xuất hiện trong Data field. Giá trị byte count có thể nằm trong khoảng từ 0 – 255 (0x00 – 0xFF). Thông thường byte count có giá trị 16 (0x10).
  • Record type
    Số lượng kí tự: 2
    Dùng để xác định chức năng của record đó. Sẽ có 6 loại record tương ứng với 6 giá trị:
    º 
    Record type = 00 ⇒ Data Record
       Record này sẽ chứa dữ liệu, chính là chương trình của chúng ta. Bên cạnh đó nó cũng sẽ cung cấp giá trị 16 bit địa chỉ bộ nhớ có trọng số thấp (bit 0-15) nơi lưu dữ liệu trong bộ nhớ chương trình của vi điều khiển.
       Lưu ý: STM32 có 32bit địa chỉ bộ nhớ, vì vậy cần có thêm record khác để cung cấp thêm 16 bit có trong số cao hơn (16-31).
    (tìm hiểu thêm về bộ nhớ của STM32 tại đây)
    º 
    Record type = 04⇒ Extended Linear Address Record 
       Record này chứa thông tin bit16-31 địa chỉ của bộ nhớ lưu chương trình.
    º 
    Record type = 01End of File Record 
       Record này xuất hiện cuối cùng file chương trình nhằm thông báo kết thúc file.
    º 
    Record type = 02⇒ Extended Segment Address Record
       Record này để thay đổi bit 4-19 trong địa chỉ bộ nhớ lưu chương trình so với record đã cung cấp trước đó. Với file được build từ KeilC thì Extended Linear Address Record thường xuyên được sử dụng hơn.
    º 
    Record type = 03⇒ Start Segment Address Record
       Record này không xuất hiện trong trong file chương trình của STM32 nên có thể được bỏ qua.
    º 
    Record type = 05⇒ Start Linear Address Record 
       Record này có thể được bỏ qua vì nó không chứa thông tin nào cần thiết để lưu vào bộ nhớ chương trình.
  • Address
    Số lượng kí tự: 4
    Với Data Record thì trường này cung cấp 16 bit địa chỉ bộ nhớ chương trình có trọng số thấp (0-15).
    Với các record khác thì nó sẽ có giá trị 0x0000.
  • Data
    Số lượng kí tự: 2 x Byte count
    Thường sử dụng để biểu thi thông tin hoặc dữ liệu tùy thuộc vào từng loại record. Có một số record sẽ không có trường này.
  • Checksum
    Số lượng kí tự: 2

    Một giá trị được tính toán được sử dụng để xác nhận record không có lỗi.Cách tính giá trị checksum:
    º 
    Bước 1: Tính tổng toàn bộ các byte trong record trừ trường Start code với trường Checksum
    º 
    Bước 2: Lấy 2 byte có trong số nhỏ nhất trong giá trị tính tổng trên.
    º 
    Bước 3: Lấy phần bù của 2 byte trên (bằng cách đảo các bit và cộng thêm với 1)
                Checksum Value = 1+ (NOT ((tổng)))

Tham khảo thêm về cấu trúc của file Intel HEX tại đây

2. Một số ví dụ

  • Ví dụ về End of File Record:

    Start code Byte count Address Record type Data Checksum
    : 00 0000 01 FF

    º  0x00 là số lượng data byte có trong record
    º 
    0x0000 là address field. Trong End of File Record thì giá trị trường này luôn là 0x0000
    º 
    0x01 là record type, chỉ ra rằng đây là End of File Record
    º 
    Không có Data field trong End of File Record
    º 
    0xFF là giá trị checksum của record và được tính như sau:
          01h+(NOT((uint8_t)(00h+00h+00h+01h)))

Một Intel HEX file phải được kết thúc với một End of File Record.

  • Ví dụ sau cho Extended Linear Address Record và Data Record:


    Nhìn vào dòng 1, ta có thể xác định đây là Extended Linear Address Record

    Start code Byte count Address Record type Data Checksum
    : 02 0000 04 0801 F1

    º  0x02 là số lượng data byte có trong record
    º  0x0000 là address field. Trong extended linear address record thì giá trị trường này luôn là 0x0000
    º  0x04 là record type, chỉ ra rằng đây là một extended linear address records
    º  0x0801 là giá trị 16 bit cao (từ 16-31) trong địa chỉ bộ nhớ chương trình
    º  0xF1 là giá trị checksum của record và được tính như sau:
    01h+(NOT((uint8_t)(02h+00h+00h+04h+08h+01h)))

Khi có record này trong file chương trình thì các địa chỉ lưu dữ liệu trong Data record tiếp theo đó sẽ được cộng với 0x0800 0000 cho đến khi xuất hiện một dòng chứa extended linear address record khác thay thế.
Extended linear address mặc định bằng 0x0000 nếu trong file chương trình không xuất hiện extended linear address record.

Tiếp theo, dòng thứ 2 có record type = 00 nên đây là data record

Start code Byte count Address Record type Data Checksum
: 10 5000 00 F03E…0108 BB

º  0x10 là số lượng data byte có trong record
º  0x5000 là giá trị 16 bit thấp (0-15) của địa chỉ mà dữ liệu sẽ được lưu trong bộ nhớ
º  00 là record type (Data record)
º  F03E…0108 là dữ liệu cần lưu vào bộ nhớ chương trình 
º  BB là giá trị checksum của record.

Dữ liệu mà bạn sẽ lưu vào trong bộ nhớ sẽ lấy từ Data record này. Dữ liệu tại dòng 1 là

F03E0020 01510008 835C0008 F35B0008

Có tổng cộng 16 byte sẽ được lưu vào trong bộ nhớ bắt đầu từ địa chỉ 0x08005000 đến 0x0800500F.
Vậy nó được lưu như thế nào? Ta thử nạp trực tiếp chương trình và kiểm tra bộ nhớ nhé:

Hình như có sự khác nhau? Ta sẽ chia dữ liệu 4byte thành 1 bộ rồi so sánh nào:

Địa chỉ Dữ liệu trong file Dữ liệu trong bộ nhớ
0x08005000 20 00 3E F0 F0 3E 00 20
0x08005004 01 51 00 08 08 00 52 0F
0x08005008 83 5C 00 08 08 00 5C 83
0x0800500C F3 5B 00 08 08 00 5B F3

Từ bảng trên ta có thể thấy sự khác nhau giữa dữ liệu từ trong file chương trình và dữ liệu trong bộ nhớ. Có thể thấy cứ 1 bộ 4 byte thì byte thứ 1 sẽ chuyển thành byte 4, byte 2 chuyển thành byte 3,… như hình dưới.

Từ sự khác nhau đó, chúng ta có viết code để có thể nạp chương trình từ file Intel HEX vào trong bộ nhớ Flash của vi điều khiển STM32 rồi 😀

3.Làm cách nào chúng ta có thể tạo ra một file chương trình?

Để tạo file chương trình (đuôi .hex) bằng KeilC IDE thì làm các bước như sau:

Bước 1: Vào Option -> Tab Output -> Kích chọn Create Executable -> Create HEX File
Bước 2: Thư mục mặc định lưu file chương trình là MDK-ARM/YourProjectName. Thay đổi thư mục lưu tại Select Folder for Objects
Bước 3: Thay đổi tên file chương trình tại Name of Executable
Bước 4: Chọn OK rồi Build thôi! 😆 

Sau khi build thì file chương trình sẽ được như sau:

Đơn giản phải không nào :mrgreen: :mrgreen: 

=================================================

Bài viết này giúp bạn có thể hiểu về cấu tạo của một file chương trình Intel HEX và cách tạo file chương trình từ phần mềm KeilC. Dựa vào những thông tin này, bài viết tiếp theo sẽ trình bày về cách viết một chương trình FOTA.

Xem tiếp phần 4: Chương trình FOTA và cách chuyển các chương trình trong mô hình FOTA

Theo dõi thêm:
– Cơ bản về cấu trúc và tính năng Vi xử lý ARM Cortex – Mx. 
– Phân biệt các khái niệm Processor Core, Processor và Microcontroller trong Hệ thống nhúng
– Tổng hợp các bài hướng dẫn Lập trình vi điều khiển STM32F1
– Tổng hợp hướng dẫn Lập trình vi điều khiển STM32F4

Chúc các bạn thành công!

Nhóm TAPIT ARM R&D