s9keaz128 UART Bootloader 单片机篇(上)

一:前言

网络上充斥着各种各样的串口升级方案,基本都是基于Y-Mode协议下载。采用这种升级方案学习还是可以,用在产品上还是有点欠缺。如下载完成后,需要把时间发送到设备就不好搞了。如下这个设备返回的信息,最后一项就是固件更新时间。

固件名称: KEA128

编译时间: 2022/03/02 14:25:18

固件版本: 1.0.3

硬件版本: 1.0.3

产品序列号: 30304536001 A2210000002D

功能名称: App

固件更新时间: 2022/03/02 14:26:46

串口升级演示视频

项目源码下载:

【免费】s9keaz128串口升级方案1:上位机qt5源码2:单片机底层与应用程序3:烧写文档4:原理图资源-CSDN文库

二:升级协议

1:获取固件信息

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

01

00 00

-

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

01

LL   HH

 “版本”

校验和

5A

2:运行命令

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

02

04 00

地址(xx xx xx xx)

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

02

01   00

 00-失败  01-成功

校验和

5A

3:擦除Flash命令

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

03

08 00

地址(AA AA AA AA)

长度(LL LL LL LL)

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

03

01   00

 00-失败  01-成功

校验和

5A

4:写数据命令

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

04

LL LL

数据

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

04

01   00

 00-失败  01-成功

校验和

5A

5:设置写地址命令

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

05

04 00

地址(AA AA AA AA)

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

05

01   00

 00-失败  01-成功

校验和

5A

6:数据校验命令

PC发送:

头部

功能

数据长度

数据

校验

结束

55 AA

06

13 00

当前时间如“2024/02/02 10:00:00”

校验和

5A

设备返回:

头部

功能

数据长度

数据

校验

结束

55 AA

06

01   00

 00-失败  01-成功

校验和

5A

三:数据接收与处理

数据接收采用环形缓冲区,串口中断接收数据后放入缓冲区,主函数对数据监听与处理。大致如下处理流程

1:串口接收数据后放入环形缓冲区

2:从环形缓存区取出一帧数据

3:处理数据

四:关键性软件

void Boot_Executive(void)

{

    uint8_t head_data[USER_CMD_STRUCT_LEN];

    int offset;

    uint8_t CallFucNumber;

    uint8_t func;

    unsigned int  lenght;

    uint8_t end;   

    uint8_t checkSum;           

    unsigned int queueAvailLen;

start:

     //获取环形缓存区数据长度

      queueAvailLen = fifo_used(&uart1_fifo);

      if(queueAvailLen >= USER_CMD_STRUCT_LEN) //缓冲器中有数据

      {

          //偷看下数据最小长度

        fifo_out_peek(&uart1_fifo,head_data,USER_CMD_STRUCT_LEN);

        //查找头部 55 AA

offset = finSerialDatahead(head_data,USER_CMD_STRUCT_LEN);

        if(offset>0)

        {

            fifo_out_clear(&uart1_fifo,offset);//删除前面无效数据

            goto start;

        }

           func    = head_data[2];

           lenght =  (uint8_t)head_data[4];

             lenght <<= 8;

           lenght |= (uint8_t)head_data[3];

          if(lenght>512) //一帧数据最大长度设置

          {

              fifo_out_clear(&uart1_fifo,2);//去掉头部

              goto start;

          }

          if(queueAvailLen>=(int)(lenght+7))//可能有完整一帧数据

          {

            //都不数据已无用清除

            fifo_out_clear(&uart1_fifo,USER_CMD_STRUCT_LEN-2);           

            //获取数据部分

fifo_out_peek(&uart1_fifo,uart_frame,lenght+2);

            //获取尾部数据5A

end = uart_frame[lenght+1];

//对数据区计算校验

            checkSum = uart_checkSum(func,&uart_frame[0],lenght);

            //判断尾部与校验和 

            if(end ==0x5a && checkSum == uart_frame[lenght])

            {

              CallFucNumber = sizeof(UserUartFunctionCall)/sizeof(UartOutProCessFunc);

               if(func<CallFucNumber)

               {

                 if(UserUartFunctionCall[func]!=NULL)

                 {

                        g_BootLoaderCmd.autoFlag = 0;

                   UserUartFunctionCall[func](func,&uart_frame[0],lenght);

                 }

               }

               //开始处理数据

                fifo_out_clear(&uart1_fifo,lenght+2);

             }else

             {

                fifo_out_clear(&uart1_fifo,lenght+2); //清除头部

               //"数据帧异常";

             }

          }

       }

       Boot_ExecutiveJump(&g_BootLoaderCmd);

}

1:判断数据是否大于等于最小数据长度7字节。

2:读取7字节,查找头部 55 AA  位置

3:头位置不是0清除前面无效数据返回到第一步。

4:判断帧数据长度;长度大于最大长度代表帧异常,清除头部 55 AA两字节返回第一步。

5:判断缓冲区数据长度是否大于等于数据长度+7,表示是否有完整帧。

6:计算数据校验和,以及对尾部5A判断 异常清除头部 55 AA两字节返回第一步。

7:处理数据数据。

处理功能集合,通过函数指针调用:

typedef void (*UartOutProCessFunc)(uint8_t func,uint8_t *buf,uint32_t len);

UartOutProCessFunc UserUartFunctionCall[]=

{

    NULL, //0

    get_board_info, //1

    run_app_command,//2

    erase_flash_command, //3

    write_data_command,//4

    set_start_address_command,//5

    verify_data_command,//6

     

};

例如运行命令:

void run_app_command(uint8_t func,uint8_t *buf,uint32_t len)

{

      uint32_t adrress=0;

      uint8_t  status;

      adrress = CharToIntBigEnd(&buf[0],4);        

      if((adrress>=APP_START_ADDR) && (adrress<FLASH_END_ADDR))

      {

        g_BootLoaderCmd.jump_address = adrress;

        g_BootLoaderCmd.status = 0x01; //需要跳转

        status = 1;

      }

      else

      {

         status = 0;

      }

      uart_WriteFrame(func,&status,1);  //返回状态         

 }

返回数据处理:

uint8_t uart_WriteFrame(uint8_t func,uint8_t *buf,unsigned int lenght)

{

     unsigned int i;

     if(lenght>MAX_FRAME_DATA_NUMBER) return 1;

      uart2_Txbuf[0] = 0x55;

      uart2_Txbuf[1] = 0xAA;

      uart2_Txbuf[2] = func;

      uart2_Txbuf[3] = lenght&0xff;

      uart2_Txbuf[4] = (lenght>>8)&0xff;

      memcpy(&uart2_Txbuf[5],buf,lenght);

      uart2_Txbuf[5+lenght] = uart_checkSum(func,buf,lenght);

      uart2_Txbuf[6+lenght] = 0x5a;

      for(i=0;i<lenght+7;i++)

      UART_PutChar(UART0,uart2_Txbuf[i]);

   return 0;

}

不断对上位机发送的命令处理,以及对处理状态的应答。经过一些列处理后完成对单片机Flash的擦除,写,校验。

五:工程

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值