通过Lua小程序,我们可以方便方便的在线方式做CANFD固件烧录,也可以离线方式运行Lua小程序做烧录。
本次是说明是采用H7-TOOL的CANFD方式连接我们V7板子做的操作说明。
【协议说明】
1、发送固件大小:符号‘*’ 来同步,然后发送固件大小,板子收到后,回复0x30表示擦除相应扇区大小成功,回复0x60表示擦除失败(由于TOOL的当前版本固件没有注册CANFD接收功能,所以简单做个延迟等待)。
2、发送固件数据:符号‘$’ 来同步,然后发送固件数据,每次224字节大小,板子收到后,回复0x30表示数据编程成功,回复0x60表示擦除失败。如此反复,一直到发送完毕(由于TOOL的当前版本固件没有注册CANFD接收功能,所以简单做个延迟等待)。
3、发送结束命令:符号‘#’ 表示传输结束,目标板可以加载到APP运行了。
【硬件接线】
H7-TOOL通过CAN接到V7板子的CANFD1接口上,注意CANH接CANH,CANL接CANL
V7板子使用CANFD1,注意跳线帽:
【准备工作】
当前上位机还没有做专门的CANFD接口脱机烧录一键下载界面,需要手动将Lua文件和app固件存到TOOL的eMMC
上电首界面长按S键 -> 系统设置 -> USB eMMC磁盘, 进入eMMC模拟U盘后,在如下路径新建文件夹串口脱机烧录
将如下两个文件存到新建的文件夹下
app.bin (50.03 KB)
canbootloader.lua (4.12 KB)
基于V7的CANFD接口脱机烧录目标板程序.7z (2 MB)
【在线方式操作说明】
H7-TOOL可以采用USB,以太网或者WiFi方式连接上位机。
将前面lua小程序canbootloader.lua的内容复制到如下窗口:
点击下面的执行按钮就可以看到动图更新了:
【离线方式操作说明】
操作TOOL显示屏,进入Lua小程序界面:
执行uartfirmware.lua小程序。
执行效果如下:
【Lua小程序简单说明】
注释非常详细:
- -------------------------------------------------------
- --
- -- H7-TOOL CAN FD脱机烧录Lua小程序实现
- --
- -------------------------------------------------------
- local str
- local len
- local bytes
- local bin
- local offset
- local value
- local count
- local filesize
- local byte0
- local byte1
- local byte2
- local byte3
- local filepath = "0:/H7-TOOL/Lua/CAN脱机烧录/app.bin" -- 表示CAN脱机烧录文件夹下存的文件
- local filepath1 = "0:/H7-TOOL/Lua/CAN脱机烧录" -- 浏览CAN脱机烧录文件下存的文件
- local can_id = 0x111 -- 目标板的ID
- local str_offset
- local str_offset1
-
-
- -------------------------------------------------------
- -- 第1步:浏览串口脱机烧录文件夹下存的文件
- -------------------------------------------------------
- f_dir(filepath1)
- print()
-
- -------------------------------------------------------
- -- 第2步:CAN FD配置
- -------------------------------------------------------
- print("CAN FD测试")
-
- --第1个参数
- ----open,close,send,recive
- --第2个参数
- ----- 0 表示FDCAN_FRAME_CLASSIC
- ----- 1 表示FDCAN_FRAME_FD_NO_BRS
- ----- 2 表示FDCAN_FRAME_FD_BRS
- --第3个参数,支持的数据个数
- ---- 表示64个字节
- --第4个参数,仲裁阶段波特率
- --第5个参数,数据阶段波特率
- can_bus("open", 2, 64, 500000, 2000000)
-
- -------------------------------------------------------
- -- 第3步:发送固件大小,方便目标板擦除相应大小扇区
- -------------------------------------------------------
- -- 获取固件大小
- filesize=f_size(filepath)
- print("============================================")
- str= string.format("固件大小:%d",filesize)
- print(str)
-
- -- 将固件大小转换成四个字节
- byte0 = ((filesize >> 0) & 0xFF)
- byte1 = ((filesize >> 8) & 0xFF)
- byte2 = ((filesize >> 16) & 0xFF)
- byte3 = ((filesize >> 24) & 0xFF)
-
- --发送固件大小给目标板
- --发送*号表示固件大小命令
- --发送固件大小
- --固定发送64字节
- str_offset = string.format("%02d", 64 - 5)
- str= string.format("%c%c%c%c%c".."%"..str_offset.."s", 42, byte0, byte1, byte2, byte3, "A")
-
- print(str)
-
- --第1个参数
- ----open,close,send,recive
- --第2个参数
- ----ID类型,0表示标准ID,1表示扩展ID
- --第3个参数
- ----0数据帧,1遥控帧
- --第4个参数
- ----字符串
- can_bus("send", 0, 0, can_id, str)
-
- print("执行扇区擦除.....")
-
- -- 正常这里应该等待CAN返回应答0x30,暂时用延迟实现
- delayms(2000)
-
- -------------------------------------------------------
- -- 第4步:发送固件大小
- -------------------------------------------------------
- offset = 0
- -- 第1个参数是路径,第2个参数的偏移地址,第3个参数读取大小
- -- 返回值bytes表示读取的字节数,bin表示都回的数据
- bytes, bin = f_read(filepath, 0, 32)
- offset = offset + bytes
-
- -- 读取数据为0,表示传输完毕
- while(bytes > 0)
- do
- -- 发送$表示开始传输固件命令
- -- 发送固件数据给目标板
- -- 固定每次发送64个字节
- count = 64 - 2 - bytes
- str_offset = string.format("%02d", count)
- str_offset1 = string.format("%"..str_offset.."s", "A")
- str_offset2 = string.format("$%c", bytes)
- str= str_offset2..bin..str_offset1
- can_bus("send", 0, 0, can_id, str)
-
- -- 等待目标板返回确认数据0x30
- -- 返回0x30表示发送成功
- -- 暂时用延迟实现
- delayms(30)
-
- bytes, bin = f_read(filepath, offset, 32) -- 继续读取数据
- offset = offset + bytes
- if(bytes ~= 0) then -- 读取不为0,打印发送的总字节数
- print("发送固件:", offset)
- end
- end
-
- -------------------------------------------------------
- -- 第5步:发送传输结束命令
- -------------------------------------------------------
- str_offset = string.format("%02d", 64 - 1)
- str= string.format("#".."%"..str_offset.."s", "A")
- can_bus("send", 0, 0, can_id, str)
- print("固件传输完成")
-
- -------------------------------------------------------
- -- end of file
- -------------------------------------------------------
【目标板程序简单说明】
最关键的就是串口程序处理:
- /*
- *********************************************************************************************************
- *
- * 模块名称 : CAN方式固件升级
- * 文件名称 : demo_canfd_update.c
- * 版 本 : V1.0
- * 说 明 : CAN方式固件升级
- *
- * 修改记录 :
- * 版本号 日期 作者 说明
- * V1.0 2022-06-15 Eric2013 正式发布
- *
- * Copyright (C), 2022-2030, 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url]
- *
- *********************************************************************************************************
- */
- #include "bsp.h"
-
-
-
- /*
- *********************************************************************************************************
- * 函数
- *********************************************************************************************************
- */
- /* 仅允许本文件内调用的函数声明 */
- static void JumpToApp(void);
- void can_Init(void);
- void can_DeInit(void);
-
- /*
- *********************************************************************************************************
- * 宏定义
- *********************************************************************************************************
- */
- #define AppAddr 0x08100000 /* APP地址 */
-
- /*
- *********************************************************************************************************
- * 变量
- *********************************************************************************************************
- */
- __IO uint32_t uwCRCValue;
- __IO uint32_t uwExpectedCRCValue;
- __IO uint32_t uwAppSize;
-
- uint8_t buf[1024];
- uint32_t RecCount = 0;
- uint32_t RecCount0 = 0;
- uint32_t RecSize = 0;
- uint8_t RecCplt = 0;
- uint32_t filesize = 0;
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: DemoCANUpdate
- * 功能说明: CAN烧录
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void DemoCANUpdate(void)
- {
- uint8_t cmd;
- uint32_t SectorCount = 0;
- uint32_t SectorRemain = 0;
- uint32_t i;
- uint32_t TotalSize = 0;
- uint8_t ucState;
- MSG_T msg;
-
- can_Init(); /* 初始化CAN */
-
- bsp_StartAutoTimer(0, 500); /* 启动1个500ms的自动重装的定时器 */
-
- while (1)
- {
- /* 判断定时器超时时间 */
- if (bsp_CheckTimer(0))
- {
- /* 每隔500ms 进来一次 */
- bsp_LedToggle(2);
- }
-
- if (bsp_GetMsg(&msg))
- {
- switch (msg.MsgCode)
- {
- case MSG_CAN1_RX: /* 接收到CAN设备的应答 */
- cmd = g_Can1RxData[0];
- printf("size = %d, cmd = %c\r\n",g_Can1RxHeader.DataLength>>16, cmd);
- /* 开始传输固件命令 **************/
- if(cmd == '$')
- {
- /* 接收够224个数据 */
- RecSize = g_Can1RxData[1];
-
- /* 编程内部Flash, */
- ucState = bsp_WriteCpuFlash((uint32_t)(AppAddr + TotalSize), (uint8_t *)&g_Can1RxData[2], RecSize);
- TotalSize += RecSize;
- printf("=====%d\r\n", TotalSize);
-
- /* 如果返回非0,表示编程失败 */
- if(ucState != 0)
- {
- /* 返回0x60,表示编程失败 */
- }
-
- /* 返回0x30,表示编程成功 */
- }
-
- /* 传输完成命令 **************/
- if(cmd == '#')
- {
- JumpToApp();
- }
-
- /* 接收固件大小命令 */
- if(cmd == '*')
- {
- filesize = g_Can1RxData[1] + (g_Can1RxData[2] << 8) + (g_Can1RxData[3] << 16) + (g_Can1RxData[4] << 24);
- uwAppSize = filesize;
- SectorCount = filesize/(128*1024);
- SectorRemain = filesize%(128*1024);
-
- printf("filesize = %d\r\n", filesize);
- for(i = 0; i < SectorCount; i++)
- {
- bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
- }
-
- if(SectorRemain)
- {
- bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
- }
-
- /* 返回0x30,表示擦除成功 */
- }
- break;
- }
- }
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: JumpToApp
- * 功能说明: 跳转到应用JumpToApp
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- static void JumpToApp(void)
- {
- uint32_t i=0;
- void (*AppJump)(void); /* 声明一个函数指针 */
-
- /* 关闭全局中断 */
- DISABLE_INT();
-
- /* 设置所有时钟到默认状态,使用HSI时钟 */
- HAL_RCC_DeInit();
-
- /* 关闭滴答定时器,复位到默认值 */
- SysTick->CTRL = 0;
- SysTick->LOAD = 0;
- SysTick->VAL = 0;
-
- /* 关闭所有中断,清除所有中断挂起标志 */
- for (i = 0; i < 8; i++)
- {
- NVIC->ICER[i]=0xFFFFFFFF;
- NVIC->ICPR[i]=0xFFFFFFFF;
- }
-
- /* 使能全局中断 */
- ENABLE_INT();
-
- /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
- AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
-
- /* 设置主堆栈指针 */
- __set_MSP(*(uint32_t *)AppAddr);
-
- /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
- __set_CONTROL(0);
-
- /* 跳转到系统BootLoader */
- AppJump();
-
- /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
- while (1)
- {
-
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: can_Init
- * 功能说明: 配置CAN硬件
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void can_Init(void)
- {
- bsp_InitCan1();
- bsp_InitCan2();
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: can_DeInit
- * 功能说明: 退出CAN硬件硬质,恢复CPU相关的GPIO为缺省;关闭CAN中断
- * 形 参: 无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void can_DeInit(void)
- {
- bsp_DeInitCan1();
- bsp_DeInitCan2();
- }
-
- /***************************** 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url] (END OF FILE) *********************************/
【参考资料】
之前更新过三期BootLoader的视频教程,可以作为参考学习:
单片机bootloader专题,启动,跳转配置和调试下载的各种用法
BSP视频教程第17期:单片机bootloader专题,启动,跳转配置和调试下载的各种用法(2022-06-10) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!
基于NAND,eMMC,SD卡和U盘的BootLoader实战,带CRC完整性校验
BSP视频教程第18期:基于NAND,eMMC,SD卡和U盘的BootLoader实战,带CRC完整性校验(2022-06-16) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!
单片机BootLoader的AES加密实战,含上位机和下位机代码全开源
BSP视频教程第19期:单片机BootLoader的AES加密实战,含上位机和下位机代码全开源(2022-06-26) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!