目录
4.3、LPC2478的bootloader程序操作注意事项
这次主要对STM32F103/Keil和LPC2478/IAR加了一个IAP在线升级功能,但是选择记录LPC2478/IAR,首先是因为自己对于IAR编译器没有Keil的熟悉,所以印象更加深刻,其次就是STM32F103/Keil下的IAP升级的资料实在是太多了,没有什么异常的情况,而IAR相对而言资料较少自己是根据STM32/Keil的思路一步步走下来的。
主要记录一下自己的思路,bootloader和App代码都不写了。
LPC-2478STK+IAR+JINK
单片机只有一个程序时,可以直接从起始地址开始运行;但当系统中有两个程序时,例如带bootloader的系统,则应用程序的运行需要通过bootloader跳转,和bootloader相比,应用程序(App)的地址和中断向量表地址都发生改变,如何告诉编译器来分配bootloader和应用程序在flash中的地址以及如何告诉CPU中断表向表的位置。
在编译器的选项中看到有后缀为icf文件、后缀为ddf文件、后缀为board文件、后缀为flash文件,但是这些文件中,跟IAP功能相关的只有icf文件,其他的文件在此篇中都不重要。
程序的项目文件在此篇中也不重要
文件配置目录是:Options->Linker->Config->Linker configuration file
需要换成自定义的icf文件需要勾选Override default
- /*###ICF### Section handled by ICF editor, don't touch! ****/
- /*-使用过应用层的会发现,这个a_v1_0.xml就是点击配置文件Edit出现的界面配置,我们不需要动它,它也无关紧要-*/
- /* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
- /*-中断向量表的起始地址,主要设置参数-*/
- define symbol __ICFEDIT_intvec_start__ = 0x00000000;
- /*-Memory Regions-*/
- /*-程序ROM的起始地址,主要设置参数-*/
- define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
- define symbol __ICFEDIT_region_ROM_end__ = 0x0004FFFF;
- /*-程序RAM的起始地址,主要设置参数-*/
- define symbol __ICFEDIT_region_RAM_start__ = 0x40000000;
- define symbol __ICFEDIT_region_RAM_end__ = 0x4000FFDF;
- /*-Sizes-*/
- /*-程序的堆栈大小,一般无需改动 -*/
- define symbol __ICFEDIT_size_cstack__ = 0x400;
- define symbol __ICFEDIT_size_svcstack__ = 0x100;
- define symbol __ICFEDIT_size_irqstack__ = 0x100;
- define symbol __ICFEDIT_size_fiqstack__ = 0x40;
- define symbol __ICFEDIT_size_undstack__ = 0x10;
- define symbol __ICFEDIT_size_abtstack__ = 0x10;
- define symbol __ICFEDIT_size_heap__ = 0x2000;
- /**** End of ICF editor section. ###ICF###*/
- /* CRP区块,主要用于代码保护功能,将ROM空间最大化,一般无需改动 */
- define symbol __CRP_start__ = 0x000001FC;
- define symbol __CRP_end__ = 0x000001FF;
- /* 下面的一般无需改动 */
- /* Memory used by RealMonitor*/
- define symbol __RM_start__ = 0x40000040;
- define symbol __RM_end__ = 0x4000011F;
-
- define memory mem with size = 4G;
- define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__] - mem:[from __CRP_start__ to __CRP_end__];
- define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__] - mem:[from __RM_start__ to __RM_end__];
- define region CRP_region = mem:[from __CRP_start__ to __CRP_end__];
-
- define symbol __region_USB_DMA_RAM_start__ = 0x7FD00000;
- define symbol __region_USB_DMA_RAM_end__ = 0x7FD03FFF;
- define region USB_DMA_RAM_region= mem:[from __region_USB_DMA_RAM_start__ to __region_USB_DMA_RAM_end__];
-
- define symbol __region_EMAC_DMA_RAM_start__ = 0x7FE00000;
- define symbol __region_EMAC_DMA_RAM_end__ = 0x7FE03FFF;
- define region EMAC_DMA_RAM_region= mem:[from __region_EMAC_DMA_RAM_start__ to __region_EMAC_DMA_RAM_end__];
-
- define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
- define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
- define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
- define block FIQ_STACK with alignment = 8, size = __ICFEDIT_size_fiqstack__ { };
- define block UND_STACK with alignment = 8, size = __ICFEDIT_size_undstack__ { };
- define block ABT_STACK with alignment = 8, size = __ICFEDIT_size_abtstack__ { };
- define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
-
- initialize by copy { readwrite };
- do not initialize { section .noinit };
- do not initialize { section USB_DMA_RAM };
- do not initialize { section EMAC_DMA_RAM };
-
- place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
-
- place in ROM_region { readonly };
- place in RAM_region { readwrite,
- block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
- block UND_STACK, block ABT_STACK, block HEAP };
- place in USB_DMA_RAM_region
- { section USB_DMA_RAM };
- place in EMAC_DMA_RAM_region
- { section EMAC_DMA_RAM };
- place in CRP_region { section .crp };
所以说,我们在icf文件中需要设置几个参数:
1、设置中断向量表的起始地址,需要重定义到应用程序的地址0x00010000上。
define symbol __ICFEDIT_intvec_start__ = 0x00010000;
2、设置ROM的起始地址,需要重定义到应用程序的地址0x00010040上。
存储器重新映射的部分允许在不同模式下处理中断,它包括中断向量区(32 字节)和额外的 32 字节,总共是 64 字节,这便于跳转到较远物理地址的中断处理程序。重新映射的代码位置与地址 0x0000 0000~0x0000 003F 重叠。位于 Flash 存储器中的典型用户程序可以将整个 FIQ 处理程序放置在地址 0x0000 001C 而不需要考虑存储器的边界。包含在SRAM、外部存储器和 Boot ROM 中的向量必须含有跳转到实际中断处理程序的分支或者其它执行跳转到中断处理程序的指令.
define symbol __ICFEDIT_region_ROM_start__ = 0x00010040;
3、设置RAM的起始地址,需要重定义到应用程序的地址0x40000040上。
define symbol __ICFEDIT_region_RAM_start__ = 0x40000040;
设置原因是因为LPC2478的中断向量表地址不像STM32一样可以直接赋值,它的中断向量表只有几个固定位置。
4、应用程序(App)添加:
- memcpy((char *)0x40000000, (char*)0x00010000,16*4);
- //中断向量表设置在RAM中
- MEMMAP = 0x02;
5、编译前选择自己修改过的icf文件,烧写即可
第一句话就是IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml
使用过应用层的会发现,这个a_v1_0.xml就是点击配置文件Edit出现的界面配置,我们不需要动它,它也无关紧要
- <?xml version="1.0" encoding="UTF-8"?>
-
- <icf_annotations version="1.0">
- <tab name="Vector Table">
- <item name=".intvec start" type="Number">
- <symbol>__ICFEDIT_intvec_start__</symbol>
- <tooltip>The vector table start address</tooltip>
- </item>
- </tab>
-
- <tab name="Memory Regions">
- <itemHeaders>
- <header>Start:</header>
- <header>End:</header>
- </itemHeaders>
- <item name="ROM" type="Range">
- <symbol_1>__ICFEDIT_region_ROM_start__</symbol_1>
- <symbol_2>__ICFEDIT_region_ROM_end__</symbol_2>
- <tooltip_1>The start address of the ROM region</tooltip_1>
- <tooltip_2>The end address of the ROM region</tooltip_2>
- </item>
- <item name="RAM" type="Range">
- <symbol_1>__ICFEDIT_region_RAM_start__</symbol_1>
- <symbol_2>__ICFEDIT_region_RAM_end__</symbol_2>
- <tooltip_1>The start address of the RAM region</tooltip_1>
- <tooltip_2>The end address of the RAM region</tooltip_2>
- </item>
- </tab>
-
- <tab name="Stack/Heap Sizes">
- <item name="CSTACK" type="Number">
- <symbol>__ICFEDIT_size_cstack__</symbol>
- <tooltip>The size of the user stack</tooltip>
- </item>
- <item name="SVC_STACK" type="Number">
- <symbol>__ICFEDIT_size_svcstack__</symbol>
- <tooltip>The size of the supervisor stack</tooltip>
- </item>
- <item name="IRQ_STACK" type="Number">
- <symbol>__ICFEDIT_size_irqstack__</symbol>
- <tooltip>The size of the stack for the interrupt handler</tooltip>
- </item>
- <item name="FIQ_STACK" type="Number">
- <symbol>__ICFEDIT_size_fiqstack__</symbol>
- <tooltip>The size of the stack for the fast interrupt handler</tooltip>
- </item>
- <item name="UND_STACK" type="Number">
- <symbol>__ICFEDIT_size_undstack__</symbol>
- <tooltip>The size of the stack for the undefined instruction handler</tooltip>
- </item>
- <item name="ABT_STACK" type="Number">
- <symbol>__ICFEDIT_size_abtstack__</symbol>
- <tooltip>The size of the stack for the data abort handler</tooltip>
- </item>
- <item name="HEAP" type="Number">
- <symbol>__ICFEDIT_size_heap__</symbol>
- <tooltip>The size of the heap</tooltip>
- </item>
- </tab>
- </icf_annotations>
在Options->Debugger->Setup->Device description file有ddf文件的信息,它也无关紧要
其中LPC2478.ddf文件内容
-
- ;; Memory information ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Used to define address zones within the ARM address space (Memory).
- ;;
- ;; Name may be almost anything
- ;; AdrSpace must be Memory
- ;; StartAdr start of memory block
- ;; EndAdr end of memory block
- ;; AccType type of access, read-only (R), read-write (RW) or SFR (W)
-
- [Memory]
- ;; Name AdrSpace StartAdr EndAdr AccType Width
- Memory = Periph1 Memory 0x3FFFC000 0x3FFFFFFF W
- Memory = ExtDev Memory 0x80000000 0x83FFFFFF W
- Memory = ExtMem Memory 0xA0000000 0xDFFFFFFF RW
- Memory = Periph2 Memory 0xE0000000 0xE01FFFFF W
- Memory = Periph3 Memory 0xFFE00000 0xFFFFFFFF W
- Memory = Flash Memory 0x00000000 0x0007FFFF R
- Memory = RAM Memory 0x40000000 0x4000FFFF RW
- Memory = RAMUSB Memory 0x7FD00000 0x7FD03FFF RW
- Memory = RAMETH Memory 0x7FE00000 0x7FE03FFF RW
- Memory = ROM Memory 0x7FFFE000 0x7FFFFFFF R
-
- TrustedRanges = true
- UseSfrFilter = true
-
- [SfrInclude]
- File = iolpc2470.ddf
就是标记了一下内存的名字,起始地址,结束地址,访问类型,以及引用iolpc2470.ddf,都是一些无需改动的东西。这个就有点类似于linux的树一样,Memory下的是LPC2478特有的属性,其他的都使用iolpc2470即可
其中iolpc2470.ddf文件内容,太长了,主要是对寄存器的位地址进行定义,截取部分:
-
- sfr = "PLLCON" , "Memory", 0xE01FC080, 4, base=16
- sfr = "PLLCON.PLLE" , "Memory", 0xE01FC080, 4, base=16, bitRange=0-0
- sfr = "PLLCON.PLLC" , "Memory", 0xE01FC080, 4, base=16, bitRange=1-1
-
- sfr = "PCLKSEL0" , "Memory", 0xE01FC1A8, 4, base=16
- sfr = "PCLKSEL0.PCLK_WDT" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=0-1
- sfr = "PCLKSEL0.PCLK_TIMER0" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=2-3
- sfr = "PCLKSEL0.PCLK_TIMER1" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=4-5
- sfr = "PCLKSEL0.PCLK_UART0" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=6-7
- sfr = "PCLKSEL0.PCLK_UART1" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=8-9
- sfr = "PCLKSEL0.PCLK_PWM0" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=10-11
- sfr = "PCLKSEL0.PCLK_PWM1" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=12-13
- sfr = "PCLKSEL0.PCLK_I2C0" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=14-15
- sfr = "PCLKSEL0.PCLK_SPI" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=16-17
- sfr = "PCLKSEL0.PCLK_RTC" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=18-19
- sfr = "PCLKSEL0.PCLK_SSP1" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=20-21
- sfr = "PCLKSEL0.PCLK_DAC" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=22-23
- sfr = "PCLKSEL0.PCLK_ADC" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=24-25
- sfr = "PCLKSEL0.PCLK_CAN1" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=26-27
- sfr = "PCLKSEL0.PCLK_CAN2" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=28-29
- sfr = "PCLKSEL0.PCLK_ACF" , "Memory", 0xE01FC1A8, 4, base=16, bitRange=30-31
在Options->Debugger->Download->Use flash loader有board file的文件信息,它也无关紧要
其中board文件内容:
- <?xml version="1.0" encoding="iso-8859-1"?>
-
- <flash_board>
- <pass>
- <loader>$TOOLKIT_DIR$\config\flashloader\NXP\FlashNXPLPC24K_CortexLL.flash</loader>
- <range>CODE 0x00000000 0x00005FFF</range>
- </pass>
- </flash_board>
主要内容就是引用FlashNXPLPC24K_CortexLL.flash文件,以及规定程序的大小
其中flash文件内容,这个就是flash的烧写算法,不关注,STM32的IAP也没有在Flash的烧写算法上做什么改动:
- <?xml version="1.0" encoding="iso-8859-1"?>
-
- <flash_device>
- <exe>$TOOLKIT_DIR$\config\flashloader\NXP\FlashLayout1RAM4K_Cortex.out</exe>
- <page>512</page>
- <block>6 0x1000</block>
- <flash_base>0x00000000</flash_base>
- <macro>$TOOLKIT_DIR$\config\flashloader\NXP\LPC1xxx.mac</macro>
- <online>1</online>
- <aggregate>1</aggregate>
- <args_doc>[--clock] Passes the clock frequency to the flash loader;
- value is the CPU clock speed in kHz. The default clock
- frequency value is 14,746 kHz.</args_doc>
- </flash_device>
跟IAR编译器相关的配置文件大概就这些。
((void(*)())0x0)();
- //定义函数指针
- void (*UserProgram)();
- //赋值App程序地址AppAddr
- UserProgram = (void (*)()) (AppAddr);
- //跳转
- (*UserProgram)();
1、写入应用程序到Flash时,需要从RAM写入到Flash,否则IAP写入会报错,状态码为SRC_ADDR_NOT_MAPPED,描述源地址没有映射到存储器映射中。计数值必须考虑其可用性
2、如果源地址不是4的倍数,将会报错,状态码为SRC_ADDR_ERROR,描述目标地址的边界错误,比如你接收了数据,但是接收地址是4的倍数,但是有效程序地址是从下标1开始的,那么你写入将会报错。
3、写入Flash时,写入字节的数目必须是按照。应当为 256 | 512 | 1024 | 4096。但是最后一次一般都会出现不是,所以在最后一次写入时需要补全。
4、每次新写一个扇区时,必须将其先清空。
1、App程序能正常运行,但是无法进入中断,App程序开头添加,具体描述请见上文:
- memcpy((char *)0x40000000, (char*)0x00010000,16*4);
- //中断向量表设置在RAM中
- MEMMAP = 0x02;
2、App程序无法运行,需要重新编辑编译前的icf文件,重定义中断向量表和RAM的起始地址,具体描述请见上文:
- /*-Specials-*/
- define symbol __ICFEDIT_intvec_start__ = 0x00010000;
- /*-Memory Regions-*/
- define symbol __ICFEDIT_region_ROM_start__ = 0x00010040;
- define symbol __ICFEDIT_region_ROM_end__ = 0x0004FFFF;
- define symbol __ICFEDIT_region_RAM_start__ = 0x40000040;
- define symbol __ICFEDIT_region_RAM_end__ = 0x4000FFDF;
3、 IAR生成bin文件:Options->Output Converter-->Output 下的Output format格式选择Raw binary,Output file将Override default勾选
主要是对于IAR编译器的熟悉加深,整个过程也是比较轻松的,因为只需要按照STM32的思路来就好了,就是
耽误了一点时间的就是因为LPC2478的芯片不熟悉,不知道需要定义当前中断向量处于的位置需要寄存器设置。