单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 890|回复: 3
打印 上一主题 下一主题
收起左侧

LPC1768 IAP升级方法

[复制链接]
跳转到指定楼层
楼主
liu100m 发表于 2018-10-8 05:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1IAP介绍
IAP即“in applicatinprogramming”在应用编程的缩写,指MCU可以在系统中获取新代码并对自己重新编程,即改变应用程序。它与我们所熟悉的ISP编程不同,      
  LPC1768 ISP编程接口为串口1,如果使用其他的串口或其他总线则不能对其进行编程。而我们这里所说的IAP通过下载一段引导程序Bootloader程序,如果我们想要从串口2或网口更新应用程序,在Bootloader中初始化相应的串口或网口,使其接收应用程序,将接收到的应用程序写入到Flash里面IAP完成后跳转到应用程序入口执行应用程序。所以现在的IAP程序涉及到两个概念:Bootloader和应用程序。

Bootloader:BootLoader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。这里我们所说的Bootloader也是系统开机前的一段小程序,其主要任务是用来初始化串口和IAP端口(网口CAN接口等)的,通过判断状态是否需要从IAP端口进行更新应用程序,若需要更新则从端口接收应用程序,并存放到指定的Flash里面,更新完成后则跳入到指定的Flash里面执行应用程序。
应用程序:即我们需要开发板实现功能的程序,其中应用程序主要分为两种:hex文件和bin文件。在我们经常使用的KEIL中默认编译生成的可执行文件(应用程序)为hex格式的,若需要编译生成bin格式需要做如下修改,加入“D:\Keil\ARM\ARMCC\bin\fromelf.exe --bin --output ./Obj/Can_Updata.bin ./Obj/test.axf”,重新编译生成的Can_Updata.bin文件存放在Obj文件夹下。

2、bin格式文件与hex格式文件的区别
bin格式文件是纯粹的二进制文件,使用下载其将其下载到开发板时其内容完全不变,所以对于IAP下载使用bin格式文件是比较方便的,如下图是bin文件的内容与写入到开发板后使用仿真器观察到Flash存放的内容(这段程序当然是可以执行的)。

Hex格式文件:Hex全称(Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制数数字组成。如下图是hex文件的部分数据,其组成由“:CCAAAARR...ZZ ”,CC=10代表长度为16字节,AAAA=0000本条记录中的数据在存储区中的起始地址,RR=00,数据区,ZZ=38为校验,这里就不做仔细说明了。

3、LPC1768 IAP原理
LPC1768复位后开始执行Boot代码,Boot代码可以执行ISP程序或用户的应用代码。发生硬件复位后,P2.10 引脚为低电平,这就被当作启动ISP命令处理器的外部硬件请求。假定在/RESET 引脚上出现上升沿时,电源引脚出现正确的信号,那么在采样P2.10 之前有3ms的时间决定是执行用户代码还是ISP 处理程序。如果P2.10 为低电平且看门狗溢出标志置位,那么忽略启动ISP 命令处理器的外部硬件请求。在没有ISP 命令处理器的请求(硬件复位后P2.10引脚为高电平)时,将搜索有效的用户程序。若发现有效的用户程序,执行控制权就被转移给用户程序。若没有找到有效的用户程序,就将调用自动波特率程序。这里不讨论ISP下载及命令,有兴趣的朋友可以查看LPC1768技术手册第三十二章ISP命令。


在IAP升级中,程序正常执行即用户代码(这里的用户代码是我们所说的IAP引导程序),如下是IAP升级流程图,程序将预留端口(这里提供有串口和CAN总线接口两种)接收到的APP程序bin文件,将接收到的数据写入到指定的Flash区域(例程APP地址为0x0001 0000),程序通过IAP命令将数据写入到Flash里面,LPC1768提供了一系列IAP命令对片内Flash进行擦除编写等
4、IAP命令
LPC1768通过IAP函数对片内Flash进行操作,IAP函数是固化在0x1FFF1FF1处的一个有传入参数和返回参数的一个函数,在LPC1768技术手册第三十二章IAP命令中有有详细的说明。主要提供有如下命令:准备下操作扇区、将RAM内容复制到Flash、清除扇区、扇区查空、读器件ID、读boot版本、比较、重新调用ISP等。

5、串口IAP升级
本例程是根据官方提供的串口IAP更新图片进行修改而来,直接使用官方的IAP.c文件,该文件中提供了如上图IAP命令的各种函数,其具体参数可以参考IAP命令。根据官方例程里面将bmp图片经过串口采用Xmodem1K协议发送到开发板存放在地址0x0001 0000,如下图是LPC1768 Flash分配地址,第16~21扇区为应用程序存放空间。这里我们将要传送的bmp图片改为传输应用程序bin文件

6、串口IAP程序分析
例程通过按键对开发板进行控制,INT0键擦除Flash,确认键等待串口IAP,向上键显示菜单,向下键执行应用程序,使用LCD来开发板状态

当程序全部写入到Flash后,按下向下按键,跳转到应用程序,首先修改中断向量表然后进入应用程序
void Boot( void )
{
        SCB->VTOR = IMG_START_SECTOR & 0x1FFFFF80;        //修改中断向量表
        JMP_Boot(IMG_START_SECTOR);
}
堆栈地址更新,PC地址更新
__asm void JMP_Boot( uint32_t address ){
   LDR SP, [R0]                ;堆栈地址更新
   LDR PC, [R0, #4]        ;进入应用程序
}
7、操作步骤及实验现象
1、下载“宝马开发板串口IAP升级”例程,插上USB转串口线,打开超级终端,复位开发板。
2、按下按键INT0按键--擦除扇区
3、按下方向键确认键(即向下按)--等待接收串口程序
4、串口打印’C’字符等待接收数据
5、串口发送文件,选择“1K Xmodem”协议,选择要下载的应用程序bin文件,这里使用DAC例程作为测试。

6、点击“发送”,发送文件
7、发送完成
8、按下方向键向下键开始执行应用程序,这时我们可以使用示波器测试P0.26口输出正弦波信号
bin文件生成方法及设置:
打开要更新应用程序工程,这里使用“IAP升级DAC转换”程序,设置ROM空间地址(程序下载到Flash的地址),这里也是我们应用程序的入口地址0x10000
打开User选项,利用Keil自带的fromelf.exe生成bin文件,bin文件保存在Obj文件夹中,如下图添加“D:\Keil\ARM\ARMCC\bin\fromelf.exe --bin --output ./Obj/app.bin ./Obj/app.axf”,输入文件为app.axf,所以工程编译生成输出文件名设置为app,命令执行生成app.bin文件
打开Asm选项,定义“NO_CRP”,我们可以打开启动文件,当定义了“NO_CRP”后,那么我们后面的代码也就不起作用了,所以在需要加密的时候前面就一定不能再定义了代码读保护,也就是加密的关键字,经过加密后芯片再也无法擦除,由于我们这里程序需要使用到IAP升级,因此添加此定义

编译即可生成app.bin




lpc1768 IAP疑点全解释
IAP简介:
       IAP为在应用编程的简称,其作用是用户自己的程序在运行过程中对用户程序所在的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的程序进行更新升级。
Lpc1768存储器空间分配:
整体Flash布局:     
地址范围
地址说明
0x1000_0000 ~0x1000_7FFF
片上32K通用SRAM
0x2007_C000 ~0x2007_FFFF
片上16K以太网/USB静态SRAM,可用作通用SRAM
0x2008_0000 ~0x2008_3FFF
片上16K以太网/USB静态SRAM,可用作通用SRAM
0x1FFF_0000 ~0x1FFF_1FFF
片上 8K启动代码区
0x0000_0000 ~0x0007_FFFF
片上512K Flash存储器
其他地址
APB、AHB等寄存器映射区
分散加载描述文件:
分散加载描述文件是arm连接器提供的可以将程序中的代码段、数据段定位到flash中特定的物理地址的一种机制。通过此机制我们可以把给IAP程序和用户程序分别分配一部分空间并制定各自的起始地址以保证IAP程序和用户程序不会重叠。关于分散加载描述文件详细文档,请参考《RealView编译工具----链接器参考指南》第三章,对于IAP涉及到的分散加载文件的知识,我们只需知道以下几点。以本次IAP工程为例,我们给IAP升级代码留32K的空间(0x0000_0000~0x0000_7FFFF),剩余的给用户程序空间(即用户程序从地址0x0000_8000开始)。对于IAP程序部分的分散加载文件不做修改,对于用户程序部分修改如下:
我们仅仅对第5行和第6行做了修改,改动的地方做出了标注,其具体表示意思是:
Line5:0x0000_8000表示加载域的起始地址,即放在flash0x0000_8000地址处开始放置,0x0008_0000表示代码区、数据区的总共大小的最大值,程序文件超过此值将会报错,这里取默认值0x0008_0000即可。
Line6: 0x0000_8000表示执行域的起始地址,即程序从0x0000_8000地址处开始执行,0x0008_0000代表的意思参考上一行。
Line7:此行的作用是把中断向量表定位在起始地址处(这里是0x0000_8000).
要使用此分散加载描述文件,还需要将Target Opitions…->Linker下的Use Memory Layout from Target Dialog前的“√”去掉。
IAP函数的使用
Iap函数是固化在Boot Rom中地址0x1FFF1FF1处的一个有传入参数和返回参数的一个函数。对于不同的传入参数,iap函数实现不同的功能。关于这些功能的详细介绍,《LPC1768 user manual》32章第8节IAP commands一节中有详细介绍,这里不赘述。远程升级中我们常用到的几个iap命令是:读器件标识号、准备写操作扇区、擦除扇区、扇区查空、将RAM内容复制到Flash、比较<地址1><地址2><字节数>。
以准备写操作扇区为例说明iap函数的写法。首先定义iap函数的入口地址:
1
#define  IAP_ENTER_ADR  0x1FFF1FF1/*IAP函数入口地址*/
接着声明函数类型指针IAP_Entry:
1
void (*IAP_Entry)(uint32  paramin[ ],uint32  paramout[ ]) ;
初始化IAP函数指针使其指向IAP函数入口地址:
1
2
3
4
void  IAP_EntryInit(void)
{
   IAP_Entry  =( void(*)() )IAP_ENTER_ADR ;
}
由用户手册可知iap命令汇总如下图:
Iap状态码汇总如下图:
据此写出IAP命令字和状态码宏定义如下:(PS:Command Code中的数字10表示十进制,如:Read part ID的命令字为5410,表示其命令字为十进制的54,见上图)
准备写操作扇区的命令解释如下图:
由上图可知准备写操作扇区需要三个参数,分别是Command code、Param0、Param1,返回状态码的可能取值为CMD_SUCCESS、BUSY、INVALID_SECTOR。据此我们写处准备写操作扇区的命令函数如下:
1
2
3
4
5
6
7
8
9
uint32  PreSector(uint8  arg1,uint8  arg2)
{
    paramin[0] = IAP_SELECTOR ;    //设置命令字
    paramin[1] = arg1 ;        //设置参数
    paramin[2] = arg2 ;
    (*IAP_Entry)(paramin, paramout) ; //调用IAP服务程序

    Return (paramout[0]) ;      // 返回状态码
}
其中paramin[]、paramout[]为定义的uint32型全局数组。调用此函数时只需将起始扇区号传给arg1,结束扇区号传给arg2即可。其他命令的函数书写于此大同小异。
这里给出一个远程升级的iap流程:读取器件标识码确定是当前芯片→确定待升级程序(用户程序)占用的起始扇区号与结束扇区号→准备需占用扇区→擦除需占用扇区→扇区查空确定需占用扇区已成功擦除→执行将RAM复制到Flash命令将数据块复制到Flash→执行比较命令校验数据是否正确→如果正确执行下一数据块的复制。
需要说明的一点是:在还行IAP命令的时候,需要关闭中断以保证IAP命令的正确执行。幸运的是Cortex-M3提供了关闭/打开中断的指令CPSID I 和CPSIE I,而且在core_cm3.h中也提供这样的开关中断的函数__enable_irq()和__disable_irq(),需要的时候直接去调用就可以。
bootloaderUsrApp的跳转:
这里我们把引导cpu进入用户代码区的程序称作bootloader,把用户实际实现相应功能的程序称作UsrApp,它们是一个完整的程序,下文提到的bootloader、UsrApp均指这些。
bootloader到UsrApp的跳转需要熟知两方面的知识:一个是中断向量表的重映射,另一个是一段完整的程序的入口是如何定义的。
中断向量表重映射
在LPC1768中,位于地址0xE000_ED08处有一个向量表偏移寄存器VTOR,通过修改此寄存器可以设定向量表基址位于Code区或是RAM区以及向量表的基址偏移域,以此达到中断向量表重映射的目的。比如我们的UsrApp起始地址为0x8000;为使UsrApp在发生中断行为时不会产生错误或异常,我们可以通过以下代码段将中断向量表重映射到地址0x8000处Code区。
1
SCB->VTOR = USR_APP_START_ADDR &0x1FFFFF80;
SCB->VTOR由core_cm3.c提供,对应向量表偏移寄存器地址0xE000_ED08。USR_APP_START_ADDR为用户代码区的起始地址,和数值0x1FFFFF80按位与是保证寄存器的保留位为0和向量表基址位于Code区。此寄存器的详细说明请参考《cortex-M3技术参考手册》第八章第二节的NVIC寄存器描述或《LPC17XX User manual》英文版34.4.3.5章节。,此处不再贴出。对于用户程序,在bootloader中的向量表偏移设置并不起作用,需要在用户程序中重新设置向量表偏移寄存器。原因是CM3器件进入main()函数即要求调用SystemInit(void)进行系统初始化,系统初始化的时候将向量表偏移寄存器清零了,所以需要在调用SystemInit()之后重新设置向量表偏移寄存器。有网文称对于应用了OS的用户程序需要这样做,其实对于开启了中断的的用户程序都需要这样,你的简单的IAP测试程序之所以在没有这样做的情况下通过了测试,是因为你的用户程序测试代码中并没有用到中断。
一个完整镜像的程序入口:
对于在flash中存储的一个完整的程序代码,其起始部分应该为向量表,向量表的内容格式固定如下表(参考《cortex-M3权威指南》7.3节)
上电后的向量表:
由表可知,对于起始存储地址为0的一段完整程序,其首地址处存放的是MSP的初始值,偏移4字节的地址处存放的是PC指针的初始值,我们要运行这段完整的程序,只需将这段完整程序的SP、PC初始值赋给SP和PC寄存器即可,具体实现的函数如下:
1
2
3
4
5
__asm void boot_jump(uint32 address)
{
   LDR  SP, [R0]
LDR  PC ,[R0, #4]
}
对于此函数的解释:__asm是MDK的编译器提供的嵌入汇编的指令(RealView C编译器3.0以上版本提供)。函数体中两行汇编代码的功能分别为:
LDR  SP, [R0]:把R0中的值作为地址,将此地址中的值赋给SP
LDR  PC ,[R0, #4]:把R0中的值加4作为地址,将此地址中的值赋给SP
这里涉及到一个问题,r0中的值是什么?我们根据ATPCS(ARM-THUMBprocedure call standard)可知,对于参数少于等于4的函数,参数是通过R0~R3传递的,第一个参数放在R0中,依次类推。所以这里的R0存放的正式UsrApp的起始地址,回过头再看前面的两行汇编代码,它们做的事正是将UsrApp的SP、PC初始值赋给相应寄存器,达到开始运行UsrApp的目的。
UsrApp的烧写:
因为在片内flash的起始地址处烧写的是我们的iap处理程序,用户程序的起始地址不是0x0000_0000,在通过keil用jlink下载程序的时候,还需做一个设置。在Option for Target→Debug→Settings→Flash Download中,设置下载程序时的起始地址为用户程序的起始地址。如本例中用户程序的起始地址是0x0000_8000,我们设置下载程序的起始地址为0x0000_8000,如下图。如果不这么做的话,通过jlink下载程序的时候会从地址0x0000_0000开始擦除。
遗留的问题:
疑问1:《lpc1768 user manual》34.4.3.5章节指出中断向量表偏移寄存器的向量表基址偏移域为[28:8]位,为什么将偏移量实际赋值给此寄存器的时候没有做’<<8’的处理而是直接赋值过来?PS:《Cortex-M3技术参考手册》第8章的表8-15指出中断向量偏移寄存器的向量表基址偏移域为[28:7]
疑问2:手册中指出使用iap的时候RAM顶部32字节空出,这该怎么理解?iap占用ram顶端32字节,即使我不去刻意留出也不影响iap使用这32字节的空间,我能想到的唯一解释是编译器可能会把程序中的全局变量放到ram顶端32字节区域进而调用iap函数会引起全局变量被修改,是这样么?
  如果你读到了这里并且你知道这些答案,敬请告知解惑。E-mail:arm6410@126.com
参考过的文献:
《arm汇编指令集》--------网文
《arm启动代码的探究-郑远超》
《arm体系结构与编程》------杜春雷(PS:重点第11章)
《map文件认识初步》-------网文
《汇编器指南》------RealviewMDK
《链接器指南》------RealviewMDK
《中断向量表重映射与复制》------网文
《cortex-m3技术参考手册》









  之前说了stm32的iap编程,今天天气真好,顺手就来说说lpc1788的iap编程(没看前面的请查看stm笔记下的内容)
  首先是flash的算法,lpc1768并没有寄存器来让我们操作flash,他内置了iap的flash算法,在技术手册的525页有如下说明
  
  其支持的iap命令有这些
这样我们就能够做出相关的flash读写借口呢(具体请查看lpc1768的技术手册)
unsigned param_table[5];//传递参数列表
unsigned result_table[5];//返回结果列表
//调用iap命令
void iap_entry(unsigned param_tab[],unsigned result_tab[])
{
    void (*iap)(unsigned [],unsigned []);
    iap = (void (*)(unsigned [],unsigned []))IAP_ADDRESS;
    iap(param_tab,result_tab);
}
  通过这种手段就能够调用iap命令,我们演示性的看一个命令
//扇区准备好指令
//起始扇区号 结束扇区号 系统时钟
void prepare_sector(unsigned start_sector,unsigned end_sector,unsigned cclk)
{
    param_table[0] = PREPARE_SECTOR_FOR_WRITE;
    param_table[1] = start_sector;
    param_table[2] = end_sector;
    param_table[3] = cclk;
    iap_entry(param_table,result_table);
}
  该指令在写flash和擦除flash之前必须调用
具体的完整flash代码请查看工程文件,会在文章末尾上传
然后依旧是五个指令
"iap_down"
"iap_jump_app"
"iap_over"
"iap_set_flag"
"iap_clear_flag"
  功能和之前的stm32差不多,但是下载算法变化了,因为stm32支持的写入是每次写入一个十六位数据,而lpc1768每次写入8位数据,而且每次写入数据的量为128/256/512/1024/4096,正好没有我们之前所用的2048,所以算法修改成如下的样子

  1. u8 iapbuf[1024] = {0}; //用于缓存数据的数组
  2. u16 receiveDataCur = 0;  //当前iapbuffer中已经填充的数据长度,一次填充满了之后写入flash并清零
  3. u32 addrCur = FLASH_APP1_ADDR;         //当前系统写入地址,每次写入之后地址增加2048

  4. #define vu32 volatile unsigned int

  5. //开始下载
  6. void iap_down_s(void)
  7. {
  8.     u16 i = 0;
  9.     u16 receiveCount;
  10.     if(erase_user_flash())
  11.     {
  12.        printf("error\r\n");
  13.        return;
  14.     }
  15.     printf("begin,wait data download\r\n");
  16.     receiveMode = 1;//串口进入下载接收数据模式
  17.     while(1)
  18.     {
  19.        //循环接收数据,每次必须要发128个数据下来,如果没有128,说明这是最后一包数据
  20.        //接收到一包数据之后,返回一个小数点,发送完成,系统编程完成之后返回一个iap_over
  21.        if(serial_Buffer_Length & 0x8000)
  22.        {
  23.            receiveCount = (u8)(serial_Buffer_Length&0x00ff);
  24.            if(receiveCount == 128)//满足一包,填充并查看是否有了1024字节,有了写入闪存
  25.            {
  26.               for(i = 0; i < receiveCount; i++)
  27.               {
  28.                   iapbuf[receiveDataCur] = serial_Buffer[i];
  29.                   receiveDataCur++;//完成之后receiveDataCur++;
  30.               }
  31.               receiveExpectCount = 0;//清除期望接收模式
  32.               serial_Buffer_Length = 0;//清除串口满标志
  33.               printf(".");//每次接受一次数据打一个点
  34.               //此时需要检测receiveDataCur的值,要是放满了,就需要写入
  35.               if(receiveDataCur == 1024)
  36.               {
  37.                   //写入flash中
  38.                   if(write_flash(100000,addrCur,(unsigned*)iapbuf,1024))
  39.                   {
  40.                      receiveMode = 0;
  41.                      addrCur = FLASH_APP1_ADDR;
  42.                      receiveDataCur = 0;
  43.                      return;
  44.                   }
  45.                   addrCur += 1024;//地址+2048
  46.                   //写完之后receiveDataCur要清零等待下一次传输
  47.                   receiveDataCur = 0;
  48.               }
  49.               else //有可能最后一包有128个数据但是最终没有2048个数据,此时扩展一个指令用于完成最后一个的写入
  50.               {
  51.                  
  52.               }
  53.               //还没放满,等待下一次数据过来
  54.            }
  55.            else   //不满足一包,说明数据传送这是最后一包,写入闪存
  56.            {
  57.               //没有一包也要传送到缓存中
  58.               for(i = 0; i < receiveCount; i++)
  59.               {
  60.                   iapbuf[receiveDataCur] = serial_Buffer[i];
  61.                   receiveDataCur++;//完成之后receiveDataCur++;
  62.               }
  63.               receiveExpectCount = 0;//清除期望接收模式
  64.               serial_Buffer_Length = 0;//清除串口满标志
  65.               printf(".");//每次接受一次数据打一个点
  66.               //要将没接收满的数据变成0xff
  67.               for(i= receiveDataCur; i < 1024; i++)
  68.               {
  69.                   iapbuf[i] = 0xff;
  70.               }
  71.               //之后就要将这数据写入到闪存中
  72.               if(write_flash(100000,addrCur,(unsigned*)iapbuf,1024))
  73.               {
  74.                   receiveMode = 0;
  75.                   addrCur = FLASH_APP1_ADDR;
  76.                   receiveDataCur = 0;
  77.                   return;
  78.               }
  79.               //printf("\r\nwrite addr %x,length %d\r\n",addrCur,receiveDataCur);
  80.               //写完之后要把地址恢复到原来的位置
  81.               addrCur = FLASH_APP1_ADDR;
  82.               receiveDataCur = 0;
  83.               //写完之后要退出下载循环并告诉上位机,已经下载完了
  84.               printf("download over\r\n");
  85.                //同时,也要退出下载循环模式
  86.               receiveMode = 0;
  87.               return;
  88.            }
复制代码

 因为lpc1768比较独特的扇区分区,如下
我们要修改地址的定义,现在app代码不能存放在0x08002000位置了,而是存储在0x00003000的位置,我们将012三个扇区当做iap代码的存放区域,并将2号扇区的最后一个位定义成了app固化标志存在的位置,写入固化标志的函数如下
unsigned char iapConfigBuffer[4096];//一个扇区4K
  1. //失败返回1 成功返回0
  2. u8 Iap_Write_Config_Value(u8 value)
  3. {
  4.     u32 i = 0;
  5.     u8 *p;
  6.     p = (u8*)SECTOR_2_START;
  7.     //首先要将第三扇区的数据全部读取到ram里面
  8.     for(i = 0; i < 4096; i++)
  9.     {
  10.        iapConfigBuffer[i] = *p;
  11.        p++;
  12.     }
  13.     //然后检查最后一个数据和我们要设置的数据是否相等

  14.     if(iapConfigBuffer[4095] == value)//相等,不用设置了

  15.     {
  16.        return 0;
  17.     }
  18.     else
  19.     {
  20.        //不等,先擦除第2扇区
  21.        prepare_sector(2,2,100000);
  22.        erase_sector(2,2,100000);
  23.        if(result_table[0] != CMD_SUCCESS)
  24.        {
  25.            return 1;//擦除失败
  26.        }
  27.        //将数组最后一个元素设置为指定值
  28.        iapConfigBuffer[4095] = value;
  29.        prepare_sector(2,2,100000);//根据地址找出应当准备哪一个扇区
  30.        write_data(100000,SECTOR_2_START,(unsigned*)iapConfigBuffer,4096);
  31.        if(result_table[0] != CMD_SUCCESS)
  32.        {
  33.          return 1;
  34.        }
  35.        return 0;
  36.     }
  37. }
复制代码


  擦除一个扇区的时候必须将扇区内容保存下来,所以必须定义一个能存放4096数据的数组,写入的时候先读取,在擦除,防止数据丢失
Flash存放的地址修改成这样
#define APP_CONFIG_ADDR     0X00002FFF //配置地址
#define APP_CONFIG_SET_VALUE    0X55       //设置值
#define APP_CONFIG_CLEAR_VALUE  0XFF       //清零值
#define FLASH_APP1_ADDR     0x00003000     //第一个应用程序起始地址(存放在FLASH)
                                     //保留的空间为IAP使用
  相应的配置就要改成如下
  当然,在main函数中还是之前一样的流程
  而对于app来说,改动的位置是这些
  还有在系统初始化函数SystemInit中的这个
  修改成
#define VECT_TAB_OFFSET  0x3000
  这样基本就能完成了,突然发现,这样app是编译不过去的,原因在于startup_LPC17XX.s文件中的110行有这么一段
该段汇编代码在flash的0x000002fc位置存放了一个0xffffffff,但是app程序从0x00003000启动,是不能操作0x000002fc处的flash的,我们来看看这个位置存放的是什么
  可以看到,这一段是进行flash读保护的,这一段我们可以注释掉了,因为iap部分的启动代码我们没有改啊,iap代码中已经设置了crp,那iap引导的app只要不去修改,crp就是我们在iap中定义了,放心大胆的注释掉吧.
现在我们比一比相对于stm32的iap,lpc1788的iap有啥变化
  •                           flash擦写算法变了
  •                           程序的存储空间变了
  •                           中断向量表的位置变了
  •                           Crpstm32没有的,算是一个新东西
  •                           因为flash的擦写算法变了,所以我们底层接收数据处理数据的方式变了
  综上,协议没变,我们依然可以按照之前的协议使用,那么,之前的上位机还算可以使用的
  对了,该上位机需要下载bin文件,需要在keil中将axf转换成bin文件,设置如下
  Target的user界面
  注意啊,这是我的工程分布,我在工程文件所在目录里面放了一个output目录,axf生成到了output目录中,如果你没有output目录,那么将output删除,设置生成axf的位置和工程文件的位置位于同一目录就可以了


完整的Word格式文档51黑下载地址:
LPC1768 IAP升级.zip (2.07 MB, 下载次数: 6)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 转播转播 分享分享 分享淘帖 顶 踩
回复

使用道具 举报

沙发
yb1988001 发表于 2018-12-10 14:23 | 只看该作者
多谢楼主分享资料
回复

使用道具 举报

板凳
yiwei0397 发表于 2019-3-2 16:13 | 只看该作者
谢谢楼主。很不错的东西!
回复

使用道具 举报

地板
yiwei0397 发表于 2019-3-2 16:14 | 只看该作者
谢谢楼主。很不错的资料!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51黑电子论坛单片机. 联系QQ:125739409;技术交流QQ群582644647

Powered by 单片机教程网

快速回复 返回顶部 返回列表