LPC1114 IAP在线升级
IAP(In Application Program),即在应用中可编程。顾名思义,就是在系统运行的过程中动态编程,这种编程是对程序执行代码的动态修改,而且毋须借助于任何外部力量,也毋须进行任何机械操作。这一点有别于ISP(In System Programming),即在系统可编程。一般来说,ISP 在进行加载程序以前,需要设置某些功能引脚,而IAP则不需要作硬件上的任何动作,只要有合法的数据来源。LPC11XX支持ISP和IAP升级程序,当采用RS485通信时候的,由于ISP升级程序受条件限制,只能采用IAP升级程序。
IAP原理以及如何调用
IAP函数是固化在微处理器内部flash上的一些函数代码,最终的用户程序可以直接通过调用这些函数来对内部flash进行擦除和编程操作。
对于在应用编程来说,应当通过寄存器r0 中的字指针指向存储器(RAM)包含的命令代码和参数来调用IAP 程序。IAP 命令的结果返回到寄存器r1 所指向的返回表。用户可通过传递寄存器r0 和r1 中的相同指针重用命令表来得到结果。参数表应当大到足够保存所有的结果以防结果的数目大于参数的数目。参数传递见图2-1。参数和结果的数目根据IAP命令而有所不同。参数的最大数目为5,由“将RAM 内容复制到Flash”命令传递。结果的最大数目为2,由“扇区查空”命令返回。命令处理程序在接收到一个未定义的命令时发送状态代码INVALID_COMMAND。IAP 程序是thumb 代码,位于地址0x7FFFFFF0。
图2-1 IAP的参数传递
表2-1描述了IAP的命令。
表2-1 IAP 命令汇总
2.3 IAP 编程函数接口
IAP 功能可用下面的C 代码来调用。
在线代码运行器定义IAP 程序的入口地址。由于IAP 地址的第0 位是1,因此,当程序计数器转移到该地址时会引起Thumb 指令集的变化。
#define IAP_LOCATION 0x7ffffff1
定义数据结构或指针,将IAP 命令表和结果表传递给IAP 函数
unsigned long command[5];
unsigned long result[2];
定义函数类型指针,函数包含2 个参数,无返回值。注意:IAP 将函数结果和R1 中的表格基址一同返回。
typedef void (*IAP) (unsigned int [ ] , unsigned int [ ]);
IAP iap_entry;
设置函数指针
iap_entry=(IAP) IAP_LOCATION;
使用下面的语句来调用IAP。
iap_entry (command , result);
Flash 存储器在写或擦除操作过程中不可被访问。执行Flash 写/擦除操作的IAP 命令使用片内RAM 顶端的32 个字节空间。如果应用程序中允许IAP 编程,那么用户程序不应使用该空间。
环境
首先,在您动手做这个实验之前,先要弄清除咱俩的软硬件有什么不同:
1.我的芯片是LPC1114,里面有32K的FLASH,您的芯片如果是其它类型,也不要紧,只是在程序里面,地址上限可能不一样。
2.我的仿真器是ULINK2,如果您的仿真器是其它的,估计也没多大问题,只要您会用它就行了。什么?没有仿真器,那还是放弃吧,出错了没法调试。
3.我的开发环境是KEIL 4,MDK4.23。使用其它开发环境的话,您要是能到MDK中的设置对应到您那里怎么设置,估计也没问题。
Flash规划
LPC1114 Flash存储器的大小为32K,下图为Flash扇区和地址的详细图。
RS485 IAP 在线升级方案
准备两份工程,一份用于负责程序跳转和升级的工程,类似于BootLoader,其实也可以称之为Second BootLoader,这里为了不跟系统的BootLoader混淆,以下用IAP命名。另外一份
就是在LPC1114单片机能正常运行的业务程序,以下用APP命名。
第一步:规划好你两个程序的存放位置。
IAP程序肯定是从0X0000 0000开始的,因为它是引导程序。将IAP程序放在
0X0000 0000-0X0000 0FFF的位置,即Flash的第0扇区,占用4K空间。
APP程序从0X0000 1000-0X0000 7FFF,占用28K空间。
如果IAP功能较多,超过了4K,可以适当的调整,这样APP的空间就相应的减少
了,但是不能分配给IAP和APP的空间须是4K的整数倍,因为在在线升级时,
编程前需要对编程的扇区进行擦除。
第二步:制作IAP程序。
为了方便APP程序能够调用在线升级的功能,把升级的入口函数放置到独立的一个program_entry.c文件里,并在定位到一个固定的地址。通过下面的分散加载文件进行固定地址。
1.编写跳转APP函数:
#define APP_START_ADDR 0X0000 1000
int main(void)
{
void (*userProgram)() = (void (*)())program_entry;
uint32_t AppSpInitV al;
uint32_t AppJumpAddr;
uint8_t u8Data = 0;
SystemInit();
UART485Init(115200);
while(0 == u8UARTReceive(&u8Data))
{
If (timeout)break; //这里是超时的判断,需要自己实现}
if ((0 == AppPresent()) || (26 == u8Data)) //ctrl+z
{
vUARTSend("\r\n", 21);
program_entry(); //启动升级
}
else
{
vUARTSend("\r\n", 16);
AppSpInitV al = *(uint32_t *)APP_START_ADDR;//堆栈地址
AppJumpAddr = *(uint32_t *)(APP_START_ADDR + 4); //APP程序的入口
userProgram = (void (*)())(AppJumpAddr);
__set_MSP(AppSpInitV al); //设置寄存器
(*userProgram)(); //跳转到APP程序
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论