[STM32F4]

基于STM32(串口+DMA+空闲中断+环形缓冲区)实现 YMODEM协议IAP在线烧写程序

[复制链接]
4876|5
手机看帖
扫描二维码
随时随地手机跟帖
zero949079783|  楼主 | 2024-4-21 16:01 | 显示全部楼层 |阅读模式
本帖最后由 zero949079783 于 2024-4-21 23:12 编辑

基于STM32(串口+DMA+空闲中断+环形缓冲区)实现 YMODEM协议IAP在线烧写程序
BootLoader 扇区: 0x08000000  - 0x08004000 共16K大小

生成BIN: fromelf.exe --bin -o "$L@L.bin" "#L

上位机软件:SecureCRT

371096624ce7eeb687.png

Ymodem_STM32F1:
链接:https://pan.baidu.com/s/1SO34uS3flsdE8MdL4HHU0g?pwd=802v
提取码:802v
Ymodem_STM32F4:
链接:https://pan.baidu.com/s/13Kh6QzgNosYnYE5fJ-TB4Q?pwd=u5tj
提取码:u5tj
https://gitee.com/csx949089783/ymodem_-stm32-f4.git









YMODED接口函数:
#include "ymodem.h"
#include "crc.h"
#include "usart.h"
#include "inner_flash.h"
#include "delay.h"
#include "key.h"
#define YMODEM_TIME 10


typedef  void (*pFunction)(void);
pFunction Jump_To_Application;


typedef struct{
        uint8_t OTA_FLAG :          1;
        uint8_t YMODE_FLAG : 1;
        uint8_t YMODE_Frist_FLAG :1;
        uint8_t YMODE_Frist_Pack_FLAG: 1;
        uint8_t YMODE_EOH_STX_DATALEN_FLAG :1;               
        uint8_t fileName[256];                                                                                //文件名        
        uint8_t  UpdataBuffer[STM32_PAGE_SIZE];                //接收数据缓冲区        
        uint16_t time;                                                                                                                                        //OTA退出时间
        uint16_t count;                                                        
        uint32_t num;                                                                                                                        //接收数据包数
        uint32_t STXnum;                                                                                                        //接收数据包数               
        uint32_t crc;                                                                                                                        //CRC校验
        uint32_t remanider;                                                                                                //数据余数
        uint32_t packnum;                                                                                                        //数据总包数
        uint32_t remaniderpacknum;                                                                //数据余数总包数(1024时)
        uint32_t fileSize;                                                                                                //文件大小
        uint32_t JumpAddress;                                                                                        //APP跳转地址
}YMODEM_T ;

YMODEM_T ymodem_t;

void Ymodem_Init(void)
{
        memset(&ymodem_t,0,sizeof(ymodem_t));
        ymodem_t.time = YMODEM_TIME;
}


static void BootLoader_To_App(void)
{
        Delay_ms(1);
        printf("\r\n");
        printf("BootLoader_To_App.....\r\n");
        Delay_ms(1);
        FLASH_Lock();
        
        SysTick->CTRL &= SysTick_CTRL_TICKINT_Msk;        //关滴答定时器
        
  ymodem_t.JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);        
  /* Jump to user application */
  Jump_To_Application = (pFunction) ymodem_t.JumpAddress;
  /* Initialize user application's Stack Pointer */
  __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
  Jump_To_Application();
}

static void BootLoader_SendByte(uint8_t data)
{
        Usartx_SendArray(USART1,&data,1);
}

/*************************************************************************
*        函 数 名: BootLoader_EraseFlash
*        功能说明: Flash扇区擦除
*        形    参:startSectorAddr:起始扇区地址    numSector:扇区个数
*        返 回 值: 无
**************************************************************************/
void BootLoader_EraseFlash(void)
{
        STM32_EraseFlash(STM32_A_SADDR,11);
}

/*************************************************************************
*        函 数 名: BootLoader_WriteFlash
*        功能说明: 数据写入
*        形    参:startAddr:起始地址   writeData:写入数据   numByte:写入字节数
*        返 回 值: 无
**************************************************************************/
static void BootLoader_WriteFlash(uint32_t startAddr, uint32_t* writeData, uint32_t numByte)
{
        STM32_WriteFlash(startAddr,writeData,numByte);
}



void BootLoader_Meun(void)
{
        static uint16_t times = 0;
        times ++;

         if(ymodem_t.OTA_FLAG == YMODEM_DISABLE && times%1000 == 0)
                {               
                        ymodem_t.time --;
                        
                        printf(" \r\n %ds后退出BootLoader\r\n ",ymodem_t.time);
                        if(ymodem_t.time <= 0)
                        {
                                BootLoader_To_App();
                        }
                }
                else if(ymodem_t.YMODE_FLAG == YMODEMD_ENABLE && times %500 == 0)
                {
                        ymodem_t.time = YMODEM_TIME;
                        BootLoader_SendByte(CA);        //发送握手
                }

        //按键双击进入OTA
        if( get_Key_Val() == 0x51 && ymodem_t.YMODE_FLAG == YMODEM_DISABLE && ymodem_t.OTA_FLAG == YMODEM_DISABLE)
        {        
                        printf("EraseFlash......\r\n");
                        BootLoader_EraseFlash();
                        printf("EraseFlash successfully \r\n");
                        ymodem_t.OTA_FLAG = 1;
                        ymodem_t.YMODE_FLAG = 1;
        }


}

static void BootLoader_Com(uint8_t *data)
{
        if(memcmp(data,"1",1)==0 )        //当接收到上位机或者双击时,进入OTA
        {
                        printf("EraseFlash......\r\n");
                        BootLoader_EraseFlash();
                        printf("EraseFlash successfully \r\n");
                        ymodem_t.OTA_FLAG = 1;
                        ymodem_t.YMODE_FLAG = 1;
        }
}

/***************************************************************************
Ymodem数据帧:        
                帧头                  包号 包号反码         信息块                                                 校验
        SOH/STX                 PN                 XPN                         DATA 128/1024                 CRC16(CRCH CRCL)
                1:对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。
                2:对于STX帧需考虑几种情况

帧长度:
                1:以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节
                2:以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节
                        a:●余下数据等于1024字节,以1029长度帧发送;
                        b:●余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充
                        c:●余下数据等于128字节,以133字节帧长度发送
                        d:●余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充

包序号:
        数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。

校验:
        Ymodem采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码

起始帧:
        Ymodem起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下
        帧头                          包号 包号反码                 文名件称                                          文件大小                                                        填充区                                 校验
        SOH/STX                PN                 XPN                                fileName+0x00                                fileSize+0x00                                                0x00                                CRC16(CRCH CRCL)

Ymodem结束帧
                帧头                  包号         包号反码                         信息块                                                 校验
                SOH                                 PN                         XPN                                  0x00                                                        CRC16(CRCH CRCL)
               
               
文件传输过程

文件的传输过程,以具体的例子说明。把foo.c,大小为4196Byte(16进制为0x1064)的文件作为传输的对象,则它的传输过程如下:
发送端----------------------------------------------------------------接收端

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

SOH 00 FF “foo.c” "1064’’ NUL[118] CRC CRC >>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

SOH 05 FA data[100] 1A[28] CRC CRC>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< NAK

EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C

SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ACK        
*******************************************************************************************/

void Ymodem_Receive(uint8_t *data,uint16_t datalen)
{
        char *fileSizebuff;
        char fileSize[50];                        //文件大小
        uint8_t i = 0,j=0;
        
        if(ymodem_t.OTA_FLAG == YMODEM_DISABLE)
        {
                BootLoader_Com(data);
        }
        
        //当是第0包数据时,和最1后才能进入,
        if((data[0] == SOH && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_SOH_PACKLEN) || ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE )        //Ymodem起始帧: 113
        {               
                        ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
                        if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1]))        //CRC
                        {
                                       
                                        if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE)        //第1次
                                        {
                                                ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
                                                ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE ;        //第1包接收标志位置使能,说时第一包接好
                                                for(i=0;data[3+i] !='\0';i++)                //读取文件名
                                                {
                                                        ymodem_t.fileName[i] = data[3+i];
                                                }
                                                i++;
                                                for(j=0;data[3+i+j] != '\0';j++)        //读取文件大小
                                                {
                                                        fileSize[j] = data[3+i+j];
                                                }
                                                
                                                        ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
                                                        ymodem_t.remanider =         ymodem_t.fileSize % YMODE_SOH_DATALEN;        
                                                        ymodem_t.packnum   =        ymodem_t.fileSize /        YMODE_SOH_DATALEN;
                                                        if(ymodem_t.remanider > 0)
                                                                ymodem_t.packnum = ymodem_t.packnum+1;
                                                        
                                                BootLoader_SendByte(ACK);        //正确发送ACK
                                                BootLoader_SendByte(CA);
                                        }
                                        else if(ymodem_t.YMODE_Frist_FLAG == YMODEMD_ENABLE)
                                        {
                                                
                                                BootLoader_SendByte(ACK);        //正确发送ACK
                                                
                                                BootLoader_SendByte(CA);        //正确发送ACK

                                                Delay_ms(20);
                                                printf("\r\n");
                                                printf("fileName :%s \r\n",ymodem_t.fileName);
                                                printf("fileSize :%d Byte\r\n",ymodem_t.fileSize);
                                                printf("File uploaded successfully  \r\n");
                                                printf("\r\n");
                                                Ymodem_Init();
                                                BootLoader_To_App();
                                                
                                        }
                        }
                        else{
                                BootLoader_SendByte(NAK);        //错误发送NAK
                        }
                        
        }
        else if((data[0] == STX && data[1] == 0x00 && data[2] == 0xff && ymodem_t.YMODE_Frist_Pack_FLAG == YMODEM_DISABLE && datalen == YMODE_STX_PACKLEN))        ////Ymodem起始帧: 1024
        {
                        ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
                        if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1]))        //CRC
                        {
                                        if(ymodem_t.YMODE_Frist_FLAG == YMODEM_DISABLE)        //第1次
                                        {
                                                ymodem_t.YMODE_FLAG = YMODEM_DISABLE;
                                                ymodem_t.YMODE_Frist_Pack_FLAG = YMODEMD_ENABLE;        //第1包接收标志位置使能,说时第一包接好
                                                
                                                for(i=0;data[3+i] !='\0';i++)                //读取文件名
                                                {
                                                        ymodem_t.fileName[i] = data[3+i];
                                                }
                                                i++;
                                                for(j=0;data[3+i+j] != '\0';j++)        //读取文件大小
                                                {
                                                        fileSize[j] = data[3+i+j];
                                                }
                                                        ymodem_t.fileSize = strtol(fileSize,&fileSizebuff,10);
                                                

                                                
                                                        //数据1024时,数据是1024时,按1024接收,当小于1024时,以每包128个字传接收,直到所有数据收完
                                                        ymodem_t.remanider =         ymodem_t.fileSize % YMODE_STX_DATALEN;                //余下字节个数
                                                        
                                                        ymodem_t.remaniderpacknum = ymodem_t.remanider / YMODE_SOH_DATALEN;        //余下字节以128接收的包数据
                                                        
                                                        ymodem_t.packnum   =        (ymodem_t.fileSize /        YMODE_STX_DATALEN)  ;                //1024总包数        
                                                        if(ymodem_t.remanider  > 0)
                                                        {
                                                                ymodem_t.remaniderpacknum = ymodem_t.remaniderpacknum +1;
                                                                ymodem_t.packnum = ymodem_t.packnum+1;
                                                        }
                                                        
                                                        ymodem_t.YMODE_EOH_STX_DATALEN_FLAG = YMODEMD_ENABLE;                        
                                       
                                                BootLoader_SendByte(ACK);        //正确发送ACK
                                                BootLoader_SendByte(CA);
                                                        
                                        }        
                        }
                        else{
                                BootLoader_SendByte(NAK);        //错误发送NAK
                        }
        }
        else if(data[0] == SOH && datalen == YMODE_SOH_PACKLEN)        //Ymodem数据帧:当数据以大小是128字节时
        {                        
                        ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_SOH_DATALEN);
                        if(ymodem_t.crc == ((data[YMODE_SOH_PACKLEN - 2]<<8) |data[YMODE_SOH_PACKLEN - 1]))        //CRC
                        {
                                                ymodem_t.num ++;        //已接收的数据包数量+1
                                       
                                                //将本次接收的数据,暂存到ymodem_t.UpdataBuffer缓冲                                                
                                                        memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.num - 1) % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN],&data[3], YMODE_SOH_DATALEN);   //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
                                                if(ymodem_t.YMODE_EOH_STX_DATALEN_FLAG == YMODEM_DISABLE)        //当是128每包数据时
                                                {
                                                        if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.num ))        //每满一个扇区写入Flash
                                                        {                                                        
                                                                //写入到单片机A区相应的扇区
                                                                BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
                                                               
                                                                //备份FLASG写入
                                                        }
                                                        else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.packnum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
                                                        {
                                                                //写入到单片机A区相应的扇区
                                                                BootLoader_WriteFlash(STM32_A_SADDR  + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN);    //写入到单片机A区相应的扇区
                                                               
                                                                //备份FLASG写入        
                                                        }
                                                }
                                                else {
                                                        if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) == 0) &&( ymodem_t.remaniderpacknum!=ymodem_t.num ))        //每满一个扇区写入Flash
                                                        {                                                        
                                                                //写入到单片机A区相应的扇区
                                                                BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE)+(((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
                                                               
                                                                //备份FLASG写入
                                                        }        
                                                        else if(((ymodem_t.num % (STM32_PAGE_SIZE/YMODE_SOH_DATALEN)) != 0) &&(ymodem_t.remaniderpacknum==ymodem_t.num))//最后一包数,判断是否还有不满1扇区1024字节的数据,如果有进入if,把剩余的小尾巴写入
                                                        {
                                                                //写入到单片机A区相应的扇区
                                                                BootLoader_WriteFlash(STM32_A_SADDR + (ymodem_t.STXnum * STM32_PAGE_SIZE) + (((ymodem_t.num / (STM32_PAGE_SIZE / YMODE_SOH_DATALEN))) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,(ymodem_t.num % (STM32_PAGE_SIZE / YMODE_SOH_DATALEN)) * YMODE_SOH_DATALEN);    //写入到单片机A区相应的扇区                                                
                                                               
                                                                //备份FLASG写入        
                                                        }                                                        
                                                }

                                                BootLoader_SendByte(ACK);        //正确发送ACK
                                                        
                        }
                        else{
                                BootLoader_SendByte(NAK);        //错误发送NAK
                        }
        }
        else if(data[0] == STX && datalen == YMODE_STX_PACKLEN)        //Ymodem数据帧:当数据是1029字节时
        {
                        ymodem_t.crc = CRC16_XMODEM(&data[3],YMODE_STX_DATALEN);
                        if(ymodem_t.crc == ((data[YMODE_STX_PACKLEN - 2]<<8) |data[YMODE_STX_PACKLEN - 1]))        //CRC
                        {
                                ymodem_t.STXnum++;
                                memcpy(&ymodem_t.UpdataBuffer[((ymodem_t.STXnum- 1) % (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) * YMODE_STX_DATALEN],&data[3], YMODE_STX_DATALEN);   //将本次接收的数据,暂存到UpDataA.Updatabuff缓冲区
                                if(((ymodem_t.STXnum % (STM32_PAGE_SIZE/YMODE_STX_DATALEN)) == 0) &&( ymodem_t.packnum!=ymodem_t.STXnum))        //每满一个扇区写入Flash
                                {                                                        
                                        //写入到单片机A区相应的扇区
                                        BootLoader_WriteFlash(STM32_A_SADDR + (((ymodem_t.STXnum/ (STM32_PAGE_SIZE / YMODE_STX_DATALEN)) -1) * STM32_PAGE_SIZE), (uint32_t *)ymodem_t.UpdataBuffer,STM32_PAGE_SIZE);    //写入到单片机A区相应的扇区
                                       
                                        //备份FLASG写入
                                       
                                }
                                
                                BootLoader_SendByte(ACK);        //正确发送ACK
                        }
                        else{
                                BootLoader_SendByte(NAK);        //错误发送NAK
                        }
               
        }
        else if(data[0] == EOT && datalen == YMODE_EOT_DATALEN)        //当接收到EOT
        {        
                if(ymodem_t.count == 0)
                {
                        ymodem_t.count ++;
                        BootLoader_SendByte(NAK);        //正确发送NAK

                }
                else if(ymodem_t.count == 1)
                {
                        ymodem_t.YMODE_Frist_FLAG = YMODEMD_ENABLE;
                        ymodem_t.count = 0;
                        BootLoader_SendByte(ACK);        //正确发送ACK                        
                        BootLoader_SendByte(CA);        //正确发送C        

                }
        }
        else if(data[0] == CAN && data[1] == CAN && data[2] == CAN && data[3] == CAN && data[4] == CAN )        //取消传输命令,连续发送5个该命令
        {
                        ymodem_t.OTA_FLAG = YMODEM_DISABLE;
                        Ymodem_Init();
        }
}


#ifndef __YMODEM_H
#define __YMODEM_H

#include "stm32f4xx.h"

#define  STM32_FLASH_SADDR   0x08000000                                                              //FLASH扇区起始地址
#define  STM32_PAGE_SIZE     1024                                                                    //FLASH扇区大小
#define  STM32_PAGE_NUM      1024                                                                     //FLASH扇区总个数
#define  STM32_B_PAGE_NUM    16                                                                      //BootLoader 扇区个数

#define  STM32_A_PAGE_NUM    (STM32_PAGE_NUM - STM32_B_PAGE_NUM)                                                                                                         //APP扇区个数
#define  STM32_A_START_PAGE  (STM32_B_PAGE_NUM)                                                                                                                                                                                //APP扇区起始数
#define  STM32_A_SADDR       (STM32_FLASH_SADDR + STM32_A_START_PAGE * STM32_PAGE_SIZE)                //APP扇区起始地址

#define APPLICATION_ADDRESS (STM32_A_SADDR)                                                                                                                                                                                                //APP跳转地址


#define YMODE_SOH_PACKLEN 133                        //SOH数据包长度
#define YMODE_STX_PACKLEN 1029                //SOH数据包长度        
#define YMODE_SOH_DATALEN 128                        //SOH有效数据长度
#define YMODE_STX_DATALEN 1024                //SOH有效数据长度        
#define YMODE_EOT_DATALEN   1

typedef enum {YMODEM_DISABLE = 0, YMODEMD_ENABLE = !YMODEM_DISABLE} YmodemState;

typedef enum{
        SOH = 0X01,//133字节长度帧
        STX = 0X02,//1024字节长度帧
        EOT = 0X04,//文件传输结束命令
        ACK = 0X06,//接收正确应答命令
        NAK = 0X15,//重传当前数据包请求命令
        CAN = 0X18,//取消传输命令,连续发送5个该命令
        CA   = 0X43,//字符C ,发送握手        
}YMODEM_COM;

void Ymodem_Init(void);
void BootLoader_Meun(void);
void Ymodem_Receive(uint8_t *data,uint16_t datalen);
#endif








使用特权

评论回复
zhengshuai888| | 2024-4-21 19:25 | 显示全部楼层
Y我晕,还要付费才能看啊。

使用特权

评论回复
WoodData| | 2024-4-21 22:25 | 显示全部楼层
这种IAP都很简单了

使用特权

评论回复
zero949079783|  楼主 | 2024-4-21 23:14 | 显示全部楼层
WoodData 发表于 2024-4-21 22:25
这种IAP都很简单了

简单但是烦而已

使用特权

评论回复
lidi911| | 2024-4-22 08:35 | 显示全部楼层
除了YModem还有XModem和ZModem

使用特权

评论回复
cmyldd| | 2024-5-11 10:01 | 显示全部楼层
协议是有许多种的, 原理差不多都一样,用熟哪种就那种

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

81

帖子

1

粉丝