STM32F4的CAN升级方案 bootloader源代码,对应测试用app源代码,都是kei...
为上层软件提供硬件功能访问接口,是方案所有功能实现的基础。
STM32F4的CAN升级方案 bootloader源代码,对应测试用app源代码,都是keil工程,代码有备注,也有使用说明。 带对应上位机可执行文件。 上位机vs2013开发(默认exe,源代码需要额外拿)
一、方案功能架构总览
STM32F4 CAN在线升级方案是一套面向嵌入式设备远程固件维护的完整解决方案,核心功能围绕“上位机指令下发- CAN总线数据传输-下位机固件接收与更新”展开,涵盖系统引导控制、固件合法性校验、CAN通信交互、Flash存储管理四大核心模块。方案通过Bootloader引导程序、APP应用程序、上位机配置工具的协同工作,实现无需物理接触设备即可完成固件更新,适用于工业控制、汽车电子、智能设备等需要批量远程维护的场景。

STM32F4的CAN升级方案 bootloader源代码,对应测试用app源代码,都是keil工程,代码有备注,也有使用说明。 带对应上位机可执行文件。 上位机vs2013开发(默认exe,源代码需要额外拿)

从代码层面看,方案功能实现依赖三层结构:底层通过stm32f4xx.h提供硬件寄存器访问接口,中层通过Bootloader实现引导与升级控制,上层通过APP实现业务功能与升级响应,同时配合上位机配置文件完成通信参数适配,形成“硬件-软件-工具”的功能闭环。
二、底层硬件功能支撑(stm32f4xx.h)
stm32f4xx.h作为STM32F4系列微控制器的核心外设头文件,并非直接实现业务功能,而是通过寄存器定义、位操作宏、外设结构体为上层软件提供硬件功能访问接口,是方案所有功能实现的基础。其核心功能支撑集中在CAN通信、Flash存储、中断控制三大模块,具体功能与代码映射如下:
(一)CAN通信功能支撑
CAN总线是方案的数据传输核心,stm32f4xx.h通过CAN_TypeDef结构体完整定义CAN控制器的寄存器组,实现“数据发送-接收-过滤-状态监控”的硬件功能封装:
1. 通信模式控制功能
代码通过CAN_MCR(主控制寄存器)定义CAN控制器的工作模式,支持初始化、正常、睡眠等模式切换,为上位机与下位机的通信建立提供基础:
typedef struct
{
__IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */
// 其他寄存器...
} CAN_TypeDef;
// 位操作宏定义
#define CAN_MCR_INRQ ((uint16_t)0x0001) // 初始化请求位
#define CAN_MCR_SLEEP ((uint16_t)0x0002) // 睡眠模式请求位
#define CAN_MCR_ABOM ((uint16_t)0x0040) // 自动总线离线管理位
- 功能作用:Bootloader初始化CAN时,需先置位
CANMCRINRQ进入初始化模式,配置波特率、过滤器后,清除该位进入正常模式;CANMCRABOM位确保CAN总线异常(如总线离线)时自动恢复,保障升级过程中通信稳定性。
2. 数据发送功能
通过CANTxMailBoxTypeDef结构体定义3个独立发送邮箱,支持多帧数据并发发送,满足固件分片传输的需求:
typedef struct
{
__IO uint32_t TIR; /*!< CAN TX mailbox identifier register */
__IO uint32_t TDTR; /*!< CAN mailbox data length control register */
__IO uint32_t TDLR; /*!< CAN mailbox data low register */
__IO uint32_t TDHR; /*!< CAN mailbox data high register */
} CAN_TxMailBox_TypeDef;
typedef struct
{
// 其他寄存器...
CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< 3个发送邮箱,地址偏移0x180-0x1AC */
// 其他寄存器...
} CAN_TypeDef;
- 功能作用:上位机发送固件数据时,下位机(Bootloader/APP)通过
TDTR设置数据长度(DLC),TDLR/TDHR存储4字节数据(共8字节),TIR设置帧ID(标准帧/扩展帧),实现CAN帧的完整构造与发送;3个邮箱支持多帧数据排队发送,避免数据阻塞。
3. 数据接收与过滤功能
通过CANFIFOMailBoxTypeDef(接收FIFO)和CANFilterRegisterTypeDef(过滤器)实现“精准接收-冗余过滤”功能,确保仅接收目标设备的升级数据:
// 接收FIFO结构体
typedef struct
{
__IO uint32_t RIR; /*!< 接收帧ID寄存器 */
__IO uint32_t RDTR; /*!< 接收数据长度寄存器 */
__IO uint32_t RDLR; /*!< 接收数据低寄存器 */
__IO uint32_t RDHR; /*!< 接收数据高寄存器 */
} CAN_FIFOMailBox_TypeDef;
// 过滤器结构体
typedef struct
{
__IO uint32_t FR1; /*!< 过滤器寄存器1 */
__IO uint32_t FR2; /*!< 过滤器寄存器2 */
} CAN_FilterRegister_TypeDef;
typedef struct
{
// 其他寄存器...
CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< 2个接收FIFO */
CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< 28个过滤器 */
// 其他寄存器...
} CAN_TypeDef;
- 功能作用:过滤器通过
FR1/FR2设置过滤ID和掩码,仅允许匹配ID的CAN帧进入接收FIFO,避免无关数据干扰升级流程;接收FIFO存储收到的数据帧,供中断服务函数或轮询函数读取解析,实现“精准接收”功能。
(二)Flash存储功能支撑
Flash是固件存储的载体,stm32f4xx.h通过FLASH_TypeDef结构体定义Flash的控制与状态寄存器,支持“扇区擦除-数据写入-操作保护”功能,为固件存储与更新提供硬件接口:
typedef struct
{
__IO uint32_t ACR; /*!< Flash访问控制寄存器 */
__IO uint32_t KEYR; /*!< Flash密钥寄存器 */
__IO uint32_t OPTKEYR; /*!< Flash选项密钥寄存器 */
__IO uint32_t SR; /*!< Flash状态寄存器 */
__IO uint32_t CR; /*!< Flash控制寄存器 */
__IO uint32_t OPTCR; /*!< Flash选项控制寄存器 */
} FLASH_TypeDef;
// 位操作宏定义
#define FLASH_CR_PG ((uint32_t)0x00000001) // 编程模式使能
#define FLASH_CR_SER ((uint32_t)0x00000002) // 扇区擦除使能
#define FLASH_CR_SNB ((uint32_t)0x0000003C) // 扇区编号选择
#define FLASH_CR_STRT ((uint32_t)0x00010000) // 操作开始触发
#define FLASH_SR_EOP ((uint32_t)0x00000001) // 操作完成标志
#define FLASH_SR_BSY ((uint32_t)0x00010000) // 忙状态标志
- 功能作用:
1. 解锁保护:Flash默认处于写保护状态,需通过KEYR写入特定密钥(0x45670123、0xCDEF89AB)解锁,防止误操作,代码中Bootloader和APP的Flash写入前均需执行此步骤;
2. 扇区擦除:升级前需擦除APP所在扇区,通过FLASHCRSER使能擦除模式,FLASHCRSNB选择扇区,FLASHCRSTRT触发擦除,FLASHSREOP判断擦除完成;
3. 数据写入:固件数据通过FLASHCRPG使能编程模式,按32位/16位写入Flash,FLASHSRBSY判断Flash是否忙,避免数据写入冲突。
(三)中断控制功能支撑
CAN通信的实时响应依赖中断机制,stm32f4xx.h通过IRQn_Type枚举定义CAN相关中断向量,支持“接收中断-发送中断-错误中断”的快速响应:
typedef enum IRQn
{
// 其他中断...
CAN1_TX_IRQn = 19, /*!< CAN1发送中断 */
CAN1_RX0_IRQn = 20, /*!< CAN1 FIFO0接收中断 */
CAN1_RX1_IRQn = 21, /*!< CAN1 FIFO1接收中断 */
CAN1_SCE_IRQn = 22, /*!< CAN1状态变化中断 */
// 其他中断...
} IRQn_Type;
- 功能作用:Bootloader和APP中均需使能
CAN1RX0IRQn(FIFO0接收中断),当CAN总线收到数据时,硬件自动触发中断,中断服务函数立即读取数据并解析,确保升级指令和固件数据的实时处理,避免轮询导致的延迟。
三、Bootloader核心功能实现
Bootloader是方案的“引导与升级中枢”,核心功能包括系统上电引导、APP合法性校验、升级模式控制、固件接收与写入,所有功能通过代码逻辑的有序执行,确保系统在“正常运行APP”与“固件升级”两种模式间稳定切换。
(一)上电引导功能
上电引导是Bootloader的首要功能,通过“外设初始化-标志位校验-APP跳转”的逻辑流程,决定系统上电后的运行路径,代码功能映射如下:
1. 核心代码实现
#define APP_EXE_FLAG_ADDR ((uint32_t)0x08007800) // APP合法性标志位地址
#define APP_START_ADDR ((uint32_t)0x08008000) // APP起始地址
void Bootloader_Main(void)
{
// 1. 初始化外设:CAN(通信)、Flash(存储)、GPIO(硬件引脚)
CAN_Init();
Flash_Init();
GPIO_Init();
// 2. 读取APP合法性标志位,判断是否存在合法APP
uint32_t app_flag = *(volatile uint32_t*)APP_EXE_FLAG_ADDR;
if(app_flag == 0x78564312) // 标志位为0x78564312表示APP合法
{
// 3. 校验APP首地址(栈指针)合法性:栈指针需在SRAM范围内(0x20000000-0x2001FFFF)
uint32_t app_stack_ptr = *(volatile uint32_t*)APP_START_ADDR;
if((app_stack_ptr & 0x2FFE0000) == 0x20000000)
{
// 4. 跳转至APP:APP入口地址为APP_START_ADDR + 4(复位向量表中,首地址为栈指针,次地址为入口)
void (*app_entry)(void) = (void (*)(void))(*(volatile uint32_t*)(APP_START_ADDR + 4));
app_entry(); // 函数指针调用,实现PC寄存器跳转
}
}
// 5. 无合法APP或校验失败,进入升级模式,等待上位机指令
Bootloader_Enter_Upgrade_Mode();
}
2. 功能细节解析
- 外设初始化:
CANInit()配置CAN通信参数(波特率、过滤器、中断),确保与上位机通信正常;FlashInit()初始化Flash操作时序,为后续标志位读取和固件写入做准备; - 标志位校验:
APPEXEFLAG_ADDR是Bootloader与APP的“通信暗号”,APP合法时该地址值为0x78564312,否则为擦除后的0xFFFFFFFF或随机值,此校验确保系统不会跳转到损坏或非法的APP; - APP跳转:通过函数指针将PC寄存器设置为APP入口地址(
APPSTARTADDR + 4),实现从Bootloader到APP的无缝切换,且跳转后Bootloader代码不再占用系统资源。
(二)APP合法性校验功能
APP合法性校验是系统稳定运行的关键保障,避免因APP损坏或地址错误导致系统崩溃,校验逻辑包含标志位校验和栈指针校验两层:
1. 标志位校验
- 功能逻辑:
APPEXEFLAG_ADDR地址由APP在首次运行时写入0x78564312,Bootloader上电时读取该值,若匹配则判定APP存在且合法;若不匹配(如升级后未写入、APP损坏),则拒绝跳转至APP; - 代码作用:防止系统跳转到空白区域或损坏的APP代码,避免HardFault等异常。
2. 栈指针校验
- 功能逻辑:STM32固件的复位向量表首地址存储栈指针(需在SRAM地址范围
0x20000000-0x2001FFFF),次地址存储入口地址,Bootloader通过校验栈指针是否在合法范围,进一步确认APP代码未被篡改; - 代码作用:即使标志位被意外修改,栈指针校验仍能拦截非法APP,双重保障系统安全。
(三)升级模式控制功能
当无合法APP或收到上位机升级指令时,Bootloader进入升级模式,核心功能包括“升级指令解析-扇区擦除-固件接收-写入Flash-升级完成复位”,代码功能映射如下:
1. 升级模式入口代码
void Bootloader_Enter_Upgrade_Mode(void)
{
uint8_t can_rx_buf[8] = {0}; // CAN接收缓冲区(最大8字节)
uint32_t flash_write_addr = APP_START_ADDR; // Flash写入起始地址(APP地址)
uint8_t upgrade_state = 0; // 升级状态:0-等待指令,1-接收数据,2-升级完成
while(1)
{
// 等待CAN接收数据(通过中断或轮询,此处以轮询为例)
if(CAN_Receive_Data(CAN1, CAN_RX_FIFO0, can_rx_buf) == SUCCESS)
{
// 解析CAN数据:首字节为指令类型
switch(can_rx_buf[0])
{
case 0x01: // 指令1:开始升级(擦除APP扇区)
upgrade_state = 1;
Flash_Erase_Sector(FLASH_Sector_6); // APP存储在扇区6,需先擦除
CAN_Send_Ack(0x01); // 发送擦除完成应答
break;
case 0x02: // 指令2:接收固件数据(数据长度为can_rx_buf[1])
if(upgrade_state == 1)
{
// 解锁Flash并写入数据(按32位写入,适配Flash编程规范)
Flash_Unlock();
for(uint8_t i=0; i<can_rx_buf[1]; i+=4)
{
uint32_t write_data = *(uint32_t*)(can_rx_buf + 2 + i);
FLASH_ProgramWord(flash_write_addr, write_data);
flash_write_addr += 4;
}
Flash_Lock();
CAN_Send_Ack(0x02); // 发送数据接收完成应答
}
break;
case 0x03: // 指令3:升级完成(写入标志位并复位)
upgrade_state = 2;
// 写入APP合法标志位
Flash_Unlock();
FLASH_ProgramWord(APP_EXE_FLAG_ADDR, 0x78564312);
Flash_Lock();
CAN_Send_Ack(0x03); // 发送升级完成应答
NVIC_SystemReset(); // 复位系统,下次上电运行新APP
break;
default:
// 未知指令,发送错误应答
CAN_Send_Ack(0xFF);
break;
}
}
}
}
2. 功能细节解析
- 升级指令解析:CAN接收数据的首字节定义为指令类型(0x01-开始升级、0x02-固件数据、0x03-升级完成),通过switch-case逻辑区分指令,确保流程有序;
- Flash扇区擦除:APP存储在Flash扇区6(地址
0x08008000-0x0800FFFF),升级前需擦除该扇区,避免旧数据与新数据冲突; - 固件数据写入:固件数据按32位(4字节)写入Flash,符合STM32F4 Flash的编程规范(仅支持32位/16位写入),同时通过
FlashUnlock()/FlashLock()确保操作安全; - 升级完成复位:写入标志位后调用
NVIC_SystemReset()复位系统,复位后Bootloader校验标志位为0x78564312,直接跳转至新APP,完成升级闭环。
(四)CAN通信应答功能
为确保上位机准确掌握升级进度,Bootloader在每个升级步骤后需发送应答报文,代码中通过CANSendAck()函数实现,功能如下:
void CAN_Send_Ack(uint8_t ack_type)
{
CAN_TxHeaderTypeDef tx_header;
uint8_t tx_data[1] = {ack_type};
// 配置应答报文:扩展帧ID(匹配上位机配置),数据长度1字节
tx_header.StdId = 0x00;
tx_header.ExtId = 0x0134; // 与APP地址一致,便于上位机识别设备
tx_header.RTR = CAN_RTR_DATA;
tx_header.IDE = CAN_ID_EXT;
tx_header.DLC = 1;
tx_header.TransmitGlobalTime = DISABLE;
// 发送应答数据
CAN_AddTxMessage(CAN1, &tx_header, tx_data, NULL);
}
- 功能作用:应答报文携带升级状态(0x01-擦除完成、0x02-数据接收完成、0x03-升级完成、0xFF-错误),上位机通过接收应答判断下一步操作,避免数据丢失或流程混乱。
四、APP应用程序功能实现
APP作为系统的业务功能载体,除实现特定业务逻辑外,还需配合Bootloader完成“升级响应”功能,核心功能包括APP合法性标志位初始化、升级指令接收与响应、CAN地址配置,确保系统能从“业务运行”模式切换到“升级”模式。
(一)APP合法性标志位初始化功能
APP首次运行时,需向APPEXEFLAG_ADDR写入合法标志位,供Bootloader下次上电时识别,代码功能映射如下:
void APP_Init(void)
{
// 1. 初始化业务相关外设(如USART、LCD、传感器等)
USART_Init();
LCD_Init();
Sensor_Init();
// 2. 初始化CAN通信(用于接收升级指令)
CAN_Init();
// 3. 检查并写入APP合法性标志位
uint32_t app_flag = *(volatile uint32_t*)APP_EXE_FLAG_ADDR;
if(app_flag == 0xFFFFFFFF) // 标志位为擦除状态(首次运行或升级后)
{
Flash_Unlock();
FLASH_ProgramWord(APP_EXE_FLAG_ADDR, 0x78564312); // 写入合法标志
Flash_Lock();
}
// 4. 启动业务逻辑
APP_Business_Start();
}
- 功能作用:APP首次运行或升级后,
APPEXEFLAG_ADDR地址为擦除后的0xFFFFFFFF,写入0x78564312后,Bootloader下次上电时会判定APP合法并跳转,确保系统正常运行。
(二)升级指令接收与响应功能
当上位机需要升级APP时,会发送升级指令,APP需接收指令并触发系统进入升级模式,代码功能映射如下:
1. CAN接收中断服务函数(核心响应逻辑)
void CAN1_RX0_IRQHandler(void)
{
CAN_RxHeaderTypeDef rx_header;
uint8_t rx_data[8] = {0};
// 读取CAN接收数据
if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK)
{
// 校验指令:扩展帧ID为0x0134(设备地址),首字节为0x03(升级指令)
if(rx_header.ExtId == 0x0134 && rx_data[0] == 0x03)
{
// 擦除APP合法性标志位,使Bootloader下次上电进入升级模式
Flash_Unlock();
FLASH_Erase_Page(APP_EXE_FLAG_ADDR); // 擦除标志位所在页
Flash_Lock();
// 复位系统,触发Bootloader引导
NVIC_SystemReset();
}
}
// 清除中断标志
HAL_CAN_ClearRxFifoOverrunFlag(&hcan1, CAN_RX_FIFO0);
}
2. 功能细节解析
- 指令校验:通过扩展帧ID(0x0134)区分设备,避免多设备场景下指令误响应;通过首字节(0x03)确认升级指令,防止业务数据误触发升级;
- 标志位擦除:擦除
APPEXEFLAG_ADDR后,系统复位时Bootloader读取标志位为0xFFFFFFFF,判定无合法APP,进入升级模式; - 系统复位:通过
NVIC_SystemReset()立即复位,快速切换到Bootloader,减少业务中断时间。
(三)CAN地址配置功能
为支持多设备同时升级,APP需定义唯一的CAN地址(扩展帧ID),代码通过ReadCANAddress()函数实现地址配置:
uint32_t Read_CAN_Address(void)
{
uint32_t device_addr = 0x0134; // 默认地址
// 可选:基于芯片唯一ID生成地址(避免多设备地址冲突)
uint32_t chip_id1 = *(volatile uint32_t*)0x1FFF7A10;
uint32_t chip_id2 = *(volatile uint32_t*)0x1FFF7A14;
uint32_t chip_id3 = *(volatile uint32_t*)0x1FFF7A18;
device_addr = (chip_id1 ^ chip_id2 ^ chip_id3) & 0xFFFF; // 基于唯一ID生成地址
return device_addr;
}
- 功能作用:每个设备的CAN地址唯一,上位机通过不同地址向目标设备发送升级指令,实现多设备批量升级,避免指令广播导致的误升级。
五、上位机配置工具功能解析
上位机虽未提供完整源码,但通过candtu.ini和kerneldll.ini两个配置文件,实现“CAN通信参数适配”和“硬件驱动兼容”功能,为下位机升级提供工具支撑。
(一)CAN通信参数配置功能(candtu.ini)
该文件定义CAN总线的通信参数,确保上位机与下位机(Bootloader/APP)的通信参数一致,功能映射如下:
[CAN0]
BpsBRP=5 ; 波特率预分频系数
BpsSWJ=0 ; 同步跳转宽度(0-1tq)
BpsSeg1=3 ; 时间段1(3tq)
BpsSeg2=1 ; 时间段2(1tq)
BpsSmp=0 ; 采样模式(0-1次采样)
FltCNT=1 ; 过滤器数量
FltFmat=0 ; 过滤器模式(0-掩码模式)
FltM0=-1 ; 过滤器ID(-1表示不过滤)
FltM1=0 ; 过滤器掩码
Mode=128 ; 工作模式(128-扩展帧)
UseRes=1 ; 启用保留位
[CAN1]
BpsBRP=2 ; CAN1波特率预分频
BpsSeg1=3
BpsSeg2=1
; 其他参数与CAN0一致
[GEN]
CfgType=2 ; 配置类型
NChan=2 ; 通道数量
- 功能作用:
1. 波特率匹配:波特率计算公式为APB1时钟 / ((BRP) (1 + Seg1 + Seg2 + SWJ)),STM32F4 APB1时钟为42MHz,CAN0波特率为42MHz / (5(1+3+1+0)) = 1.68MHz,需与Bootloader/APP的CAN波特率配置一致;
2. 帧格式匹配:Mode=128启用扩展帧,与下位机的扩展帧ID配置(0x0134)匹配,确保数据正常接收;
3. 过滤配置:FltM0=-1表示不启用过滤器,接收所有设备的CAN帧,便于上位机批量管理多设备。
(二)CAN硬件驱动兼容功能(kerneldll.ini)
该文件列出上位机支持的CAN硬件驱动,实现“多硬件适配”功能,代码功能映射如下:
[KERNELDLL]
COUNT=40 ; 支持的驱动数量
1=PCI51XXE.dll ; PCI接口CAN卡驱动
2=PCI9810.dll ; 另一种PCI CAN卡驱动
3=USBCAN.dll ; USB-CAN盒驱动(如周立功USBCAN-II)
4=USBCAN.dll ; 重复驱动,确保兼容性
...
37=CANDTU.dll ; 国产CAN盒驱动
38=zpcfd.dll ; 其他兼容驱动
...
- 功能作用:上位机启动时自动加载列表中的驱动,支持PCI CAN卡、USB CAN盒等多种硬件,用户更换CAN硬件时无需修改上位机代码,仅需确保驱动在列表中,降低硬件选型限制。
六、方案功能闭环与应用场景
(一)功能闭环流程
STM32F4 CAN在线升级方案的功能通过以下流程形成闭环:
- 上电引导:系统上电→Bootloader运行→校验APP标志位→合法则跳转APP,否则进入升级模式;
- 正常运行:APP运行→初始化标志位→接收业务数据→接收升级指令则擦除标志位并复位;
- 固件升级:上位机发送升级指令→Bootloader接收并擦除Flash→上位机发送固件数据→Bootloader写入Flash→升级完成后复位→新APP运行。
(二)典型应用场景
- 工业控制设备:工厂中的PLC、传感器节点,通过CAN总线实现批量固件升级,无需现场拆机;
- 汽车电子设备:车载ECU(发动机控制器、车身控制器),通过CAN总线远程更新功能固件,提升维护效率;
- 智能硬件设备:智能家居网关、物联网传感器,通过CAN总线(或CAN转以太网)实现远程固件维护,降低售后成本。
七、功能实现注意事项
- 地址分配:
APPEXEFLAGADDR和APPSTART_ADDR需根据STM32F4 Flash扇区大小合理分配,避免与Bootloader重叠(建议Bootloader占用前3个扇区,APP从扇区6开始); - CAN参数匹配:上位机与下位机的波特率、帧格式(标准帧/扩展帧)、ID必须一致,否则通信失败;
- Flash操作安全:Flash擦除/写入时需避免断电,建议在升级前提示用户确保设备供电稳定,同时在代码中增加操作超时检测;
- 多设备区分:实际应用中需基于芯片唯一ID生成CAN地址,避免多设备地址冲突,确保升级指令精准下发。
通过以上功能解析可见,STM32F4 CAN在线升级方案的代码功能与业务需求高度匹配,从底层硬件接口到上层应用响应,形成完整的功能链条,既确保了系统的稳定性和安全性,又为用户提供了灵活的适配空间,是嵌入式设备远程维护的理想解决方案。
更多推荐
所有评论(0)