• H7-TOOL的CANFD/CAN接口脱机烧写操作说明, 已经更新(2022-07-12)


    通过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

    1、H7-TOOL进入虚拟U盘

    上电首界面长按S键 -> 系统设置 -> USB eMMC磁盘, 进入eMMC模拟U盘后,在如下路径新建文件夹串口脱机烧录

     将如下两个文件存到新建的文件夹下

      app.bin (50.03 KB)

      canbootloader.lua (4.12 KB)

     


    2、将目标板程序下载到V7开发板

    基于V7的CANFD接口脱机烧录目标板程序.7z (2 MB)

    【在线方式操作说明】

    H7-TOOL可以采用USB,以太网或者WiFi方式连接上位机。

    将前面lua小程序canbootloader.lua的内容复制到如下窗口:

     点击下面的执行按钮就可以看到动图更新了:

     



    【离线方式操作说明】

    操作TOOL显示屏,进入Lua小程序界面:

     

    执行uartfirmware.lua小程序。

    执行效果如下:

     


    【Lua小程序简单说明】

    注释非常详细:

    1. -------------------------------------------------------
    2. --
    3. -- H7-TOOL CAN FD脱机烧录Lua小程序实现
    4. --
    5. -------------------------------------------------------
    6. local str
    7. local len
    8. local bytes
    9. local bin
    10. local offset
    11. local value
    12. local count
    13. local filesize
    14. local byte0
    15. local byte1
    16. local byte2
    17. local byte3
    18. local filepath = "0:/H7-TOOL/Lua/CAN脱机烧录/app.bin" -- 表示CAN脱机烧录文件夹下存的文件
    19. local filepath1 = "0:/H7-TOOL/Lua/CAN脱机烧录" -- 浏览CAN脱机烧录文件下存的文件
    20. local can_id = 0x111 -- 目标板的ID
    21. local str_offset
    22. local str_offset1
    23. -------------------------------------------------------
    24. -- 第1步:浏览串口脱机烧录文件夹下存的文件
    25. -------------------------------------------------------
    26. f_dir(filepath1)
    27. print()
    28. -------------------------------------------------------
    29. -- 第2步:CAN FD配置
    30. -------------------------------------------------------
    31. print("CAN FD测试")
    32. --第1个参数
    33. ----open,close,send,recive
    34. --第2个参数
    35. ----- 0 表示FDCAN_FRAME_CLASSIC
    36. ----- 1 表示FDCAN_FRAME_FD_NO_BRS
    37. ----- 2 表示FDCAN_FRAME_FD_BRS
    38. --第3个参数,支持的数据个数
    39. ---- 表示64个字节
    40. --第4个参数,仲裁阶段波特率
    41. --第5个参数,数据阶段波特率
    42. can_bus("open", 2, 64, 500000, 2000000)
    43. -------------------------------------------------------
    44. -- 第3步:发送固件大小,方便目标板擦除相应大小扇区
    45. -------------------------------------------------------
    46. -- 获取固件大小
    47. filesize=f_size(filepath)
    48. print("============================================")
    49. str= string.format("固件大小:%d",filesize)
    50. print(str)
    51. -- 将固件大小转换成四个字节
    52. byte0 = ((filesize >> 0) & 0xFF)
    53. byte1 = ((filesize >> 8) & 0xFF)
    54. byte2 = ((filesize >> 16) & 0xFF)
    55. byte3 = ((filesize >> 24) & 0xFF)
    56. --发送固件大小给目标板
    57. --发送*号表示固件大小命令
    58. --发送固件大小
    59. --固定发送64字节
    60. str_offset = string.format("%02d", 64 - 5)
    61. str= string.format("%c%c%c%c%c".."%"..str_offset.."s", 42, byte0, byte1, byte2, byte3, "A")
    62. print(str)
    63. --第1个参数
    64. ----open,close,send,recive
    65. --第2个参数
    66. ----ID类型,0表示标准ID,1表示扩展ID
    67. --第3个参数
    68. ----0数据帧,1遥控帧
    69. --第4个参数
    70. ----字符串
    71. can_bus("send", 0, 0, can_id, str)
    72. print("执行扇区擦除.....")
    73. -- 正常这里应该等待CAN返回应答0x30,暂时用延迟实现
    74. delayms(2000)
    75. -------------------------------------------------------
    76. -- 第4步:发送固件大小
    77. -------------------------------------------------------
    78. offset = 0
    79. -- 第1个参数是路径,第2个参数的偏移地址,第3个参数读取大小
    80. -- 返回值bytes表示读取的字节数,bin表示都回的数据
    81. bytes, bin = f_read(filepath, 0, 32)
    82. offset = offset + bytes
    83. -- 读取数据为0,表示传输完毕
    84. while(bytes > 0)
    85. do
    86. -- 发送$表示开始传输固件命令
    87. -- 发送固件数据给目标板
    88. -- 固定每次发送64个字节
    89. count = 64 - 2 - bytes
    90. str_offset = string.format("%02d", count)
    91. str_offset1 = string.format("%"..str_offset.."s", "A")
    92. str_offset2 = string.format("$%c", bytes)
    93. str= str_offset2..bin..str_offset1
    94. can_bus("send", 0, 0, can_id, str)
    95. -- 等待目标板返回确认数据0x30
    96. -- 返回0x30表示发送成功
    97. -- 暂时用延迟实现
    98. delayms(30)
    99. bytes, bin = f_read(filepath, offset, 32) -- 继续读取数据
    100. offset = offset + bytes
    101. if(bytes ~= 0) then -- 读取不为0,打印发送的总字节数
    102. print("发送固件:", offset)
    103. end
    104. end
    105. -------------------------------------------------------
    106. -- 第5步:发送传输结束命令
    107. -------------------------------------------------------
    108. str_offset = string.format("%02d", 64 - 1)
    109. str= string.format("#".."%"..str_offset.."s", "A")
    110. can_bus("send", 0, 0, can_id, str)
    111. print("固件传输完成")
    112. -------------------------------------------------------
    113. -- end of file
    114. -------------------------------------------------------



    【目标板程序简单说明】

    最关键的就是串口程序处理:

    1. /*
    2. *********************************************************************************************************
    3. *
    4. * 模块名称 : CAN方式固件升级
    5. * 文件名称 : demo_canfd_update.c
    6. * 版 本 : V1.0
    7. * 说 明 : CAN方式固件升级
    8. *
    9. * 修改记录 :
    10. * 版本号 日期 作者 说明
    11. * V1.0 2022-06-15 Eric2013 正式发布
    12. *
    13. * Copyright (C), 2022-2030, 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url]
    14. *
    15. *********************************************************************************************************
    16. */
    17. #include "bsp.h"
    18. /*
    19. *********************************************************************************************************
    20. * 函数
    21. *********************************************************************************************************
    22. */
    23. /* 仅允许本文件内调用的函数声明 */
    24. static void JumpToApp(void);
    25. void can_Init(void);
    26. void can_DeInit(void);
    27. /*
    28. *********************************************************************************************************
    29. * 宏定义
    30. *********************************************************************************************************
    31. */
    32. #define AppAddr 0x08100000 /* APP地址 */
    33. /*
    34. *********************************************************************************************************
    35. * 变量
    36. *********************************************************************************************************
    37. */
    38. __IO uint32_t uwCRCValue;
    39. __IO uint32_t uwExpectedCRCValue;
    40. __IO uint32_t uwAppSize;
    41. uint8_t buf[1024];
    42. uint32_t RecCount = 0;
    43. uint32_t RecCount0 = 0;
    44. uint32_t RecSize = 0;
    45. uint8_t RecCplt = 0;
    46. uint32_t filesize = 0;
    47. /*
    48. *********************************************************************************************************
    49. * 函 数 名: DemoCANUpdate
    50. * 功能说明: CAN烧录
    51. * 形 参: 无
    52. * 返 回 值: 无
    53. *********************************************************************************************************
    54. */
    55. void DemoCANUpdate(void)
    56. {
    57. uint8_t cmd;
    58. uint32_t SectorCount = 0;
    59. uint32_t SectorRemain = 0;
    60. uint32_t i;
    61. uint32_t TotalSize = 0;
    62. uint8_t ucState;
    63. MSG_T msg;
    64. can_Init(); /* 初始化CAN */
    65. bsp_StartAutoTimer(0, 500); /* 启动1个500ms的自动重装的定时器 */
    66. while (1)
    67. {
    68. /* 判断定时器超时时间 */
    69. if (bsp_CheckTimer(0))
    70. {
    71. /* 每隔500ms 进来一次 */
    72. bsp_LedToggle(2);
    73. }
    74. if (bsp_GetMsg(&msg))
    75. {
    76. switch (msg.MsgCode)
    77. {
    78. case MSG_CAN1_RX: /* 接收到CAN设备的应答 */
    79. cmd = g_Can1RxData[0];
    80. printf("size = %d, cmd = %c\r\n",g_Can1RxHeader.DataLength>>16, cmd);
    81. /* 开始传输固件命令 **************/
    82. if(cmd == '$')
    83. {
    84. /* 接收够224个数据 */
    85. RecSize = g_Can1RxData[1];
    86. /* 编程内部Flash, */
    87. ucState = bsp_WriteCpuFlash((uint32_t)(AppAddr + TotalSize), (uint8_t *)&g_Can1RxData[2], RecSize);
    88. TotalSize += RecSize;
    89. printf("=====%d\r\n", TotalSize);
    90. /* 如果返回非0,表示编程失败 */
    91. if(ucState != 0)
    92. {
    93. /* 返回0x60,表示编程失败 */
    94. }
    95. /* 返回0x30,表示编程成功 */
    96. }
    97. /* 传输完成命令 **************/
    98. if(cmd == '#')
    99. {
    100. JumpToApp();
    101. }
    102. /* 接收固件大小命令 */
    103. if(cmd == '*')
    104. {
    105. filesize = g_Can1RxData[1] + (g_Can1RxData[2] << 8) + (g_Can1RxData[3] << 16) + (g_Can1RxData[4] << 24);
    106. uwAppSize = filesize;
    107. SectorCount = filesize/(128*1024);
    108. SectorRemain = filesize%(128*1024);
    109. printf("filesize = %d\r\n", filesize);
    110. for(i = 0; i < SectorCount; i++)
    111. {
    112. bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
    113. }
    114. if(SectorRemain)
    115. {
    116. bsp_EraseCpuFlash((uint32_t)(AppAddr + i*128*1024));
    117. }
    118. /* 返回0x30,表示擦除成功 */
    119. }
    120. break;
    121. }
    122. }
    123. }
    124. }
    125. /*
    126. *********************************************************************************************************
    127. * 函 数 名: JumpToApp
    128. * 功能说明: 跳转到应用JumpToApp
    129. * 形 参: 无
    130. * 返 回 值: 无
    131. *********************************************************************************************************
    132. */
    133. static void JumpToApp(void)
    134. {
    135. uint32_t i=0;
    136. void (*AppJump)(void); /* 声明一个函数指针 */
    137. /* 关闭全局中断 */
    138. DISABLE_INT();
    139. /* 设置所有时钟到默认状态,使用HSI时钟 */
    140. HAL_RCC_DeInit();
    141. /* 关闭滴答定时器,复位到默认值 */
    142. SysTick->CTRL = 0;
    143. SysTick->LOAD = 0;
    144. SysTick->VAL = 0;
    145. /* 关闭所有中断,清除所有中断挂起标志 */
    146. for (i = 0; i < 8; i++)
    147. {
    148. NVIC->ICER[i]=0xFFFFFFFF;
    149. NVIC->ICPR[i]=0xFFFFFFFF;
    150. }
    151. /* 使能全局中断 */
    152. ENABLE_INT();
    153. /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
    154. AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
    155. /* 设置主堆栈指针 */
    156. __set_MSP(*(uint32_t *)AppAddr);
    157. /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
    158. __set_CONTROL(0);
    159. /* 跳转到系统BootLoader */
    160. AppJump();
    161. /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
    162. while (1)
    163. {
    164. }
    165. }
    166. /*
    167. *********************************************************************************************************
    168. * 函 数 名: can_Init
    169. * 功能说明: 配置CAN硬件
    170. * 形 参: 无
    171. * 返 回 值: 无
    172. *********************************************************************************************************
    173. */
    174. void can_Init(void)
    175. {
    176. bsp_InitCan1();
    177. bsp_InitCan2();
    178. }
    179. /*
    180. *********************************************************************************************************
    181. * 函 数 名: can_DeInit
    182. * 功能说明: 退出CAN硬件硬质,恢复CPU相关的GPIO为缺省;关闭CAN中断
    183. * 形 参: 无
    184. * 返 回 值: 无
    185. *********************************************************************************************************
    186. */
    187. void can_DeInit(void)
    188. {
    189. bsp_DeInitCan1();
    190. bsp_DeInitCan2();
    191. }
    192. /***************************** 安富莱电子 [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!

  • 相关阅读:
    OccuSeg: Occupancy-aware 3D Instance Segmentation
    关于小程序 scroll
    面试时,公司的什么表现让你一看就知道不靠谱?
    E. Li Hua and Array
    【Java基础】Debug模式操作流程及案例:不死神兔、百钱百鸡
    room数据库的使用
    I/O模型之非阻塞IO
    生态系统服务——水源涵养水源涵养分布
    软考高项-计算题(3)
    java家政服务中心网站mysql
  • 原文地址:https://blog.csdn.net/Simon223/article/details/125940742