telink:tc321x串口升级
1 telink升级原理概括
tc3215m的flash 512KB,可设置AB分区启动,启动地址为 [ 0/128KB ]或 [ 0/256KB ],资源充裕所以选[ 0/256KB ];
telinkIoT编译工具生成的bin文件的0x08地址偏移处的值都为0x544C4E4B "TLNK",该值sdk代码可访问,作为设置升级地址的标志;

1.1 升级流程
telink-mcu在收到一帧fwbin之后,会预留0x08地址偏移处的4字节bin不写入flash,把其他fwbin数据写入flash;
telink-mcu继续接收剩下的fwbin数据帧,每帧写入flash,且对每帧数据进行crc累计校验和;
最后一帧fwbin数据帧的结尾会额外加2bytes的多项式crc,用于校验;
telink-mcu在收完最后一帧后,会重新将flash数据读出进行crc校验得到一个crc校验和,对比这3个crc校验和是否相等;
3个crc相等 >> 补全写入flash的0x08地址字节,然后将当前flash区的0x08地址字节写入0xff >> 软件重启完成升级;
重启后romBoot通过判断flash 0x08偏移地址值决定从flash的0x000000还是0x040000启动;
===================================
对于串口升级数据流向是咋样的呢?
===================================
2 串口dmaBuff
串口数据通过dmaBuff收进来,等接收中断置位后在irq中,将dmaBuffAddr作为msg发送到queue中处理;
//telink中,dmaBuff的结构
typedef struct{
unsigned int dma_len; //dma硬件自动计数
unsigned char data[UART_DATA_LEN]; //dmaBuff, RxIrq >> &data push >> pop处理
}uart_data_t;
//telink中,msg的结构
typedef struct {
unsigned int Type; //msgTypeData, msgTypeTimeout, msgTypeInvalid, msgTypeCheckFail
unsigned char *Data; //msgTypeData、msgTypeCheckFail时, 为dmaBuff地址
//msgTypeTimeout, msgTypeInvalid时, 未用上
} FW_UPDATE_MsgTypeDef;
//telink中,queue的结构
typedef struct {
FW_UPDATE_MsgTypeDef Msg[MSG_QUEUE_LEN]; // buffer storing msg
unsigned char Cnt; // current num of msg
unsigned char ReadPtr; // ptr of first msg should be read next
} FW_UPDATE_MsgQueueTypeDef;
3 收发数据帧
这边queue收到数据后就需要处理,通过串口收发的 dmaRcvBuff /dmaSndBuff 的数据帧格式如下
//dma rcv/snd data struct
typedef struct {
unsigned char CheckSum; //frameHeader >> checksum
unsigned char Type; //frameType >> typeCmd, typeData, typeAck, typeChkFail
unsigned short payloadLen; //payloadLen
unsigned char Payload[payloadLen]; //payload[ FW_UPDATE_FRAME_PAYLOAD_MAX ]
} FW_UPDATE_FrameTypeDef;
当type不同时,4种payload的解析如下
#define FW_UPDATE_FRAME_FW_SIZE 1024
#define SIZE_LEN_PL_PARAMS 10
typedef enum{
EC_SUCCESS = 0,
EC_FRAME_CHECK = 1,
EC_PAYLOAD_CHECK = 2,
}FW_UPDATE_errorCode;
typedef struct{
unsigned char checksum;
unsigned char reserved;
unsigned short blockIndex;
unsigned char fwBinData[FW_UPDATE_FRAME_FW_SIZE];
}payload_typeData;
typedef struct{
unsigned char checksum;
unsigned char reserved;
unsigned short blockIndex;
}payload_typeAck;
typedef struct{
unsigned char checksum;
unsigned char cmdid;
unsigned char cmdParams[SIZE_LEN_PL_PARAMS];
}payload_typeCmd;
typedef struct{
unsigned char checksum;
unsigned char checkErrorCode;
}payload_typeChecksumFail;
4 那么上面这4种串口通讯帧是如何通讯的呢?
ble-mcu收到通讯帧后,首先计算两个checksum,如果checksum不对直接回复typeChkFail;连续收到3帧checksum错误则软件复位;
接着ble-mcu对于不能解析的通讯帧不进行处理,2s内没有收到正确帧,超时复位;ble-mcu帧与帧之间的间隔也需要在2s内,超时复位;
ble-mcu的正常通讯帧的收发顺序则如下所示;ble-mcu会对收到后执行的通讯帧都进行回复;


4.1 通讯流程状态机

5 校验方式
ble-mcu的校验方式为:通讯帧帧头校验和校验,通讯帧payload校验和校验,固件包整包多项式校验;
5.1 校验和校验
static unsigned char FW_UPDATE_checksumGenerate(const unsigned char *pDataValid, unsigned short dataLen){
unsigned char CheckSum = 0;
if (pDataValid == NULL || dataLen == 0) {
return 0;
}
for (unsigned short i = 0; i < dataLen; i++) {
CheckSum ^= pDataValid[i];
}
//CAECHAR("check:%02x \n",CheckSum );
return CheckSum;
}
5.2 固件包整包多项式校验
mcu发送固件包的时候,多项式校验的2字节会加在最后一帧固件包的结尾,一起发送给ble-mcu校验;
ble-mcu在接收每帧fwbin的时候会对fwbin每帧进行crc累计,ble-mcu在接收完fwbin整个固件后会从flash中读出所有固件再计算一遍crc;
ble-mcu会将两次crc和mcu发过来的crc进行比对,都相同才回复CMDID_END_RSP;
//crc初值为0xffff
static unsigned short FW_UPDATE_crcGenerate(unsigned short crc, unsigned char *pd, int len){
unsigned short crc16_poly[2] = { 0, 0x8408 };
int i, j;
for (j = len; j > 0; j--){
unsigned char ds = *pd++;
for (i = 0; i < 8; i++){
crc = (crc >> 1) ^ crc16_poly[(crc ^ ds) & 1];
ds = ds >> 1;
}
}
return crc;
}
6 所以这玩意应该咋搞呢?
1 状态机 >> 确认整体协议的收发流程,先发什么数据,后发什么数据;
2 帧格式 >> 单帧的数据帧应该怎么发,帧本身数据可以放到payload中二次解析;[ crc : frameType : len : payload ]
3 crc/ack,超时处理,丢包处理 >> 单帧的数据帧发的对不对;
4 编写调试 >> 按照规划好的框架写代码然后调试;所以看别人的代码也可以这样看;
所以这玩意我咋让AI帮我搞呢?
1 先让AI生成状态机,状态转移表,空函数;
2 自己补充边界条件,物理限制,错误处理,有些关键flash读写操作;
3 再让AI按补充的条件编写重复性函数,辅助函数等;

浙公网安备 33010602011771号