STM32G4单片机-基于Ymode协议的IAP代码升级YMode协议说明数据帧格式命令类型起始帧格式数据帧格式结束帧格式YMODE协议数据传输流程代码实现过程YMode协议说明YModem 协议是由 XModem 协议演变而来的每包数据可以达到 1024 字节是一个非常高效的文件传输协议。我们平常所说的 Ymodem 协议是指的 Ymodem-1K除此还有 Ymodem-g没有 CRC 校验不常用。YModem-1K 协议用 1024 字节数据帧传输取代了标准的 128 字节数据帧传输发送的数据会使用 CRC 校验保证数据传输的正确性。它每传输一个信息块时就会等待接收端返回 ACK 信号接收到响应信号后才会继续传输下一个信息块从而保证能够接收到全部数据。所有声称支持 Ymodem 协议的项目必须满足以下最低要求发送端应在第一个数据包中发送路径名文件名。路径名应为以 “NULL” 结尾的 ASCII 字符串如下所述1除非有特别要求否则只发送文件名部分。2不发送驱动器符号。3不区分文件名中大小写字母的系统应仅以小写形式发送路径名。接收端应使用第一个数据包中发送的路径名作为接收文件名。当接收端接收到第一个数据包并成功打开输出文件后应该返回一个 “ACK” 字符给发送端用来确认这个数据包然后接收端再发送 “C” 或 “NAK” 来开始进行正常的 Ymodem 传输。接收端在接收每个文件时要能接受 128 字节和 1024 字节两种数据包的任意混合发送。发送端可以在 1024 字节和 128 字节两种数据包之间任意切换发送。发送端不能更改未确认的数据包的长度。在每次文件传输的末尾发送端只能发送最多 10 次 “EOT” 字符直到它收到一个 “ACK” 字符。这是 Xmodem 规范的一部分。发送路径名为空的路径名数据包来表示传输会话的结束该路径名数据包应与其它路径名数据包一样被确认。没有满足以上要求的程序不兼容 Ymodem 协议不应被描述为支持 Ymodem 协议。数据帧格式命令类型起始帧格式Ymode协议的第一帧数据是文件的名称和大小数据。帧头为 SOH表示起始帧中包含着128个字节的数据。起始帧帧序号固定为 0x00帧序号反码为 0xFF。FILENAME 是要传输的文件名如 Template.bin它在数据帧中的格式为0x54,0x65,0x6D,0x70,0x6C,0x61,0x74,0x65,0x2E,0x62,0x69,0x6E,0x00也就是把 ASCII 码转成十六进制但是最后一定要在文件名后加上 0x00表示文件名的结束。FILESIZE 是要传输的文件大小如上面的 Template.bin 大小 107544 byte转换成十六进制就是 0x1A418。它在数据帧中的格式可以是十进制数的 0x31,0x30,0x37,0x35,0x34,0x34也可以是十六进制数的 0x30,0x78,0x31,0x41,0x34,0x31,0x38同样最后要加上 0x00 表示结束。NULL 是数据部分若 FILENAME 和 FILESIZE 加起来不满 128 字节则以 0x00 填充剩余字节。CRC 表示的是数据部分的 CRC 校验不包含帧头、帧序号和帧序号反码。校验值为 2 字节传输时 CRC 高八位在前低八位在后。数据帧格式帧头为 SOH 时表示数据帧的数据段为 128 个字节;帧头为 STX 时表示数据帧的数据段为 1024 个字书。数据帧帧序号的取值范围为 0~255帧序号反码是它的取反;·DATA 表示要传输的文件数据;·FILL 是数据部分若 DATA 不满 128/1024 字节则以 0x1A 填充剩余字节CRC 表示的是数据部分的 CRC 校验不包含帧头、帧序号和帧序号反码。校验值为2字节传输时CRC 高八位在前低八位在后。结束帧格式帧头为 SOH表示结束帧中包含着 128 个字节的数据。结束帧帧序号固定为 0x00帧序号反码为 0xFF。结束帧的 128 字节的数据部分不存放任何信息即全部用 0x00 填充。CRC 表示的是数据部分的 CRC 校验不包含帧头、帧序号和帧序号反码。校验值为2字节传输时CRC 高八位在前低八位在后。YMODE协议数据传输流程代码实现过程这里只列出IAP过程代码详细代码后续以压缩包的形式上传有需要的自己下载voidiap_task(void){uint8_ti0;uint16_tcrc0;printf(\r\nMotor Control STM32G431 Bootloader\r\n);printf(Please send file with YMODEM\r\n);while(1){iap_data_lenuart3_get_receive_data(iap_buf,IAP_BUF_LEN);switch(iap_status){caseWAIT_CONNECT:if(systick_time_diff(iap_tick)CONNECT_DATA_CYCLE)//1秒发一次YMODE链接指令{iap_tickHAL_GetTick();HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_C,1,100);}if(systick_time_diff(jump_app_tick)WAIT_CONNECT_TIMEOUT)//超时直接跳转到APP{jump_to_app();jump_app_tickHAL_GetTick();}if(iap_data_len(YMODEM_SOH_DATA_LEN5))//接收到SOH数据帧{if((iap_buf[0]YMODEM_CMD_SOH)(iap_buf[1]0x00)(iap_buf[2]0xFF)){packet_numberiap_buf[1];crccal_crc16(iap_buf[3],iap_data_len-5);if(crc((iap_buf[iap_data_len-2]8)|iap_buf[iap_data_len-1])){uint16_tfind_index3;uint8_tfile_name_end_flag0;while(find_index(iap_data_len-5)){if(iap_buf[find_index]0x00){file_name_end_flag1;find_index;i0;}if(file_name_end_flag0){filename[i]iap_buf[find_index];}if(file_name_end_flag){if((iap_buf[find_index]0x30)(iap_buf[find_index]0x39)){filelength[i]iap_buf[find_index];file_length*10;file_length(iap_buf[find_index]-0x30);}if(iap_buf[find_index]0x20){break;}}find_index;}if(file_lengthAPP_MAX_LENGTH)//判断数据是否超出允许的大小{HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_ACK,1,100);//擦除文件指定大小的扇区if(FLASH_EraseSector(FLASH_GetSector(ApplactionAddr),FLASH_GetSectorNum(APP_MAX_LENGTH))!FLASH_OK){// 错误处理}packet_number;iap_statusDATA_RECEIVE;program_addrApplactionAddr;HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_C,1,100);iap_tickHAL_GetTick();jump_app_tickHAL_GetTick();}}}}break;caseDATA_RECEIVE:if(iap_data_len){if(iap_buf[0]YMODEM_CMD_SOH){if(iap_data_len!(YMODEM_SOH_DATA_LEN5)){iap_statusWAIT_CONNECT;break;}if(packet_number!iap_buf[1]){iap_statusWAIT_CONNECT;break;}packet_number;crccal_crc16(iap_buf[3],YMODEM_SOH_DATA_LEN);if(crc!((iap_buf[iap_data_len-2]8)|iap_buf[iap_data_len-1])){iap_statusWAIT_CONNECT;break;}if((program_addrYMODEM_SOH_DATA_LEN-ApplactionAddr)file_length){memcpy(program_buf,iap_buf[3],YMODEM_SOH_DATA_LEN);FLASH_WriteData(program_addr,YMODEM_SOH_DATA_LEN,program_buf);program_addrYMODEM_SOH_DATA_LEN;}else{uint16_tprogram_lenfile_length-(program_addr-ApplactionAddr);if(program_len){memcpy(program_buf,iap_buf[3],program_len);FLASH_WriteData(program_addr,program_len,program_buf);program_addrprogram_len;}}HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_ACK,1,100);iap_tickHAL_GetTick();jump_app_tickHAL_GetTick();}elseif(iap_buf[0]YMODEM_CMD_STX){if(iap_data_len!(YMODEM_STX_DATA_LEN5)){iap_statusWAIT_CONNECT;break;}if(packet_number!iap_buf[1]){iap_statusWAIT_CONNECT;break;}packet_number;crccal_crc16(iap_buf[3],YMODEM_STX_DATA_LEN);if(crc!((iap_buf[iap_data_len-2]8)|iap_buf[iap_data_len-1])){iap_statusWAIT_CONNECT;break;}if((program_addrYMODEM_STX_DATA_LEN-ApplactionAddr)file_length){memcpy(program_buf,iap_buf[3],YMODEM_STX_DATA_LEN);FLASH_WriteData(program_addr,YMODEM_STX_DATA_LEN,program_buf);program_addrYMODEM_STX_DATA_LEN;}else{uint16_tprogram_lenfile_length-(program_addr-ApplactionAddr);if(program_len){memcpy(program_buf,iap_buf[3],program_len);FLASH_WriteData(program_addr,program_len,program_buf);program_addrprogram_len;}}HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_ACK,1,100);iap_tickHAL_GetTick();jump_app_tickHAL_GetTick();}elseif(iap_buf[0]YMODEM_CMD_EOT){HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_NAK,1,100);iap_statusRECEIVE_FINISH;iap_tickHAL_GetTick();jump_app_tickHAL_GetTick();}}break;caseRECEIVE_FINISH:if(iap_data_len){if(iap_buf[0]YMODEM_CMD_EOT){HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_ACK,1,100);HAL_Delay(100);HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_C,1,100);iap_statusRECEIVE_END;iap_tickHAL_GetTick();jump_app_tickHAL_GetTick();}}break;caseRECEIVE_END:if(iap_data_len(YMODEM_SOH_DATA_LEN5)){HAL_UART_Transmit(huart3,(uint8_t*)YMODEM_CMD_ACK,1,100);iap_statusJUMP_TO_APP;HAL_Delay(1000);printf(\r\nProgramming Completed Successfully!\r\n);iap_tickHAL_GetTick();}if(systick_time_diff(iap_tick)CONNECT_DATA_CYCLE){iap_tickHAL_GetTick();iap_statusJUMP_TO_APP;}break;caseJUMP_TO_APP:printf(Jump to APP\r\n);jump_to_app();printf(\r\nJump to APP Error!!!\r\n);iap_statusWAIT_CONNECT;break;default:break;}}}