Ở các bài trước, mình đã nói về update flow, fail-safe và secure update. Một câu hỏi rất thực tế là có nên nén firmware trước khi update không.
Với MCU, đây không chỉ là chuyện giảm kích thước file.
Nó còn liên quan tới thời gian truyền, RAM, CPU time, cách ghi flash, logic fail-safe và cả cách verify application image.
Mục lục
Vì sao người ta nghĩ tới chuyện nén firmware
Khi application image ngày càng lớn, thời gian update cũng tăng lên. Nếu firmware đi qua UART, CAN, BLE hoặc OTA gateway, thời gian truyền có thể trở thành vấn đề thật.
Update càng lâu thì cửa sổ rủi ro càng lớn.
Thiết bị có nhiều khả năng bị gián đoạn giữa chừng, người dùng cũng dễ thấy khó chịu hơn.
Vì vậy nhiều hệ bắt đầu nghĩ tới chuyện nén firmware trước khi truyền.
Nén firmware giúp được gì
Nếu firmware nén tốt, dữ liệu phải truyền đi sẽ ít hơn. Điều này có thể mang lại vài lợi ích rõ ràng.
- Giảm dung lượng phải truyền.
- Rút ngắn thời gian truyền trong nhiều trường hợp.
- Giảm băng thông nếu update qua kênh chậm hoặc tốn phí.
- Giảm thời gian thiết bị phải nằm trong update mode.
Nhưng lợi ích này chỉ có thật nếu chi phí giải nén không ăn hết phần mình vừa tiết kiệm được.
Nén firmware không phải lúc nào cũng lời
Đổi lại cho phần dữ liệu truyền ngắn hơn là thêm logic giải nén. Với MCU, đây có thể là phần đắt nhất của bài toán.
- Tốn thêm RAM để giải nén.
- Tốn thêm CPU time.
- Bootloader hoặc flash loader phức tạp hơn.
- Debug khó hơn khi có lỗi giữa lúc giải nén và ghi flash.
- Có trường hợp thời gian tổng không giảm vì truyền nhanh nhưng giải nén chậm.
Nói cách khác, nén firmware là một bài toán trade-off. Không phải cứ nén vào là hệ thống sẽ tốt hơn.
Nén ở đâu, giải nén ở đâu
Thông thường application image sẽ được nén ở phía build server hoặc tool update. Phần cần quyết định là ai sẽ giải nén.
- Bootloader tự giải nén rồi ghi flash.
- Flash loader giải nén rồi ghi flash.
- Application hiện tại giải nén và chuẩn bị image mới trước khi handoff cho bootloader.
- Gateway trung gian giải nén trước, MCU chỉ nhận raw image.
Mỗi hướng đều ảnh hưởng tới RAM, security, fail-safe và độ phức tạp của toàn hệ thống.
Các cách triển khai thường gặp
Trong thực tế, ít nhất có bốn kiểu triển khai hay gặp.
- Truyền compressed image, giải nén xong rồi mới ghi full application image.
- Truyền compressed block, giải nén theo block rồi ghi dần.
- Dùng delta update rồi nén phần delta.
- Để gateway giải nén trước, MCU chỉ xử lý raw image.
Không có một cách nào luôn tốt nhất.
Cách phù hợp phụ thuộc vào RAM, transport, flash layout và cách mình muốn thiết kế fail-safe.
Một số thuật toán hay gặp
Không phải thuật toán nén nào cũng hợp với bootloader trên MCU. Khi chọn thuật toán, thường phải nhìn cả tỷ lệ nén, tốc độ giải nén và lượng RAM cần dùng.
LZSS là một họ thuật toán dictionary-based, khá quen trong embedded và thường dễ nhúng hơn các lựa chọn nặng.
LZ4 nổi bật ở tốc độ giải nén nhanh, thường hợp khi ưu tiên thời gian hơn tỷ lệ nén.
heatshrink là thư viện nén nhỏ, hay được nhắc trong embedded nhỏ vì footprint khá gọn.
LZMA thường cho tỷ lệ nén tốt hơn, nhưng đổi lại logic giải nén nặng hơn và đòi hỏi tài nguyên nhiều hơn. Với MCU nhỏ, đây thường là lựa chọn phải cân nhắc rất kỹ.
Nếu ưu tiên bootloader gọn và dễ kiểm soát, nhiều hệ sẽ nghiêng về giải pháp đơn giản hơn.
Nếu ưu tiên tiết kiệm băng thông tối đa, các thuật toán nén mạnh như LZMA có thể đáng cân nhắc, nhưng cái giá phải trả thường không nhỏ.
Các ràng buộc kỹ thuật khi giải nén trong bootloader
Giải nén trong bootloader không chỉ là gọi một hàm decompress rồi xong. Nó đụng vào khá nhiều ràng buộc thấp tầng của MCU.
- RAM có đủ cho buffer giải nén hay không.
- Có thể giải nén theo block hay phải giữ cả image trong RAM.
- Flash có cho execute while write hay không.
- Có cần staging area hay không.
- Alignment, page size và erase block có làm flow ghi phức tạp hơn không.
- Nếu bị gián đoạn giữa chừng thì metadata sẽ ghi lại trạng thái như thế nào.
Đây là lý do nhiều hệ không giải nén ngay trong bootloader, mà đẩy phần việc này sang flash loader hoặc sang application hiện tại.
Liên hệ với fail-safe update
Compressed image không làm giảm nhu cầu fail-safe. Ngược lại, nó còn làm state machine của update phức tạp hơn.
Mình phải trả lời rõ vài điểm: application image nào được verify, metadata theo dõi compressed image hay raw image, và nếu update bị gián đoạn giữa lúc giải nén thì bootloader sẽ nhìn state ra sao khi chạy lại.
Liên hệ với secure update
Nén firmware còn kéo theo câu chuyện security. Mình ký compressed image hay ký raw image. Mình verify trước hay sau khi giải nén. Nếu vừa mã hóa vừa nén thì thứ tự xử lý là gì.
Đây không phải chi tiết nhỏ.
Chỉ cần chọn sai thứ tự verify và giải nén là toàn bộ update flow có thể trở nên khó kiểm soát hơn nhiều.
Khi nào nên dùng, khi nào không nên dùng
Nén firmware đáng cân nhắc khi có các điều kiện như:
- Đường truyền chậm hoặc đắt.
- Application image khá lớn.
- RAM vẫn đủ cho cách giải nén đã chọn.
- Thời gian update là vấn đề thật của sản phẩm.
Ngược lại, có nhiều trường hợp không nên cố nén.
- MCU quá nhỏ.
- Bootloader cần cực kỳ đơn giản.
- Lợi ích về thời gian truyền không đáng kể.
- Chi phí debug, fail-safe và security tăng quá mạnh so với phần tiết kiệm được.
Kết luận
Nén firmware trong bootloader không phải bài toán chỉ có lợi ích. Nó luôn là một bài toán cân bằng giữa thời gian truyền, RAM, CPU time, flash layout, fail-safe và security. Chọn đúng hay sai phụ thuộc rất nhiều vào bối cảnh thật của sản phẩm.








