昨天晚上想着MDK调试LPC的时候貌似是在FLASH里面调试的,还是有些局限性的,比如只能打2个硬件断点,每次都要下载等。今天在网上搜了一下怎样在RAM里面调试的方法总结一下,记录下来。很可能漏洞百出,但现在就是接受拍砖的时期,希望大虾不吝墨宝。
首先就是关于分散加载:这个名词其实我也只有在周立功那里听过,其他的人叫什么我也不知道,姑且我也跟着周工叫吧。“分散加载”顾名思义就是将数据分散的加载到空间里去。数据是什么?数据指的是段,一般嵌入式系统编译器会在逻辑上把程序的代码和数据描述分成如下几个部分:
BSS段:通常是用来存放未初始化的全局变量的一片内存区域
数据段:存放程序中已经初始化的全局变量的一片内存区域
代码段:存放程序执行代码的,这个区域通常也会存放一写只读的表,字符串,常量等
堆 :是指在内存中预留出一片区域来给程序动态分配内存用的。
栈 :用来存放局部变量和函数调用时传递参数的。
这些有着共同属性的数据集合就叫做段。多讲两句关于栈,栈的主要作用是在CPU进行函数调用时用来开辟零时变量和传递参数用的。调用的时候先将PC存入LR中,然后如果参数大于4个就将多出来的参数压入栈中,然后跳转到函数入口,执行函数,返回时先出栈,然后将LR中存放的现场地址回写到PC中。ARM有7种模式,用户模式和系统模式共用R13也就是SP-堆栈指针。下面是MDK自带的启动代码定义栈大小:
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000008
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000080
USR_Stack_Size EQU 0x00000400
回归正题,分散加载就是要将不同的段加载到不同的空间地址映射上。很容易理解,比如代码段,那肯定是加载到FLASH上也就映射的0x0地址上。再比如BSS和数据段就是加载在RAM的某个位置。再具体的细节我也不太清楚了,这里留个记号,下次找了资料再详细的学习一下分散加载。今天只要把怎么在RAM中调试的一些基本原理了解一下就OK了。 很显然,在RAM里面调试就是要把分散加载到ROM里面的代码段也放到RAM中来,然后跳转到RAM里面的入口来执行程序。几个参数在下面的设置中讲解。
先还是说下怎么设置在FLASH中调试,按如下图设置:
按着两个页面设置好应该就可以在FLASH中调试了。
接下来修改到RAM里面:
首先,在Option for Target中选Target标签页,看到下面有:
IROM1和IRAM1,这两个就是定义了FLASH空间和RAM的起始地址和大小。
将他们改为0x4000000 0x2000 和 0x40002000 0x2000 表示ROM的空间和RAM的空间都是8K字节,RAM在ROM的后面。至于怎么分配就看你代码和RAM的比例了。
第二步:在工程目录下建一个后缀为ini的文本,然后debug标签页按下图设置。
在ini文件中写入如下内容:
FUNC void Setup (void) {
PC = 0x40000000;
}
Setup();
LOAD lpc2132.axf INCREMENTAL
g, main
注意上面的lpc2132.axf是目标可执行文件,把它替换成你自己工程中生成文件的名字。
第三步,在Startup.s文件上右键找到option选项,在define 中填入RAM_MODE REMAP
起始这个步骤就是添加一个宏定义,可以看到编译参数里面增加了–pd “REMAP”。再看到汇编代码里面有这么一段:
MEMMAP EQU 0xE01FC040 ; Memory Mapping Control
IF :DEF:REMAP
LDR R0, =MEMMAP
IF :DEF:EXTMEM_MODE
MOV R1, #3
ELIF :DEF:RAM_MODE
MOV R1, #2
ELSE
MOV R1, #1
ENDIF
STR R1, [R0]
ENDIF
Memory Mapping Control:这个就是LPC系列ARM的存储器映射,可以将中断向量映射到:FLASH,RAM,和内部引导程序三种地址上。打开这个REMAP就把中断向量映射到了RAM的起始地址上,也就是0x40000000。但我有一点很奇怪,传说LDR PC, [PC, #-0x0FF0]这条语句能计算出中断向量控制器的地址,然后进行跳转。但如果映射到RAM上去了那这个公式还会有用吗?? 这个暂时不考虑,明天在RAM里面调试串口驱动就知道了。
大功告成,接下来就看下成果吧:
可以看出现在PC的地址已经到了RAM空间了。