前言
笔者所在的公司近期选型用的新MCU,型号为NXP的MPC5748G,最近接到搞bootloader的任务,CSDN浏览一番发现MPC5744系列的文章比较多,于是参考了两个大佬的程序,将bootloader移植到了MPC5748G中。
参考的上位机
参考的MCU中的下位机
参考的5748 bootloader demo
上面第三个链接中,该作者只提供了bootloader的跳转demo,具体思路为将此demo作为框架,将第二个链接中的下位机代码移植过来,适配5748G。
具体程序流程大致为,上电后4秒内,LED1闪烁等待上位机指令,如果没有,4s后跳转至用户app。如果上位机有CAN指令,则执行flash 擦除、编程等操作,上位机显示进度,编程时,LED2闪烁。编程完成后,跳转至app。
5748G flash分布以及启动原理
5748G的flash分布情况可以参考官方RM文档的Memory Map章节,同5744一样,分为16K、32K、64K、256K四种block
其中指定了可以作为boot区的block:(RM文档57.1.3)
系统启动时,按照序号顺序依次检索这些地址的数据前半字是否具为0x005A,如果是,则确定此block为启动boot区。
在这里只启动CPU0,假设我们想将00FC0000起始的分区作为boot区,则该地址的数据必须为005A0002,该值由SDK自动生成,编译到elf文件或者hex文件中。
如果你用的是SDK_S32_PA_11的SDK包,该值的生成被定义在工程中的stattup_MPC5748G.S文件中:
可是很不幸,开头参考的三个链接中,所用的SDK都很老,所以在此例程中,该值被定义在了flashrchw.c中:
当确定好boot启动分区之后(0xFC0000),需要修改链接文件,从而才能正确编译。
这里将FC0000作为起始地址,FC0010存放boot程序入口地址,FC0400作为boot程序入口
同时别忘了修改flashrchw.c文件:
将RCHW2_0修改为上面的boot程序入口地址。
编译出来之后,可以查看一下HEX文件:
可以看到,与预期的相同。当系统上电后,MCU寻址到FC0000,识别到0x005A0002,即确定了此boot区与启动的CPU核心。随即在FC0010处寻址到了cpu的入口地址(即我们的boot程序起始地址),然后跳转到FC0400,开始运行boot程序
boot程序解析
上电后,boot程序首先开中断、设置频率等操作,初始化GPIO与CAN。然后向上位机发送一帧进入bootloader指示:
之后就是等待、CAN协议、flash擦除编程等逻辑操作了。具体实现代码可以查看源码。
我们规定app的起始地址必须为0x01000000,boot中实现跳转的代码与地址:
#define Bootloader_StartAddr 0x00FC0010
#define APP_StartAddr 0x01000010
void bootloader_entry(void)
{
Prepare_Before_Jump_m();/*de-initialize the used peripherals and clean RAM*/
(*(void (*)(void))(*(uint32_t*)Bootloader_StartAddr))();
while(1);
}
void app_entry(void)
{
Prepare_Before_Jump_m();/*de-initialize the used peripherals and clean RAM*/
uint32_t result = *(uint32_t *)APP_StartAddr;
if(result!=0xFFFFFFFF)
(*(void (*)(void))(*(uint32_t*)APP_StartAddr))();/*run the function via function pointer convert with a certain address*/
else
(*(void (*)(void))(*(uint32_t*)Bootloader_StartAddr))();
while(1);/*stop here for anyhow*/
}
app程序
这里将app程序的flash分区改为0x01000000,此后此boot的所有app必须按照此地址修改:
注意flashrchw.c中也要对应修改。
上位机
上位机使用时需要注意,我用的是创芯科技的CAN盒,需要替换ControlCAN.dll文件,不然识别连接不成功:
移植过程中的问题
1.我一开始在boot中加入了uart,方便调试,但是跳转app经常不成功,后来屏蔽uart相关代码之后恢复正常,猜测可能是uart没有deinit,如果想用uart调试的同学请自行添加deinit uart相关代码。
2.CAN引脚复用寄存器IMCR。
SIUL2.IMCR[188].B.SSS = 0b0010; //Set PB1 as CAN0_RX.
如果你在RM0文档搜这个寄存器的话,会发现数量有500多个!具体要用哪个呢?搜索半天才发现RM文档附带了一个xls文件,所有的引脚复用等说明在这个表里面可以找到。
3.5748G RAM大小。官方给出的总大小为768K
但是ld文件中却声明了只有256K
SRAM_SIZE = 256K;
/* Define SRAM Base Address */
SRAM_BASE_ADDR = 0x40000000;
因为主函数中具有跳转时清除RAM的功能,一开始我直接设置的768K,结果每次程序清完这768K的RAM之后,跳转app都不成功,后面只修改为清256K,才恢复正常,个人猜测原因可能是这768K RAM不全是CPU0用的,CPU0只可使用256K?
#define __SRAM_BASE_ADDR 0x40000000
#define __SRAM_SIZE 0x00040000
...
void CleanRAM(void)
{
uint32_t cnt;
uint32_t *pRam;
/*
* clean system SRAM
*/
cnt = __SRAM_SIZE/4;
pRam = (uint32_t*)__SRAM_BASE_ADDR;
while(cnt--)
*pRam++ = 0;
/*
* clean system Local DMEM
*/
//cnt = __LOCAL_DMEM_SIZE/4;
//pRam = (uint32_t*)__LOCAL_DMEM_BASE_ADDR;
//while(cnt--)
// *pRam++ = 0;
}
下载地址
参考
【MPC5744P】Hex文件解析
【MPC5744P】Bootloader下位机开发(CAN通讯)
【MPC5744P】Bootloader上位机开发(CAN通讯)
【MPC5744P】S32DS编译生成Hex文件的方法
MPC5748G之flash bootloader & app