嵌入式控制器分布式控制系统固件更新方式探讨

机器人、AGV等自动化设备,车身有大量嵌入式控制单元,开发及应用过程中有固件更新需求。需要探讨出一套通用的在应用编程模板。

其中涉及的通信链路有: 以太网 CAN UART
涉及应用层协议: TCP, UDP, TCP Modbus, CANopen, 485Modbus, 232Modbus以及一些开发者自定义的协议
在应用编程协议统一使用: ST IAP protocol
其中固件更新所使用的程序为python脚本。

其网络拓扑如下图

嵌入式控制器分布式控制系统固件更新方式探讨

对于一级设备,可以直接由x86控制器或者交换机对外调试口进行固件更新。
对于二级设备,需要通过一级设备进行转发,完成固件更新功能。
本文主要讨论的是二级设备的固件更新方式。

更新固件的流程大致如下(以x86中运行pyscript,经一级设备,更新232Modbus设备的固件为例):
1. pyscript发送UDP指令,将一级设备的232Modbus任务模式切换为透传模式。
2. pyscript发送UDP报文模拟Modbus指令,使二级设备跳转到 bootloader
3. pyscript发送UDP报文模拟ST IAP Protocol, 对二级设备进行固件更新
4. pyscript发送UDP报文模拟ST IAP Protocol, 修改二级设备启动选项
5. pyscript发送UDP报文模拟ST IAP Protocol, 使二级设备跳转到应用层
6. pyscript发送UDP指令,将一级设备的透传模式切换回232Modbus任务模式

为求通用性,将ST IAP Proto的设备抽象为字符流设备,chardev。
TCP UDP UART等接口均可直接抽象成对应的chardev。
对于CAN接口,将每帧8个字节拼接,作为字符流设备使用。

chardev的方法有:
chardev.open()
chardev.close()
chardev.read()
chardev.write()
chardev.ioctl()

将ST IAP Proto 本身的实现抽象为iapdev

iapdev的方法有:
iapdev.jumptoaddr(addr)
iapdev.getbootloaderversion()
iapdev.loadbin(filename, addr)
iapdev.readbin(filename, addr)
iapdev.readuint32(valueaddr)
iapdev.loaduint32(blockstartaddr, valueaddr)
iapdev.confirmack()
iapdev.forwardwrite(bytes)
iapdev.restorebootoption(blockstartaddr)

静态方法
iapdev.getxor(bytes)
iapdev.getbytesfromuint32(bytes)
iapdev.isallbytes0xff(bytes)

和一级,二级设备指令有关的方法有:
iapdev.setforwardmode()
iapdev.exitforwardmode()
iapdev.settaregetboardtobootloader()
iapdev.resettargetboard()

抽象后流程可以简化成:
1. pyscript发送一级设备指令,将一级设备的二级设备任务模式切换为透传模式。
2. pyscript发送二级设备指令,使二级设备跳转到 bootloader
3. pyscript发送ST IAP Protocol, 对二级设备进行固件更新
4. pyscript发送ST IAP Protocol, 修改二级设备启动选项
5. pyscript发送ST IAP Protocol, 使二级设备跳转到应用层
6. pyscript发送一级设备指令,将一级设备的透传模式切换回二级设备任务模式

可用函数描述为:
iapdev.setforwardmode()
iapdev.settargettobootloader()
iapdev.getbootloaderversion()
iapdev.loadbin(filename, *.bin)
iapdev.writeuint32(blockaddr, valueaddr)
iapdev.jumptoaddr(appaddr)
iapdev.exitforwardmode()

附:关于bootoption域的约定:
1. bootoption必须单独占一个flash block
2. bootoption所指明的启动类型占第一个uint32
3. bootoption的长度占第二个uint32
4. bootoption的最后一个uint32_t为域的所有字节的异或校验和