AN2295 bootloader文档解析
AN2295提供了基于8-bit MCU、Coldfire、 Kinetis版本的boot loader代码,开发者可根据自己所选MCU的型号,选择对应的版本。由于在同一版本的boot loader代码中,为了适用于同一类型但不同系列的MCU,所以就定义了很多变量以作不同系列MCU的选择之用,但这样会导致bootloader代码的复杂程度递增,从而增加分析的难度。 所以出于上述的原因,特地选择FRDM-KE02的boot loader例程,其可为作为AN2295 bootloader代码的“简装版”,来介绍boot loader例程的工作原理及流程。 Ø 主程序代码说明 int main(void)
{
uint32_t uiNullCounter = 0;
uint32_t uiRepeatCount = 0;
FC_Init();
for(;;) {
if( !FC_Communication() )
{
if( g_ucFC_State == FC_STATE_NULL )
{
uiNullCounter ++;
if( uiNullCounter > 0xffff )
{
uiNullCounter = 0;
uiRepeatCount ++;
UART_putchar(TERM_PORT,0xfc);
}
if( uiRepeatCount > CONNECT_OVER_TIME )
{
#ifdef FLASH_LOCATION
SCB_VTOR = RELOCATION_VERTOR_ADDR;
JumpToUserApplication(RELOCATION_VERTOR_ADDR);
#endif
}
}
}
}
return 0;
}
Ø FC_Init函数
void FC_Init( void )
{
Flash_Init(); //初始化Flash时钟
m_pRecFrame = (uint8_t *)&m_RecFrame;
g_ucFC_State = FC_STATE_NULL;
m_uiRecCount = 0; //初始化各变量值
}
Ø FC_ Communication函数 unsigned char FC_Communication( void )
{
uint8_t uiReadData,i;
uint8_t *pAddress;
ADDRESS_TYPE * pTempAddress;
// 判断UART有无收到数据
if(UART_S1_RDRF_MASK != UART_getchar_present(TERM_PORT))
{
return 0;
}
// 读取UART收到的数据
uiReadData = UART_getchar(TERM_PORT);
switch( g_ucFC_State )
{
case FC_STATE_NULL:
{
if( uiReadData == FC_CMD_ACK ) // FC_CMD_ADK即为0xFC
{
//由于KE02波特率设置精准,所以例程中无MCU与PC波特率同步校准函数
UART_putchar( TERM_PORT,0xfc );
g_ucFC_State = FC_STATE_WORKING; // 进入接受命令操作状态
}
else
{
return 0;
}
}
break;
case FC_STATE_WORKING:
{
switch( uiReadData )
{
// Ident指令(0x49),发送boot loader的相关属性信息
case FC_CMD_IDENT:
{
UART_putchar( TERM_PORT,m_MCU_Info.Version);
UART_putchar( TERM_PORT,m_MCU_Info.Sdid>>8);
UART_putchar( TERM_PORT,m_MCU_Info.Sdid);
pTempAddress=(ADDRESS_TYPE *)&m_MCU_Info.BlocksCnt;
for(i=0;i<7;i++)
{
UART_putchar( TERM_PORT,pTempAddress[i].Bytes.hh);
UART_putchar( TERM_PORT,pTempAddress[i].Bytes.hl);
UART_putchar( TERM_PORT,pTempAddress[i].Bytes.lh);
UART_putchar( TERM_PORT,pTempAddress[i].Bytes.ll);
}
i = 0;
do
{
UART_putchar( TERM_PORT,m_MCU_Info.IdString[i]);
}while(m_MCU_Info.IdString[i++]);
}
break;
// Erase指令(0x45),进入Erase Flash 操作
case FC_CMD_ERASE:
{
g_ucFC_State = FC_STATE_EREASE;
}
break;
// Write指令(0x57),进入Write Flash操作
case FC_CMD_WRITE:
{
g_ucFC_State = FC_STATE_WRITE_ADDRESS;
}
break;
//Read指令(0x52),进入Read Flash 操作
case FC_CMD_READ:
{
g_ucFC_State = FC_STATE_READ;
}
break;
//Quit指令(0x51),进入Quit 操作
case FC_CMD_QUIT:
{
//中断向量重定位
SCB_VTOR = RELOCATION_VERTOR_ADDR;
//跳转到User application
JumpToUserApplication(RELOCATION_VERTOR_ADDR);
}
break;
default:
break;
}
m_uiRecCount = 0;
}
break;
// Erase flash操作中
case FC_STATE_EREASE:
{
m_pRecFrame[m_uiRecCount++] = uiReadData;
if( m_uiRecCount >= sizeof(uint32_t) )
{
//地址字节校正
LONG_Convert(&m_RecFrame.uiAddress);
//判断Erase flash操作是否成功
if(!Flash_EraseSector(m_RecFrame.uiAddress))
{
UART_putchar( TERM_PORT,FC_CMD_ACK );
}
else
{
UART_putchar( TERM_PORT,FC_CMD_NACK );
}
g_ucFC_State = FC_STATE_WORKING;
}
}
break;
// 接受Write Flash操作的起始地址
case FC_STATE_WRITE_ADDRESS:
{
m_pRecFrame[m_uiRecCount++] = uiReadData;
if( m_uiRecCount >= sizeof(uint32_t) )
{
g_ucFC_State = FC_STATE_WRITE_LEN;
}
}
break;
// 接受Write Flash操作的字节个数
case FC_STATE_WRITE_LEN:
{
m_pRecFrame[m_uiRecCount++] = uiReadData;
g_ucFC_State = FC_STATE_WRITE_DATA;
}
break;
// 接受Write Flash操作的数据
case FC_STATE_WRITE_DATA:
{
m_pRecFrame[m_uiRecCount++] = uiReadData;
if( m_uiRecCount > (m_RecFrame.Length + sizeof(uint32_t) ))
{
LONG_Convert(&m_RecFrame.uiAddress);
Memcpy_Byte((uint8_t*)&m_ucDataBuff[0],(uint8_t*)&m_RecFrame.DataBuff[0],
m_RecFrame.Length);
uiNumberCount ++;
if( !Flash_Program(m_RecFrame.uiAddress,
(uint8_t *)&m_ucDataBuff[0],m_RecFrame.Length) )
{
UART_putchar( TERM_PORT,FC_CMD_ACK );
}
else
{
UART_putchar( TERM_PORT,FC_CMD_NACK );
}
g_ucFC_State = FC_STATE_WORKING;
}
}
break;
//Read Flash操作
case FC_STATE_READ:
{
m_pRecFrame[m_uiRecCount++] = uiReadData;
if( m_uiRecCount > sizeof(uint32_t) )
{
LONG_Convert(&m_RecFrame.uiAddress);
pAddress = (uint8_t *)m_RecFrame.uiAddress;
for( i=0;i<m_RecFrame.Length;i++)
{
UART_putchar( TERM_PORT,pAddress[i] );
}
g_ucFC_State = FC_STATE_WORKING;
}
}
break;
default:
break;
}
return 1;
}
Boot loader程序流程图 boot loader例程程序流程图如下图所示。
文档下载:
AN2295—Developer’s Serial Bootloader 解析(二).pdf
(457.14 KB)
FRDM-KE02例程包:
|