基于ARM7-LPC2368 的一种简单IAP方法
本帖最后由 tangcdong 于 2012-8-22 23:29 编辑经过一个星期的夜战(下班回家整的)终于把LPC2368单片机在系统升级的程序调试完成,自己做了50次的烧写试验,成功率100%,由于时间的关系就没有再进行测试。
现在把我思路以及实现方法罗列出来给大家,希望对大家有所帮助,同时也希望大家提出宝贵的建议。
在写在系统升级思路前还是先说明一下存储器重映射的功能,以免有些人看的云里雾里。
1、存储器重映射:
由于ARM处理器的存储器结构比较复杂,可能同时存在片内存储器和片外存储器等,他们在存储器映射上的起始地址都不一样,因此ARM内核要访问的中断向量表可能不在0x0000 0000~0x0000 003F地址上,因此采用了存储器重映射来实现将存在与不同地方的中断向量表都映射到0x0000 0000~0x0000 003F地址上。
单片机在每次复位后都会执行从起始地址0x0000 0000开始的跳转指令,至于这条跳转指令以及后面的一些中断跳转指令(共64字节)的来源是可以通过存储器重映射功能改变的。当MAP 1:0设置为二进制10(当然这个值只能在程序运行中更改,可以参考LPC2300技术手册)则中断向量被映射到LPC2368静态RAM即0x4000 0000到0x4000 003F,例如当产生软件中断时内核从0x0000 0008处取出32位的指令,但这32位指令是从静态RAM0x4000 0008提供的。
2、存储器分配:
LPC2214 有512k Flash ROM, 起始地址为0x0000 0000 ,终止地址为0x0007 FFFF。
32k 静态RAM , 起始地址为0x4000 0000 ,终止地址为0x4000 7FFF
(1)、整个ROM 空间分为四个部分:
三个程序区: Boot程序、用户程序、IAP升级程序备份
一个标志区: 用户程序标志
a、 Boot程序地址: 0x0000 0000-- 0x0000 7FFF 0-7扇区 共32k 用于程序升级并判断是否有有效程序并跳转到0x00008000处运行程序
b、 用户程序地址: 0x0000 8000-- 0x00017FFF 8—9扇区 共64k 用户程序
c、 IAP升级程序备份地址:0x0002 8000-- 0x0003 7FFF 12—13扇区 共64k 用于IAP对用户程序进行升级
d、 程序标志地址: 0x0004 8000-- 0x0004 FFFF 16扇区 共32k 保存用户程序是否已经写入标志只有最低四个字节有用。
(2)、RAM分为三个部分:
a、0x4000 0000-0x4000 003F 共64字节 用于中断向量重映射
b、0x4000 0040-0x4000 2FFF 共12K-64 用于Boot程序变量使用
c、0x4000 3000-0x4000 8000 共20K 用于应用程序变量使用
3. 程序更新过程
(1)、加电后先进入0x0000 0000 Boot程序区(此时的相应中断向量取值为0X0000 0000-0X0000 0040中的值)。
(2)、判断是否有升级程序命令,如果有则进行程序升级,如果3S之内没有升级程序命令,判断16扇区(0x0004 8000 -- 0x0004 8003)的值进行相应的跳转或不跳转。
a、(0x0004 8000 -- 0x0004 8003)的值为0x0000 0001,则跳转到地址0x0000 8000处开始执行程序,此地址开始的应用程序(起始代码)中必须把地址0x0000 8000-0x0000 803F中的 内容复制到0x4000 0000-0x4000 003F中,并把MAP 1:0设置为二进制10,当产生中断后程序跳转到地址为0x0000 0000-0x0000 003F中取指令,注意此时相应指令的数据是由RAM区0x4000 0000-0x4000 0040相应地址提供的。
b、(0x0004 8000 -- 0x0004 8003)的值不为0x0000 0001,则等待升级命令。
(3)、用户程序必须包含识别升级命令的代码,当收到升级命令后关中断并把MAP 1:0设置为二进制01,使中断向量不重映射,然后使单片机软件复位跳转到0x0000 0000Boot程序区执行代码(此时的相应中断向量跳转指令的取值又转为0X0000 0000-0X0000 003F中的值)。
下面贴出程序的升级代码(其中包括Boot程序、应用程序以及使用VC6.0编写的下载程序):
注:如有问题可以加入QQ群:235387696进行进一步探讨。 补充:如果要运用到实际项目中需改进两点:1、BOOT的程序可以不用UCOSII实时操作系统,可以简化代码。2、当代码全部下载到备份区时赋给标志另一个值如0X0000FFFF,表明代码从上位机下载完毕,下一步就是把备份代码拷贝到应用程序中,如果这时掉电的话,在下次启动的时候判断该标志位为0X0000FFFF,则把备份区代码拷贝到应用程序区去,接着运行应用程序,这样一来在升级中不管何时掉电都能够保证程序运行正常。 谢谢!正研究STM32L-IAP. 32MCU 发表于 2012-9-7 13:00 static/image/common/back.gif
谢谢!正研究STM32L-IAP.
呵呵,我也正在研究STM32基于Crotex-M3内核。{:smile:} 我在武汉。要是同城的就好了。 MARK........ mark
{:victory:} mark
too{:handshake:} 非常好的帖子,好好研究一下,争取能够用上! mark学习 虽没细看 但是写的非常好 number007cool 发表于 2013-4-9 00:01 static/image/common/back.gif
虽没细看 但是写的非常好
呵呵,我短信息发送不了,有问题多多交流啊! 你有ads下面的应用程序么
你的boot和app的mdk版本下载试过可以用
但是我把之前ads下的程序按照你的思路修改地址 然后被boot下载进去跑不起来
另:上位机有没有后续版本可以选择指定路劲的bin文件 可以记住bin路径等等 ~~~ number007cool 发表于 2013-4-16 12:46 static/image/common/back.gif
你有ads下面的应用程序么
你的boot和app的mdk版本下载试过可以用
呵呵,用ADS也一样的,只要设置好地址就可以了,ADS我没怎么用,不知道要不要写分散加载文件。上位机软件的话暂时也没有时间去弄,具体要用的时候可以去优化一下。 好像应用程序中不用把“地址0x0000 8000-0x0000 803F中的 内容复制到0x4000 0000-0x4000 003F中,并把MAP 1:0设置为二进制10”
应为boot程序中也有中断向量表,放在0到3f地址中,应用程序中断的时候,跳到boot程序的向量表貌似也可以~~~~ number007cool 发表于 2013-4-17 09:25 static/image/common/back.gif
好像应用程序中不用把“地址0x0000 8000-0x0000 803F中的 内容复制到0x4000 0000-0x4000 003F中,并把MAP ...
那样子不行吧,boot与应用程序的中断向量表是独立的,你应用程序使用boot中断向量不是乱透了。{:sad:} tangcdong 发表于 2013-4-17 10:10 static/image/common/back.gif
那样子不行吧,boot与应用程序的中断向量表是独立的,你应用程序使用boot中断向量不是乱透了。...
;/*****************************************************************************
;* startup.s: startup file for NXP LPC230x Family Microprocessors
;*
;* Copyright(C) 2006, NXP Semiconductor
;* All rights reserved.
;*
;* History
;* 2006.09.01ver 1.00 Prelimnary version, first Release
;*
;*****************************************************************************/
PRESERVE8
;/*
; *The STARTUP.S code is executed after CPU Reset. This file may be
; *translated with the following SET symbols. In uVision these SET
; *symbols are entered under Options - ASM - Define.
; *
; *REMAP: when set the startup code initializes the register MEMMAP
; *which overwrites the settings of the CPU configuration pins. The
; *startup and interrupt vectors are remapped from:
; * 0x00000000default setting (not remapped)
; * 0x40000000when RAM_MODE is used
; *
; *RAM_MODE: when set the device is configured for code execution
; *from on-chip RAM starting at address 0x40000000.
; */
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
;// <h> Stack Configuration (Stack Sizes in Bytes)
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
;// </h>
UND_Stack_SizeEQU 0x00000000
SVC_Stack_SizeEQU 0x00000100
ABT_Stack_SizeEQU 0x00000000
FIQ_Stack_SizeEQU 0x00000000
IRQ_Stack_SizeEQU 0x00000120 ;每层嵌套需要9个字堆栈,允许8层嵌套
USR_Stack_SizeEQU 0x00000200
Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
StackUsr EQU Stack_Mem+USR_Stack_Size
Stack_Top EQU Stack_Mem + Stack_Size
EXPORTStackUsr ;声明为外部标号,供IRQ.S调用。
;// <h> Heap Configuration
;// <o>Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>
Heap_Size EQU 0x00000001
AREA HEAP, NOINIT, READWRITE, ALIGN=3
Heap_Mem SPACE Heap_Size
; Area Definition and Entry Point
;Startup Code must be linked first at Address at which it expects to run.
;引入的外部标号在这声明
IMPORTFIQ_Exception ;快速中断异常处理程序
IMPORT__main ;C语言主程序入口
IMPORTTargetResetInit ;目标板基本初始化
IMPORTSoftwareInterrupt ;软件中断的处理函数
EXPORTVectors
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
;Mapped to Address 0.
;Absolute addressing mode must be used.
;Dummy Handlers are implemented as infinite loops which can be modified.
;;中断向量表
;;对于1.未定义指令 2.预取指中止 3.数据中止三种异常不做处理
;;
ENTRY
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
; LDR PC, IRQ_Addr
LDR PC, ; Vector from VicVectAddr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SoftwareInterrupt
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0xB9206E28 ; Reserved Address
;IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
;SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
;IRQ_Handler B IRQ_Handler
FIQ_Handler
STMFD SP!, {R0-R3, LR}
BL FIQ_Exception
LDMFD SP!, {R0-R3, LR}
SUBS PC,LR,#4
; Reset Handler
EXPORTReset_Handler
Reset_Handler
; Setup Stack for each mode
; LDR R0, =Stack_Top
;Enter Undefined Instruction Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
; MOV SP, R0
; SUB R0, R0, #UND_Stack_Size
;Enter Abort Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
; MOV SP, R0
; SUB R0, R0, #ABT_Stack_Size
;Enter FIQ Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
; MOV SP, R0
; SUB R0, R0, #FIQ_Stack_Size
;Enter IRQ Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
; MOV SP, R0
; SUB R0, R0, #IRQ_Stack_Size
;Enter Supervisor Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
; MOV SP, R0
; SUB R0, R0, #SVC_Stack_Size
;Enter User Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_USR
; MOV SP, R0
; SUB SL, SP, #USR_Stack_Size
MOV R8,#0x40000000
LDR R9,=Vectors
LDMIA R9!,{R0-R7}
STMIA R8!,{R0-R7}
LDMIA R9!,{R0-R7}
STMIA R8!,{R0-R7}
;//使用remap ram
;LDR R8,=MEMMAP
LDR R8,=0xE01FC040
MOV R9,#0x02
STR R9,
; IMPORT TargetResetInit
BL TargetResetInit ;在target.c文件中
; Enter the C code
; IMPORT__main
LDR R0, =__main
BX R0
; User Initial Stack & Heap
;;函数说明参考RV_CC.PDF文件P291
;;function:__user_initial_stackheap
;;description:初始化堆栈(stack)和堆(heap),函数采用双存储器区域。
;;parameter:r0,sp,r2
;;return value:r0--堆的基址(heap base in r0)
;;r1--堆栈基址,堆栈区域的最高地址
;;r2--堆的限制地址(heap limit in r2)
;;r3--堆栈限制地址,堆栈区域的最低地址
;;
AREA |.text|, CODE, READONLY
IMPORT__use_two_region_memory ;select memory model of two memory region
EXPORT__user_initial_stackheap
__user_initial_stackheap
LDR R0, =Heap_Mem
LDR R1, =(Stack_Mem + USR_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
END
比较了你的keil下的应用程序与正常情况下的程序,有几点比较奇怪:
1、你的应用程序的启动代码的堆栈初始化部分被注释掉了
2、Heap_Size EQU 0x00000001这个地方为什么是1 我看其他的网上下载的例程是0
而且__user_initial_stackheap貌似也没有被执行
设置中不同的是:
rom其实地址为0x8000
ram起始地址为0x40003000
这个还是可以理解的 number007cool 发表于 2013-4-17 11:00 static/image/common/back.gif
;/*****************************************************************************
;* startup.s: st ...
heap堆基本上不用所以你设置成0或1不影响,那个初始化没用。 number007cool 发表于 2013-4-17 11:00 static/image/common/back.gif
;/*****************************************************************************
;* startup.s: st ...
__user_initial_stackheap是编译器调用的,当运行到__main时并不是C代码中的main,而是编译器提供的专门用于启动用户程序的库函数,负责完成库函数的初始化和初始化应用程序执行环境,其中会调用__user_initial_stackheap以初始化C代码运行需要的堆栈,初始化运行完最后自动跳转到main()执行。
我把我的一个mdk下的应用程序的工程传上来给你看下
感觉REMAP那个寄存器不管怎么设置,程序中断(定时器、ad转换)都可以用。
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control
IF :DEF:REMAP00000
LDR R0, =MEMMAP
IF :DEF:EXTMEM_MODE
MOV R1, #3
ELIF :DEF:RAM_MODE
MOV R1, #2
ELSE
MOV R1, #1
ENDIF
STR R1,
ENDIF
而且在跳到main之前加上你的那个拷贝向量表到0x40000000反而会使程序的中断无法使用
把几个立即数全部改成3或2或1似乎都可以使用 number007cool 发表于 2013-4-17 15:14 static/image/common/back.gif
把几个立即数全部改成3或2或1似乎都可以使用
我的keil是V3版本你的项目我打不开,你在配置ASM->DEFINE里声明RAM_INTVEC、REMAP00000与RAM_MODE没有啊 ? tangcdong 发表于 2013-4-17 16:02 static/image/common/back.gif
我的keil是V3版本你的项目我打不开,你在配置ASM->DEFINE里声明RAM_INTVEC、REMAP00000与RAM_MODE没有啊...
没有定义 本帖最后由 number007cool 于 2013-4-17 16:16 编辑
MOV R1, #3
ELIF :DEF:RAM_MODE
MOV R1, #2
ELSE
MOV R1, #1
我吧这里的三个赋给R1的数全部改成1,或者全部改成2 ,3貌似都可以使用
中断也可以进去
这是最奇怪的地方
这个工程总共两个文件
要不你建个工程试下 {:smile:} number007cool 发表于 2013-4-17 16:13 static/image/common/back.gif
MOV R1, #3
ELIF :DEF:RAM_MODE
MOV R1, #2
你都没有声明你改那几个数据有什么用啊?IF :DEF:REMAP00000与c语言里#if define REMAP00000类似 你REMAP00000都没有定义这段代码就没什么意义了。 没有声明 就满足最后一个else啊
就是ELSE
MOV R1, #1
就是写入MEMMAP
的值是1!
而且这里改成2和3似乎也可以正常使用
你联系方式多少 电话也行 number007cool 发表于 2013-4-17 17:19 static/image/common/back.gif
没有声明 就满足最后一个else啊
就是ELSE
MOV R1, #1
QQ498502983 电话15857458573 tangcdong 发表于 2013-4-17 18:02 static/image/common/back.gif
QQ498502983 电话15857458573
哥们还在不我的那个iap弄成功了 但是app中压根么有搞向量表拷贝和地址重映射 也能进中断 能否交流下 number007cool 发表于 2013-5-16 10:32 static/image/common/back.gif
哥们还在不我的那个iap弄成功了 但是app中压根么有搞向量表拷贝和地址重映射 也能进中断 能否 ...
那你那个中断进的可能是Boot的中断吧! tangcdong 发表于 2013-5-16 12:59 static/image/common/back.gif
那你那个中断进的可能是Boot的中断吧!
boot已经跳转到app,而且根据现象来看也不是boot的中断而是app的 定时器0.zip有木马! jlian168 发表于 2013-5-17 15:20 static/image/common/back.gif
定时器0.zip有木马!
????什么情况? tangcdong 发表于 2013-5-18 08:04 static/image/common/back.gif
????什么情况?
AVAST V6 say:定时器0.zip有木马! jlian168 发表于 2013-5-20 10:33 static/image/common/back.gif
AVAST V6 say:定时器0.zip有木马!
电脑应该是中招了
以前用卡巴杀了好多次
用一段时间后就又出来了 我在另外的机子上试貌似提示的不是这种病毒 没影响正常使用 没怎么管
目前用的这台太慢 卡巴也卸了 目前仍处于裸奔状态~ 在你的app的工程中,指定ram的起始地址是从0x4000 3000
长度是0x5000,那么app的代码部分:
MOV R8,#0x40000000
LDR R9,=Vectors
LDMIA R9!,{R0-R7}
STMIA R8!,{R0-R7}
LDMIA R9!,{R0-R7}
STMIA R8!,{R0-R7}
;//使用remap ram
;LDR R8,=MEMMAP
LDR R8,=0xE01FC040
MOV R9,#0x02
STR R9,
应该改成:
MOV R8,#0x40003000
要不拷贝的中断向量表还是从bootloader的向量表拷贝而来
我是这样理解的,您看呢? number007cool 发表于 2013-5-20 11:14 static/image/common/back.gif
在你的app的工程中,指定ram的起始地址是从0x4000 3000
长度是0x5000,那么app的代码部分:
MOV R8,#0x4 ...
不是这样的,当你把中断向量映射成RAM的话,每次中断入口地址都是从0x4000 0000开始的64字节单元中取数据的,所以你要把中断向量放到0x4000 0000开始的64字节中。 number007cool 发表于 2013-5-20 11:14 static/image/common/back.gif
在你的app的工程中,指定ram的起始地址是从0x4000 3000
长度是0x5000,那么app的代码部分:
MOV R8,#0x4 ...
补充:平时你不映射的话是从flash取中断入口地址,而它是在0x0000 0000开始的64个字节中的。 那请问 在app工程中限定ram地址空间范围的意义又在哪里呢 ? tangcdong 发表于 2013-5-20 13:20 static/image/common/back.gif
补充:平时你不映射的话是从flash取中断入口地址,而它是在0x0000 0000开始的64个字节中的。 ...
嗯赞同
有一点我觉得很重要的,想和你交流下
汇编中跳转到_main的指令要用相对跳转指令,而不是绝对跳转
我第一次在基于IAR的arm7上搞IAP 就是因为app的这条指令卡住了一个月 ,最后程序改成功了,改了一个月就是改了一条指令
相对跳转:
LDR R0, =__main
BX R0
绝对跳转:
B _main
app中要使用前者进行跳转,否则程序会跑飞 楼主,请问这个RAM怎么分区的,可以自己想存哪里自己划分吗 MARK........ 多谢lz分享 这帖子很有价值啊 number007cool 发表于 2013-5-20 14:42 static/image/common/back.gif
嗯赞同
有一点我觉得很重要的,想和你交流下
BX 指令是跳转加指令集切换(ARM与Thumb指令的切换),B指令直接跳转。 snoweaglemcu 发表于 2013-5-20 22:14 static/image/common/back.gif
这帖子很有价值啊
奉献给有用的人吧! number007cool 发表于 2013-5-20 13:25 static/image/common/back.gif
那请问 在app工程中限定ram地址空间范围的意义又在哪里呢 ?
首先起始的64字节肯定要分配给中断向量吧;其次是分配给Boot程序,这里的RAM空间在Boot运行完之后基本上也没什么用,当程序要升级的时候是软件复位的,这段RAM空间又重新初始化了(即使在应用程序中被利用了也不影响),感觉这段空间应该也可以和应用程序合并在一起使用,目前我还没有想到会有什么影响,不过分开肯定是可以的(为了安全起见我就直接分开了);最后是分配给应用程序,这就不用多说了。 由于片子ram空间不够,我让lwip的 app和bootram空间重叠了一部分 ,app运行了一晚上就死掉了
假如让app与boot 的ram完全重叠 那么下载成功后无法运行 number007cool 发表于 2013-5-21 09:46 static/image/common/back.gif
由于片子ram空间不够,我让lwip的 app和bootram空间重叠了一部分 ,app运行了一晚上就死掉了
假如让app ...
呀,我最近也在移植LWIP,在stm32上面。你用的是哪个版本的啊? 我用的是别人的例程
版本可能比较老 很好!谢谢! 谢谢楼主分享,最近正在研究IAP,学习的不透彻遇到好多问题 好东西,赶紧研究下,之前看的事STM32
页:
[1]