×
单片机 > 单片机程序设计 > 详情

LPC1788 IAP的实现及遇见的问题

发布时间:2020-06-18 发布时间:
|

参考网上的资料先学习了IAP实现的基本原理,结合自己板子的实际硬件资源,把芯片自带的512K内部Flash分为两部分,一部分为BootLoader实现IAP和应用程序的加载(跳转),另一部分是应用程序,升级的固件文件存放在外置的NandFlash系统中。为了把BootLoader做的更通用和漂亮一些,启用了RTX操作系统和Emwin,代码量大概在130K左右,因此,BootLoader放在了0~0x30000,应用放在了0x30000~0x80000。



芯片启动时首先运行BootLoader,BootLoader启动NandFlash文件系统,检查是否需要更新固件,NandFlash中放置了一个needup.bin文件,内容为空,只要存在needup.bin文件就说明需要升级,固件放在文件名为firmware.bin中。如果需要升级固件,启动固件升级进程,利用LPC1788的IAP功能,擦除扇区,将firmware.bin文件内容编程到0x30000开始的地方,然后跳转到0x8 0000运行APP。


如果不需要升级固件(没有needup.bin),则直接跳转到0x8 0000运行APP。


在跳转到0x8 0000开始运行APP前,首先判断一下0x80000处的数据(堆栈指针)是否在0x1000 0000~0x1000 FFFF,如果在范围里则为正确的APP,否则没有有效的APP,则不跳转到APP,直接进入到BootLoader程序。


为了防止在将固件文件写到内部Flash过程中出现问题,或固件本身就有问题,导致下载完成后不能正常运行,需要有一种直接进入BootLoader程序的方法,本系统有个按键,就设计为如果开机时按键被按下则直接进入到BootLoader而不加载APP应用,在BootLoader程序下启动USB、串口等进行固件的重新下载。


在实际编程的过程中出现了两个特殊的问题,经过努力查找问题最终得到了解决,下面将两个问题做个总结。


第一个问题是BootLoader程序调用LPC1788的IAP程序代码出现HardFault,在百度、Google各种查找,有一个人也出现类似的问题,但是并没有解决。最后不得已从main函数第一行开始防止IAP的测试代码,发现刚进main函数时调用IAP代码是不出错的,这就给我们一个启示,肯定是程序的某个地方触发了此问题。把IAP的测试代码往后放,放到while(1)前发现出现了HardFault,对这两个地方用仿真器进行跟踪,发现当代码停到两个调用代码前时,IAP所在(0x1FFF1FF0)的程序代码竟然不同。在后面停下时的代码明显的不对,好多mov r0, r0。为了找出来到底是哪句代码出了问题,从上到下一行一行的测试,最终找到了问题,原来在初始化EMC时修改了LPC_SC->MARB,是为了提高LCD占用总线的权限,设置LCD刷新拥有做高权限,数据访问次之,程序再次,其余最低。把这句话屏蔽后,采用缺省的总线仲裁设置后,能够正常的调用IAP。也许出现这种情况的可能性不高,但自己趟过的坑能告诉别人,让别人免走弯路也是一件好事。


第二个问题是从BootLoader跳转到APP时,APP并不能正常的运行。代码也是按照正常的跳转处理的,读取0x30000处的4个字节设置MSP(堆栈指针),将把0x30004的4个字节装入PC进行跳转,APP程序也正确设置了终端向量到0x30000。由于在BootLoader程序中看不到跳转后的源代码,但结合APP的map文件大致能知道程序运行到了哪个函数,用仿真器一直跟踪跳转后的汇编代码,发现程序也是最终停在了HardFault。用仿真器直接调试APP程序,要设置仿真器的初始化文件,如下图所示。其中runflash.ini文件内容如下:


SP = _RDWORD(0x00030000);           // Setup Stack Pointer

 

PC = _RDWORD(0x00030004);           // Setup Program Counter


其实就是设置仿真器进入调试状态是把MCU的SP和PC从哪里装载值,这个从BootLoader跳转的代码作用是一样的。进入调试状态,整个APP能够正常运行。这就说明我们在跳转到APP时,由于BootLoader本身已经设置了很多寄存器,导致APP的初始化过程和现有的寄存器设置有冲突。网上资料显示一定要关闭中断,在跳转前加了关全局中断的代码,不管用。又说要把RCC和NVIC复位,做了也不太管用。后来经过思考,最好的解决方法是BootLoader跳转到APP时把MCU做软复位,然后在执行尽量少的代码的情况下进行跳转,这样BootLoader的影响就很小,几乎等同于直接运行APP程序,能够尽早的把控制权交给APP程序。



软复位的代码还是比较好做的,如下:


__set_FAULTMASK(1);

 

NVIC_SystemReset();

 

while(1);


经测试也好用,现在的问题是等MCU重新启动后,如何判断是为了进APP的软重启还是用户断电后的硬启动,这个可以通过读取复位源标识寄存器(RSID—0x400F C180) 确定,如果此寄存器的第4位SYSRESET置位,说明处理器由于系统请求复位而被复位。但是在BootLoader的界面中也有一个复位按钮,也是通过这个方式重启的,这样就不能完全区分出来了。


为了解决这个问题,就在思考有哪些信息能够重启而不会丢失呢?写文件肯定是可以的,但为了让BootLoader尽快进入APP不能加载文件系统。写EEPROM肯定也是可以的,但是EEPROM被APP用了。还有个能用的就是RTC的通用寄存器,LPC1788有4个RTC通用寄存器(GPREG0~GPREG4–地址 0x4002 4044~0x4002 4054),这类寄存器可在主电源断开时保存重要的信息。芯片复位时,不会影响到这些寄存器中的值。而我们的APP正好也没有用到这四个寄存器,就选用其中的GPREG0保存重启的原因。


剩下的工作就简单了,需要跳转到APP时将GPREG0的值置为1,然后软重启。BootLoader程序在SystemInit函数(MCU启动后执行的第一段代码)中加入判断GPREG0的值的代码,如果GPREG0的值为0正常继续启动BootLoader,如果值为1直接跳转到APP。


经过测试发现此方法可行,能够很顺利的从BootLoader跳转到APP。

关键字:LPC1788  IAP  问题 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会