【飞思卡尔 MC9S12】BootLoader 下位机
本篇讲述BootLoader下位机的开发。
Bootloader上位机、下位机以及用户App 范例源码:https://gitee.com/beatfan/freescale_mc9s12xep100_-bootloader.git
实际上搞定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<(1000*g_GOTOAPP_TIMEOUT))
{
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<milliSeconds;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)
{
case -1:
g_Bootloader_DataProgramEndReponse[1]=DataChecksumError;
break;
case -2:
g_Bootloader_DataProgramEndReponse[1]= FlashProgramFailed;
break;
default:
g_Bootloader_DataProgramEndReponse[1]= CmdRunOK;
UserFlash_SetAppIndicate_g(APP_UPDATE_OK_GLOBAL_ADDR); //set app flag
McuDriver_GPIO_PB0_Set(); // led 0 off
break;
}
Software_Wait(100);
CAN_Send(1,g_Bootloader_DataProgramEndReponse,8);
app_entry(); /*jump to app and should not back */
break;
case CheckBootloader:
CAN_Send(1,g_Bootloader_CheckBootloaderReponse,8);
break;
default:
break;
}/*end if switch*/
}
else if(m_CAN_RxMsg.U32ID==ReceiveDataCANID) //cmd id
{
if(m_State==1)
{
//g_ReceiveCount++;
//if(g_ReceiveCount>=20063)
// _asm(nop);
UserFlash_DataParse_g(m_CAN_RxMsg.Datas,m_CAN_RxMsg.DataLength);
McuDriver_GPIO_PB2_Toggle(); //led 2 blink
CAN_Send(0,g_Bootloader_SendDataReponse,8);
}
}
}
}/*end of g_CAN0_BufferReceive_Flag==1 if*/
}