基于XCP(On CAN)协议的Bootloader升级方案
前言
本文展示了一种ECU设备的的升级方案。用户可以通过CAN网络通讯,实现的对ECU设备内部软件的升级。
此方案主要有以下特色:
1.功能全面:由于此方案使用了XCP协议栈,用户在不使用调试接口的情况下,即可实现对ECU内部的软件完成
升级、存储数据读写(通过a2l文件和工具可观测\改写C代码中声明的变量)、数据标定以及功能调试等。
2.代码标准化:此方案的软件使用了部分AUTOSAR架构中的标准模块,在网上拥有丰富的学习资源(例:
https://www.autosar.org/nc/document-search/)。
3.易移植:由于使用了AUTOSAR软件架构的标准模块,使得此方案中的代码可以很容易在其他项目中重复使用
(在STM32平台和TC27X平台已移植验证通过)。
实例中展示的是STM32F407平台下的源码,包括bootloader、和上位机程序。
上位机程序: https://download.csdn.net/download/weixin_38194877/20688243
Bootloader程序:https://download.csdn.net/download/weixin_38194877/20688267
一、ECU端设计
1.Flash分配
如下图,将MCU的Flash分为两个部分,一个存放bootloader程序(0x08000000–0x0800C000),另一个存放应用程序(0x0800C000–0x08080000),当MCU通过上电复位时默认的中断向量表的起始位置为0x08000004。上电复位后,程序首先从Bootloader程序的复位中断向量开始运行(即执行bootloader程序),在bootloader程序中,可以跳转至应用程序的复位中断向量位置去执行应用程序。在应用程序初始化阶段,需将中断向量表转移到应用程序所在的存储区域,否则在中断到来时,程序又会跳转至boot loader程序中。
2.软件架构层次图
由于boot loader程序功能比较简单,这里只用到了AUTOSAR软件架构中的几个模块,对于这些模块大家可以在 https://www.autosar.org/nc/document-search 查找如下文档:
AUTOSAR_SWS_DIODriver.pdf
AUTOSAR_SWS_PortDriver.pdf
AUTOSAR_SWS_FlsDriver.pdf
AUTOSAR_SWS_WdgDriver.pdf
...
USART模块不属于标准的AUTOSAR模块,这里主要用于串口输出调试信息。
下图为MCU端代码结构,可以下AUTOSAR标准文档中学习使用这些代码。
3.流程图
由于这里我们使用了XCP协议栈,这里可以很多复杂的操作。
4.源码
以下是一些关键的代码。
main.c
AppEntrFuncType AppEntrFunc;
uint32 MsCounter = 0;
uint8 AppProgramFlag = 0;
boolean LEDSt = FALSE;
Xcp_GetState_t Xcp_State;
Port_Init(Port_Config);
MUSART_Init();
Can_Init(Can_Config);
CanIf_Init(&CanIf_Config);
Xcp_Init(&Xcp_Config);
printf("Start Bootloader !\r\n");
Fls_Read(APP_FLASH_START_ADDR-1,&AppProgramFlag,1);
CanIf_SetControllerMode(0,CANIF_CS_STARTED);
CanIf_SetPduMode(0,CANIF_SET_ONLINE);
while(1)
{
if(1 == MsCounter%5)
{
Xcp_EventChannel(XcpConf_XcpEventChannel_XcpEventChannel_daq5ms);
}
if(2 == MsCounter%10)
{
Xcp_EventChannel(XcpConf_XcpEventChannel_XcpEventChannel_daq10ms);
}
if(3 == MsCounter%100)
{
Xcp_EventChannel(XcpConf_XcpEventChannel_XcpEventChannel_daq100ms);
}
if(4 == MsCounter%1000)
{
LEDSt = !LEDSt;
Dio_WriteChannel(Dio_LED1_Channel,LEDSt);
Dio_WriteChannel(Dio_LED2_Channel,LEDSt);
Dio_WriteChannel(Dio_LED3_Channel,LEDSt);
}
Xcp_MainFunction();
MsCounter++;
Delay(0xFFFFFF/2000);
Xcp_State = Xcp_GetState();
if((