本篇讲述BootLoader下位机的开发。
刚到新公司第三天就接了一个项目,搞到现在才局部完成,更新比较慢了。
先上传源码比较实际,再介绍基本功能。
源码地址:/zixunimg/eeworldimg/download.csdn.net/download/u010875635/11692136
实际上搞定CAN通信和Flash读写,Bootloader下位机就没什么问题了。
注意一下Bootloader与App的分区划分。
Bootloader与App分别占用2个非分页区。
Bootloader: 0xC000-0xFFFF(实际到0xF7FF,保留一个sector给vector table)
Application: 0x4000-0x7FFF,加上其它分页区(转换成全局地址为0x7F4000-0x7FFFF)
Bootloader实际上核心逻辑没有什么东西,无非就是传输协议,数据重新组合,然后写进去,只不过数据组合的方式决定了刷写的速度。
MCU上电后,首先会进入Bootloader中,1s内没有收到刷写命令(如果App可以接收跳转,则时间不需要这么久,可直接从App跳到Bootloader进行刷写),就会跳到App。数据的CAN ID和命令的CAN ID分开。
本Bootloader采用按行传送数据,减少地址传送次数,以及数据和命令分开传送的方式,提高单位时间数据传送量,以加快刷写速度,在刷写结束后,做个简单校验(例如CRC校验,此处没有做,大家可以自行补充),然后在某个地方写Flag标识,开机启动时Bootloader会读取这个标识,然后判断App是否完好,若是完好,则会在超时后跳到App。
需要注意的是,跳转前要将使用的设备DeInit,例如CAN,否则App使用时可能会有问题。
核心逻辑代码如下(详细请参考源码):
void main(void)
{
McuDrivers_System_Init();
McuDrivers_GPIO_Init();
McuDrivers_CAN2_Init();
EnableInterrupts;
CAN_Send(1,g_Bootloader_EntryBootloaderReponse,8);
for(;;)
{
CAN_Tasks(); //can
Tick_Tasks();
//_FEED_COP(); /* feeds the dog */
} /* loop forever */
/* please make sure that you never leave main */
}
UINT32 countTick = 0;
UINT8 Tick_Tasks()
{
countTick++;
//每隔1000大约1ms
if(countTick==1000)
{
countTick=0;
return Time_Tasks();
}
return 1;
}
UINT32 countTimer=0;
UINT8 Time_Tasks()
{
countTimer++;
if(countTimer
{
if(countTimer%500==0)
McuDriver_GPIO_PB0_Toggle(); //blue led blink
}
else if(countTimer==(1000*g_GOTOAPP_TIMEOUT))
{
app_entry();
return 0;
}
if(countTimer>(1000*g_GOTOAPP_TIMEOUT*10))
countTimer=(1000*g_GOTOAPP_TIMEOUT)+1;
return 1;
}
Scm_CanStandData m_CAN_RxMsg; /* for CAN RX */
#pragma MESSAGE DISABLE C1420 //result of function call is ignore
//send can data
void CAN_Send(UINT8 isCmdType,UINT8 *datas,UINT8 length)
{
m_CAN_RxMsg.U32ID = isCmdType==1?SendCmdCANID:SendDataCANID;
m_CAN_RxMsg.DataType = 0; //data type
m_CAN_RxMsg.DataFormat = 1; //ext
m_CAN_RxMsg.DataLength = length;
memcpy(m_CAN_RxMsg.Datas,datas,length);
McuDrivers_CAN2_SendData(&m_CAN_RxMsg);
}
void Software_Wait(UINT16 milliSeconds)
{
UINT16 i,j;
for(i=0;i for(j=0;j<1000;j++) ; } //UINT32 g_ReceiveCount=0; UINT8 m_State = 0; #pragma MESSAGE DISABLE C2705//result of function call is ignore //Receive Can Data void CAN_Tasks() { Protocol_Bootloader_CmdType result; int reponse = 0; if(McuDrivers_CAN2_GetStateRX()) { if(McuDrivers_CAN2_ReadData(&m_CAN_RxMsg)==ERR_OK) { if(m_CAN_RxMsg.U32ID==ReceiveCmdCANID) //cmd id { result = Bootloader_DataParse_g(m_CAN_RxMsg.Datas,m_CAN_RxMsg.DataLength); switch (result) { case Reset: app_entry(); /*jump to app and should not back */ break; case FlashErase: if(m_State==0) { countTimer=(1000*g_GOTOAPP_TIMEOUT)+1; reponse = UserFlash_EraseIvtAndUserAppBlock_g(m_CAN_RxMsg.Datas,m_CAN_RxMsg.DataLength); switch(reponse) { case -1: g_Bootloader_EraseFlashReponse[1]=AddressChecksumError; break; case -2: g_Bootloader_EraseFlashReponse[1]= AddressOverRange; break; case -3: g_Bootloader_EraseFlashReponse[1]= EraseFailed; break; default: g_Bootloader_EraseFlashReponse[1]= CmdRunOK; UserFlash_ClearAppIndicate_g(APP_UPDATE_OK_GLOBAL_ADDR); //clear app flag McuDriver_GPIO_PB0_Set(); // led 0 off m_State = 1; break; } CAN_Send(1,g_Bootloader_EraseFlashReponse,8); } break; case SendAddress: if(m_State==1) { // g_ReceiveCount++; //if(g_ReceiveCount>=20063) // _asm(nop); reponse = UserFlash_AddrParse_g(m_CAN_RxMsg.Datas,m_CAN_RxMsg.DataLength); switch(reponse) { case -1: g_Bootloader_SendAddressReponse[1]=AddressChecksumError; break; case -2: g_Bootloader_SendAddressReponse[1]= DataChecksumError; break; default: g_Bootloader_SendAddressReponse[1]= CmdRunOK; break; } CAN_Send(1,g_Bootloader_SendAddressReponse,8); } break; case DataEnd: reponse = UserFlash_CheckLastLineChecksumAndWritten_g(); //write last line to flash switch(reponse)
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』