硬汉嵌入式论坛

 找回密码
 立即注册
查看: 2944|回复: 11
收起左侧

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

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2022-7-9 11:23:47 | 显示全部楼层 |阅读模式
通过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
image.png

V7板子使用CANFD1,注意跳线帽:
image.png


【准备工作】

当前上位机还没有做专门的CANFD接口脱机烧录一键下载界面,需要手动将Lua文件和app固件存到TOOL的eMMC

1、H7-TOOL进入虚拟U盘

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

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

app.bin (50.03 KB)
canbootloader.lua (4.12 KB)

image.png

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


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

【在线方式操作说明】

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

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

image.png

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




【离线方式操作说明】

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

image.png

执行uartfirmware.lua小程序。

执行效果如下:

image.png

【Lua小程序简单说明】
注释非常详细:

[C] 纯文本查看 复制代码
-------------------------------------------------------
--   
--     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
-------------------------------------------------------



【目标板程序简单说明】
最关键的就是串口程序处理:

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
*        模块名称 : 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专题,启动,跳转配置和调试下载的各种用法
https://www.armbbs.cn/forum.php?mod=viewthread&tid=112792

基于NAND,eMMC,SD卡和U盘的BootLoader实战,带CRC完整性校验
https://www.armbbs.cn/forum.php?mod=viewthread&tid=113053

单片机BootLoader的AES加密实战,含上位机和下位机代码全开源
https://www.armbbs.cn/forum.php?mod=viewthread&tid=113361


评分

参与人数 2金币 +40 收起 理由
lqw13420106197 + 20 很给力!
missfox + 20 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-7-11 04:34:08 | 显示全部楼层
刚发布完毕周报,白天了更新帖子。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-7-12 03:44:29 | 显示全部楼层
更新完毕。
回复

使用道具 举报

23

主题

1403

回帖

1472

积分

至尊会员

积分
1472
发表于 2022-7-12 10:07:09 | 显示全部楼层
感谢分享,非常给力,这个功能急需
代码不规范,亲人两行泪!
回复

使用道具 举报

36

主题

2039

回帖

2147

积分

至尊会员

积分
2147
发表于 2022-7-12 11:54:24 | 显示全部楼层
经过测试,下面函数第3个参数字节个数
can_bus("open", 2, 20, 500000, 2000000)

与下面函数字符串个数要匹配
can_bus("send", 0, 0, 0x111, "12345678123456781234")
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2022-7-12 11:58:52 | 显示全部楼层
byccc 发表于 2022-7-12 11:54
经过测试,下面函数第3个参数字节个数
can_bus("open", 2, 20, 500000, 2000000)

是这样的,这个地方要匹配
回复

使用道具 举报

2

主题

14

回帖

20

积分

新手上路

积分
20
发表于 2023-10-18 10:05:10 | 显示全部楼层
--第1个参数
----open,close,send,recive
--第2个参数
----ID类型,0表示标准ID,1表示扩展ID
--第3个参数
----0数据帧,1遥控帧
--第4个参数
----字符串
can_bus("send", 0, 0, can_id, str)
请问这个函数recive模式的使用说明是怎样的,找了半天没有找到
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2023-10-18 10:06:51 | 显示全部楼层
StephenCui 发表于 2023-10-18 10:05
--第1个参数
----open,close,send,recive
--第2个参数

没有开放receive 的lua api给大家使用。

后续版本考虑开放。
回复

使用道具 举报

2

主题

14

回帖

20

积分

新手上路

积分
20
发表于 2023-10-18 10:17:11 | 显示全部楼层
eric2013 发表于 2023-10-18 10:06
没有开放receive 的lua api给大家使用。

后续版本考虑开放。

非常需要这个接口
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2024-1-2 21:23:32 来自手机 | 显示全部楼层
希望尽快尽早开放can接收接口对对对
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
 楼主| 发表于 2024-1-3 08:03:43 | 显示全部楼层
fly0315 发表于 2024-1-2 21:23
希望尽快尽早开放can接收接口对对对

好的,之前2.24就打算分享的。
回复

使用道具 举报

0

主题

4

回帖

4

积分

新手上路

积分
4
发表于 2024-1-3 09:40:40 | 显示全部楼层
eric2013 发表于 2024-1-3 08:03
好的,之前2.24就打算分享的。

硬汉哥真强!!!我正在做TI C2000芯片的在线升级工具,打算用H7tool+LUA做上位机,用到UART、CAN。就差LUA API for CAN receive了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-29 04:14 , Processed in 0.229461 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表