Bootloader下位机及用户APP范例直接下载:
https://download.csdn.net/download/u010875635/10882172
此下位机开发通讯采用CAN,所有Hex文件解析工作在上位机,下位机尽可能避免复杂操作,以加快烧录速度。
使用的为NXP DEVKIT-MPC5744P开发板。
为保证烧录过程不出现错误,上下位机采用一问一答模式,上位机发送一帧数据后,下位机接收处理完毕再回馈给上位机,上位机再决定下一步动作。
核心代码逻辑部分,将命令分成EntryBootloader, Reset, Data, DataEnd, CheckBootloader, Erase, ERR几个部分。
烧录时会先检查是否处于Bootloader,然后执行擦写操作(擦写地址范围由上位机发送),再发送数据(地址+数据为一帧),最后发送结束命令。由于Flash编程最小单位为64bits,所以为防止出现奇数个数据,最后结束检查必不可少。
void CAN_Tasks()
{
// uint32_t iflag = CAN_0.IFLAG1.R;
if(CAN_0.IFLAG1.B.BUF6I==1) /*is new CAN data received*/
{
CAN_RxMsg = CAN0_ReceiveMsg(MB6);
//CAN_0.IFLAG1.B.BUF6I=0;
AfterBootloader_CmdType result = Bootloader_DataParse_g(CAN_RxMsg.Frame_Data,CAN_RxMsg.Frame_Length);
switch (result)
{
case EntryBootloader:
break;
case Reset:
bootloader_entry(); /*jump to app and should not back */
break;
case Data:
UserFlash_DataParseAddrData(CAN_RxMsg.Frame_Data,CAN_RxMsg.Frame_Length);
SIUL2.GPDO[LED_R].B.PDO ^= 1; //red led blink
Load_ReponseToUpMachine(g_Bootloader_DataReponse,8);
// g_ReceiveCount++;
break;
case DataEnd:
UserFlash_LastIsFull64Bits_g();
SIUL2.GPDO[LED_R].B.PDO = 1; //red off
SIUL2.GPDO[LED_G].B.PDO = 0; //green on
SIUL2.GPDO[LED_B].B.PDO = 1; // blue off
Load_ReponseToUpMachine(g_Bootloader_DataProgramEndReponse,8);
app_entry(); /*jump to app and should not back */
break;
case CheckBootloader:
Load_ReponseToUpMachine(g_Bootloader_CheckBootloaderReponse,8);
break;
case Erase:
countTimer=(1000*g_GOTOAPP_TIMEOUT)+1;
UserFlash_EraseIvtAndUserAppBlock_g(CAN_RxMsg.Frame_Data,CAN_RxMsg.Frame_Length);
SIUL2.GPDO[LED_R].B.PDO = 1; //red off
SIUL2.GPDO[LED_G].B.PDO = 1; //green off
SIUL2.GPDO[LED_B].B.PDO = 1; // blue off
Load_ReponseToUpMachine(g_Bootloader_EraseFlashReponse,8);
break;
default:
break;
}/*end if switch*/
}
}
//每帧CAN数据类型解析
AfterBootloader_CmdType Bootloader_DataParse_g(uint8_t *data, uint8_t dataLength)
{
uint8_t result=0;
if(dataLength!=8)
return 0xff;
//第一个字节为数据类型
switch(data[0])
{
case EntryBootloader:
result = EntryBootloader;
break;
case Reset:
result = Reset;
break;
case Data:
result = Data;
break;
case DataEnd:
result = DataEnd;
break;
case CheckBootloader:
result = CheckBootloader;
break;
case Erase:
result = Erase;
break;
default:return 0xff;
}
return result;
}
Flash焼写逻辑(注意,由于CAN长度为8字节,而32位地址已经占用4字节,Flash地址从0x800000开始,所以所有地址减去0x800000,3字节即可,
首字节作为数据类型):
/***************************************
* Flash Block Range
锛�
// LOW--not program, partition 0 and 1
0x00800000-0x00803FFF -- 16KB,EEPROM-low block0, RWW_P:0
0x00804000-0x00807FFF -- 16KB,EEPROM-low block1, RWW_P:0
0x00F98000-0x00F9BFFF -- 16KB,low flash memory block2, RWW_P:1 //bootloader
0x00F9C000-0x00F9FFFF -- 16KB,low flash memory block3, RWW_P:1 //bootloader
// MID , partition 2 and 3
0x00808000-0x0080FFFF -- 32KB,EEPROM-mid block0, RWW_P:2
0x00810000-0x00817FFF -- 32KB,EEPROM-mid block1, RWW_P:3
//HIGH, , partition 4 and 5
0x00FA0000-0x00FAFFFF -- 64KB,high flash memory block0, RWW_P:4 //User App
0x00FB0000-0x00FBFFFF -- 64KB,high flash memory block1, RWW_P:4
0x00FC0000-0x00FCFFFF -- 64KB,high flash memory block2, RWW_P:4
0x00FD0000-0x00FDFFFF -- 64KB,high flash memory block3, RWW_P:5
0x00FE0000-0x00FEFFFF -- 64KB,high flash memory block4, RWW_P:5
0x00FF0000-0x00FFFFFF -- 64KB,high flash memory block5, RWW_P:5
//256K--all used
0x01000000-0x0103FFFF -- 256KB,256k flash memory block0, RWW_P:6
0x01040000-0x0107FFFF -- 256KB,256k flash memory block1, RWW_P:6
0x01080000-0x010BFFFF -- 256KB,256k flash memory block2, RWW_P:6
0x010C0000-0x010FFFFF -- 256KB,256k flash memory block3, RWW_P:6
0x01100000-0x0113FFFF -- 256KB,256k flash memory block4, RWW_P:7
0x01140000-0x0117FFFF -- 256KB,256k flash memory block5, RWW_P:7
0x01180000-0x011BFFFF -- 256KB,256k flash memory block6, RWW_P:7
0x011C0000-0x011FFFFF -- 256KB,256k flash memory block7, RWW_P:7
**************************************/
uint32_t USERAPPFLASH_STARTADDR=0x00FA0000;
uint32_t USERAPPFLASH_ENDADDR=0x011FFFFF;
//erase
//0xFD0000-0x010032E4, 0x05,0x7d,0x00,0x00,0x80,0x32,0xe4,0x00
void UserFlash_EraseIvtAndUserAppBlock_g(uint8_t *data, uint8_t length)
{
uint32_t count=0;
USERAPPFLASH_STARTADDR = data[1]*256*256 + data[2]*256 + data[3] + 0x800000;
USERAPPFLASH_ENDADDR = data[4]*256*256 + data[5]*256 + data[6] + 0x800000;
Flash_Unlock_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
Flash_Erase_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
//Flash_Check_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
while(count<100000)
count++;
// erase_flash_except_bootloader();
}
//length%2==0,length must be even number
void UserFlash_WriteData(uint32_t addr, uint32_t *data, uint32_t length)
{
uint32_t startAddr;
uint32_t endAddr;
startAddr = addr;
endAddr = startAddr+length-1;
// Flash_Unlock_g(startAddr,endAddr);
// ret = Flash_Erase_g(startAddr,endAddr);
//ret = Flash_Check_g(startAddr,endAddr);
Flash_Program_g(startAddr,endAddr, data,length);
// Flash_Lock_g(startAddr,endAddr);
}
uint32_t m_LastAddr=0x000004+0x800000; //program every 8 address
uint32_t dataForWrite[2]; //最小写入单位64bits
//program addr must add 0x800000
void UserFlash_DataParseAddrData(uint8_t *data, uint8_t length)
{
uint32_t addr;
uint32_t dataTmp;
addr = data[1]*256*256 + data[2]*256 + data[3] + 0x800000;
//large-endian
dataTmp = data[4]*256*256*256 +data[5]*256*256+ data[6]*256 + data[7];
if(addr%8==0) //本次第一个地址
{
if(m_LastAddr%8==0) //上一次也为第一个
{
dataForWrite[1] = 0xFFFFFFFF; //上一次第二个填充FFFFFFFF
UserFlash_WriteData(m_LastAddr,dataForWrite,2);
}
//无论上次是否为第一个,本次都是开始
dataForWrite[0] = dataTmp; //鏈涓虹涓�涓寚浠ゅ瓧
}
else //本次为第二个地址
{
if(m_LastAddr%8==0) //上次为第一个
{
if((addr-m_LastAddr)==4) //与上次连续
{
dataForWrite[1] = dataTmp; //本地为上次同一组第二个
UserFlash_WriteData(m_LastAddr,dataForWrite,2);
}
else //与上一次不连续
{
dataForWrite[1] = 0xFFFFFFFF; //上次第二个填充FFFFFFFF
UserFlash_WriteData(m_LastAddr,dataForWrite,2);
dataForWrite[0] = 0xFFFFFFFF; //本次第一个填充FFFFFFFF
dataForWrite[1] = dataTmp; /
UserFlash_WriteData(addr-4,dataForWrite,2);
}
}
else //上次为第二个,仅填充本次组即可
{
dataForWrite[0] = 0xFFFFFFFF;
dataForWrite[1] = dataTmp;
UserFlash_WriteData(addr-4,dataForWrite,2);
}
}
m_LastAddr = addr;
}
void UserFlash_LastIsFull64Bits_g()
{
if(m_LastAddr%8==0) //最后是否为单个数据
{
dataForWrite[1] = 0xFFFFFFFF;
UserFlash_WriteData(m_LastAddr,dataForWrite,2);
}
Flash_Lock_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
}
另外提醒大家一下,在没有Bootloader时,首次通过JTAG烧录程序时,可以将Bootloader和App合并烧录,一般是将Bootloader的Hex文件最后一行删除,将App的所有行复制到Bootloader后面。
下面贴几个文件:
Bootloader.h
#ifndef _AFTER_PROTOCOL_BOOTLOADER_H_
#define _AFTER_PROTOCOL_BOOTLOADER_H_
#include
//bootloader wait time (seconds)
#define g_GOTOAPP_TIMEOUT 4
///
/// Command type
///
typedef enum
{
EntryBootloader=0,Reset=1,Data=2,DataEnd=3,CheckBootloader=4,Erase=5,ERR=0xff
}AfterBootloader_CmdType;
///
/// Bootloader Entry
///
uint8_t m_Bootloader_EntryBootloaderCmd[8];
///
/// reset in bootloader
///
uint8_t m_Bootloader_ResetCmd_g[8];
///
/// Check Mcu is whether in bootloader
///
uint8_t m_Bootloader_CheckBootloaderCmd[8];
///
/// reponse to up machine with "I am in bootloader" for once enter bootloader
///
uint8_t g_Bootloader_EntryBootloaderReponse[8];
///
/// reponse for check bootloader command, if mcu is in bootloader and up machine ask for reply
///
uint8_t g_Bootloader_CheckBootloaderReponse[8];
///
/// reponse for erasing completed
///
uint8_t g_Bootloader_EraseFlashReponse[8];
///
/// reponse for filling one data completed
/// 02 00 00 00 00 00 00 00
///
uint8_t g_Bootloader_DataReponse[8];
///
/// reponse for the last data writing completed
///
extern uint8_t g_Bootloader_DataProgramEndReponse[8];
//check received can data, and parse command type
AfterBootloader_CmdType Bootloader_DataParse_g(uint8_t *data, uint8_t dataLength);
#endif
Bootloader.c
#include "Bootloader.h"
///
/// Bootloader Entry
///
uint8_t m_Bootloader_EntryBootloaderCmd[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
///
/// reset in bootloader
///
uint8_t m_Bootloader_ResetCmd_g[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
///
/// Check Mcu is whether in bootloader
///
uint8_t m_Bootloader_CheckBootloaderCmd[8] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
///
/// reponse to up machine with "I am in bootloader" for once enter bootloader
///
uint8_t g_Bootloader_EntryBootloaderReponse[8] = { 0x00, g_GOTOAPP_TIMEOUT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
///
/// reponse for check bootloader command, if mcu is in bootloader and up machine ask for reply
///
uint8_t g_Bootloader_CheckBootloaderReponse[8] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
///
/// reponse for erasing completed
///
uint8_t g_Bootloader_EraseFlashReponse[8] = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
///
/// reponse for filling one data completed
/// 02 00 00 00 00 00 00 00
///
uint8_t g_Bootloader_DataReponse[8] ={ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
///
/// reponse for the last data writing completed
///
uint8_t g_Bootloader_DataProgramEndReponse[8] = { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//compare array
uint8_t ArrayCheck(uint8_t *data1,uint8_t *data2,uint8_t length)
{
uint8_t i,result=0;
for(i=0;i
UserAppFlash.h
#ifndef _AFTER_PROTOCOL_USERAPPFLASH_H_
#define _AFTER_PROTOCOL_USERAPPFLASH_H_
#include
//erase, 8 bits data is can receive data
void UserFlash_EraseIvtAndUserAppBlock_g(uint8_t *data, uint8_t length);
//fill data, 8 bits data is can receive data
void UserFlash_DataParseAddrData(uint8_t *data, uint8_t length);
//receive data end, check data is whether writed completed
void UserFlash_LastIsFull64Bits_g();
#endif
UserAppFlash.c
#include "Bootloader.h"
#include "Drivers/Flash/flash.h"
/***************************************
* Flash Block Range
锛�
// LOW--not program, partition 0 and 1
0x00800000-0x00803FFF -- 16KB,EEPROM-low block0, RWW_P:0
0x00804000-0x00807FFF -- 16KB,EEPROM-low block1, RWW_P:0
0x00F98000-0x00F9BFFF -- 16KB,low flash memory block2, RWW_P:1 //bootloader
0x00F9C000-0x00F9FFFF -- 16KB,low flash memory block3, RWW_P:1 //bootloader
// MID , partition 2 and 3
0x00808000-0x0080FFFF -- 32KB,EEPROM-mid block0, RWW_P:2
0x00810000-0x00817FFF -- 32KB,EEPROM-mid block1, RWW_P:3
//HIGH, , partition 4 and 5
0x00FA0000-0x00FAFFFF -- 64KB,high flash memory block0, RWW_P:4 //User App
0x00FB0000-0x00FBFFFF -- 64KB,high flash memory block1, RWW_P:4
0x00FC0000-0x00FCFFFF -- 64KB,high flash memory block2, RWW_P:4
0x00FD0000-0x00FDFFFF -- 64KB,high flash memory block3, RWW_P:5
0x00FE0000-0x00FEFFFF -- 64KB,high flash memory block4, RWW_P:5
0x00FF0000-0x00FFFFFF -- 64KB,high flash memory block5, RWW_P:5
//256K--all used
0x01000000-0x0103FFFF -- 256KB,256k flash memory block0, RWW_P:6
0x01040000-0x0107FFFF -- 256KB,256k flash memory block1, RWW_P:6
0x01080000-0x010BFFFF -- 256KB,256k flash memory block2, RWW_P:6
0x010C0000-0x010FFFFF -- 256KB,256k flash memory block3, RWW_P:6
0x01100000-0x0113FFFF -- 256KB,256k flash memory block4, RWW_P:7
0x01140000-0x0117FFFF -- 256KB,256k flash memory block5, RWW_P:7
0x01180000-0x011BFFFF -- 256KB,256k flash memory block6, RWW_P:7
0x011C0000-0x011FFFFF -- 256KB,256k flash memory block7, RWW_P:7
**************************************/
uint32_t USERAPPFLASH_STARTADDR=0x00FA0000;
uint32_t USERAPPFLASH_ENDADDR=0x011FFFFF;
//erase
//0xFD0000-0x010032E4, 0x05,0x7d,0x00,0x00,0x80,0x32,0xe4,0x00
void UserFlash_EraseIvtAndUserAppBlock_g(uint8_t *data, uint8_t length)
{
uint32_t count=0;
USERAPPFLASH_STARTADDR = data[1]*256*256 + data[2]*256 + data[3] + 0x800000;
USERAPPFLASH_ENDADDR = data[4]*256*256 + data[5]*256 + data[6] + 0x800000;
Flash_Unlock_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
Flash_Erase_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
//Flash_Check_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
while(count<100000)
count++;
// erase_flash_except_bootloader();
}
//write one group (64bits) data
//length%2==0,length must be even number
void UserFlash_WriteData(uint32_t addr, uint32_t *data, uint32_t length)
{
uint32_t startAddr;
uint32_t endAddr;
startAddr = addr;
endAddr = startAddr+length-1;
// Flash_Unlock_g(startAddr,endAddr);
// ret = Flash_Erase_g(startAddr,endAddr);
//ret = Flash_Check_g(startAddr,endAddr);
Flash_Program_g(startAddr,endAddr, data,length);
// Flash_Lock_g(startAddr,endAddr);
}
uint32_t m_LastAddr=0x000004+0x800000; //program every 8 address锛�64bits
uint32_t dataForWrite[2]; //every 64bits for programming
//program addr must add 0x800000
//every 64bits for programming (one group with two data)
void UserFlash_DataParseAddrData(uint8_t *data, uint8_t length)
{
uint32_t addr;
uint32_t dataTmp;
addr = data[1]*256*256 + data[2]*256 + data[3] + 0x800000;
//large-endian
dataTmp = data[4]*256*256*256 +data[5]*256*256+ data[6]*256 + data[7];
if(addr%8==0) //is the first 32bits data of 64bits , every 32bits occupy 4 address uints
{
if(m_LastAddr%8==0) // last address is first of a group
{
dataForWrite[1] = 0xFFFFFFFF; //fill second data of last group with 0xffffffff
UserFlash_WriteData(m_LastAddr,dataForWrite,2); //write last group data to flash
}
//Hower last group is really filled, the new group start
dataForWrite[0] = dataTmp; //new group first data
}
else //is the second data of group
{
if(m_LastAddr%8==0) // last address is first of a group
{
if((addr-m_LastAddr)==4) //this is the next of last data within one group
{
dataForWrite[1] = dataTmp; //fill the second data of group
UserFlash_WriteData(m_LastAddr,dataForWrite,2); //write this group to flash
}
else //last address is first data of a group, and this address is second, but they are not in one group
{
dataForWrite[1] = 0xFFFFFFFF; //fill second data of last group with 0xffffffff
UserFlash_WriteData(m_LastAddr,dataForWrite,2); //write last group data to flash
dataForWrite[0] = 0xFFFFFFFF; //fill first data of this group with 0xffffffff
dataForWrite[1] = dataTmp; //fill second data of this group
UserFlash_WriteData(addr-4,dataForWrite,2); //write this group data to flash
}
}
else// last address is second of a group, and this address is second
{
dataForWrite[0] = 0xFFFFFFFF; //fill first data of this group with 0xffffffff
dataForWrite[1] = dataTmp; //fill second data of this group
UserFlash_WriteData(addr-4,dataForWrite,2); //write this group data to flash
}
}
m_LastAddr = addr;
}
//receive data end, check data is whether writed completed
void UserFlash_LastIsFull64Bits_g()
{
if(m_LastAddr%8==0) // last address is first of a group
{
dataForWrite[1] = 0xFFFFFFFF; //fill second data of last group with 0xffffffff
UserFlash_WriteData(m_LastAddr,dataForWrite,2); //write last group data to flash
}
Flash_Lock_g(USERAPPFLASH_STARTADDR,USERAPPFLASH_ENDADDR);
}