首页 > 编程知识 正文

keil调试 不全速运行,keil程序怎么调试

时间:2023-05-06 10:36:33 阅读:255719 作者:3848

keil程序在内部RAM调试的基本步骤网上已经有很多了,我就不再赘述,大家可以在网上搜到很多。


但是有些时候内部RAM并不够用,这就需要将程序装入外部RAM中调试,而在这个过程中可能会出现各种各样的问题,在这里我将会把我遇到过的一些问题和需要注意的地方总结一下,希望能够对大家有所帮助。


有错误的地方也希望大神们能够不吝赐教,提前表示感谢···


转载请注明出处:waitig's blog


先介绍下我项目使用的硬件,芯片是LPC1788,外部RAM是MT48LC4M32B2,大小为16M(128Mb X32 SDRAM),之前用的是MT48LC2M32B2,大小为8M,后来发现东西太多,8M不够用了,所以换成了16M的。

在换RAM时也遇到过一些问题,这个在下文中会有介绍。


在外部RAM中调试程序,程序中一定不能有操作外部RAM的代码!


在外部RAM中调试,程序中不要有操作外部RAM的代码,初始化也不要有,包括对RAM相关引脚的操作。

RAM的初始化和引脚的初始化要放到jlink的下载配置文件中,主要是对LPC的寄存器进行相关配置,不要忘了RAM中的读取算法配置。

把我的配置文件贴出来供大家参考一下。

FUNC void PinSel(int p1, int n1, int f1){ _WDWORD(0x4002C000 + (p1 * 32 + n1) * 4, 0x8 | f1);}FUNC void InitSDRAM(void){ int i; PinSel(2,16,1); PinSel(2,17,1); PinSel(2,18,1); PinSel(2,20,1); PinSel(2,24,1); PinSel(2,28,1); PinSel(2,29,1); PinSel(2,30,1); PinSel(2,31,1); for(i = 0; i < 32; i++) PinSel(3,i,1); for(i = 0; i < 21; i++) PinSel(4,i,1); PinSel(4,24,1); PinSel(4,25,1); PinSel(4,30,1); PinSel(4,31,1); /* PCONP |= 1 << 11 */ _WDWORD(0x400FC0C4, 0x04288FDE); // Power On EMC /* EMCCONTROL |= 1 */ _WDWORD(0x2009C000, 0x00000001); // Enable EMC /* EMCDLYCTL */ _WDWORD(0x400FC1DC, 0x00081818); // Config data read delay /* EMCCONFIG */ _WDWORD(0x2009C008, 0x00000000); // Little endian mode /* DYNAMICCONTROL */ _WDWORD(0x2009C020, 0x00000003); // Set normal self refresh mode, normal power mode // CE always HI // Enable clock out // Clock do not stop during idle /* DYNAMICREFRESH */ _WDWORD(0x2009C024, 0x0000001F); // refresh timing /* DYNAMICREADCONFIG */ _WDWORD(0x2009C028, 0x00000001); // read timing /* DYNAMICRP */ _WDWORD(0x2009C030, 0x00000002); // tRP /* DYNAMICRAS */ _WDWORD(0x2009C034, 0x00000003); // tRAS /* DYNAMICSREX */ _WDWORD(0x2009C038, 0x00000005); // tSREX /* DYNAMICAPR */ _WDWORD(0x2009C03C, 0x00000001); // tAPR /* DYNAMICDAL */ _WDWORD(0x2009C040, 0x00000005); // tDAL /* DYNAMICWR */ _WDWORD(0x2009C044, 0x00000003); // tWR /* DYNAMICRC */ _WDWORD(0x2009C048, 0x00000004); // tRC /* DYNAMICRFC */ _WDWORD(0x2009C04C, 0x00000004); // tRFC /* DYNAMICXSR */ _WDWORD(0x2009C050, 0x00000005); // tXSR /* DYNAMICRRD */ _WDWORD(0x2009C054, 0x00000001); // tRRD /* DYNAMICMRD */ _WDWORD(0x2009C058, 0x00000003); // tMRD /* DYNAMICCASRAS0 */ _WDWORD(0x2009C104, 0x00000303); // RAS/CAS Latency /* DYNAMICCONFIG0 */ _WDWORD(0x2009C100, 0x00004500); // Config device type as SDRAM // Config address mapping _sleep_(100); // Wait 100 ms /* DYNAMICCONTROL */ _WDWORD(0x2009C020, 0x00000183); // nop command _sleep_(100); // Wait 100 ms /* DYNAMICCONTROL */ _WDWORD(0x2009C020, 0x00000103); // pre-charge command // /* DYNAMICREFRESH */// _WDWORD(0x2009C024, 0x00000002); // refresh timing _sleep_(100); // Wait 100 ms /* DYNAMICREFRESH */ _WDWORD(0x2009C024, 0x0000001F); // refresh timing /* DYNAMICCONTROL */ _WDWORD(0x2009C020, 0x00000083); // mode command _RDWORD(0xA0000000 | (0x32 << (2 + 2 + 8))); _sleep_(100); // Wait 100 ms /* DYNAMICCONTROL */ _WDWORD(0x2009C020, 0x00000003); // noamal command /* DYNAMICCONFIG0 */ _WDWORD(0x2009C100, 0x00084500); // enable buffer _sleep_(100); // Wait 100 ms}

以上是外部RAM的初始化部分,不要忘了其中的RAM本身的寄存器,在本例中的地址是0xA0000000,寄存器中的各个位数的作用如下图:


(截图自MT48LC4M32B2的datasheet)

其中数据要配置正确,RAM才能正确工作。接下来是对内存保护单元(MPU)的配置,两者结合,就是Jlink对RAM的初始化和配置。


RAM_Debug.ini 的文件如下所示:

INCLUDE MT48LC4M32LFB5.iniInitSDRAM(); // Initialize memoryLOAD ..SDRAM_objuc1788.axf INCREMENTAL // Download program/* RNR */_WDWORD(0xE000ED98, 0x00000000); // Use No.0 MPU/* RBAR */_WDWORD(0xE000ED9C, 0xA0000000); // Set MPU base addr/* RASR */_WDWORD(0xE000EDA0, 0x03000031); // Set MPU size and permission/* SHCSR */// _WDWORD(0xE000ED24, 0x00000100); // Enable memory managemeng fault/* MPU_CONTROL */_WDWORD(0xE000ED94, 0x00000005); // Enable MPU/* VTOR */_WDWORD(0xE000ED08, 0x10000000); // Set vector table offsetSP = _RDWORD(0x10000000); // Set stack pointerPC = _RDWORD(0x10000004); // Set program counter
这样就能像在FLASH中调试一样来在RAM中调试了。

但是,程序中不要出现任何操作RAM的代码!一定记住!


程序装入RAM中起始地址出错

所谓起始地址,就是指程序刚装入RAM中,还没有运行的那个pc地址。
正常情况下,这个地址是指向芯片启动代码的systemiInit()这个函数所在的地址的,但是有些时候这个地址会出错,跑到一个不知道什么地址的地方去。


如下图所示:



我分析出现这个现象的原因是在jlink对RAM的配置方面有问题,也就是对RAM没有配置成功,导致程序没有成功存入RAM中,或者是储存成功,但是读取失败,或者储存读取都有问题。


解决方案就是查看内存中的数据,看是否正确。或者对设备重新上电,对jlink复位后重新调试。


这个问题在我这里偶尔会出现,但重新调试又会消失,所以到目前我也没弄清楚这个问题出现的原因。


程序跑入HardFault_Handler

HardFault_Handler是指指令错误中断,一般是因为程序代码翻译成的汇编代码中出现了错误的指令。

解决这个问题的方法一般是找出错误指令的地址,如果地址是在当前分配的代码段的最开始位置(比如我在分散加载里面将这段代码放在0xA0001000-0XA0002000之间,然后出错指令出现在0xA0001010这个位置);

或者在上个代码段的结束位置(比如我将这段代码放在0xA0001000位置处,上段代码在0xA0000900结束,而出错指令在0xA0000920这个位置);

一般情况下是内存不够用导致的,而且出错的语句一般是向全局变量赋值的语句。因为内存不够用,但是jlink在向RAM中写数据的时候并不知道内存不够,导致后来溢出的数据折返回代码段起始地址,将以前的内容覆盖所导致的。(内存覆盖)


解决这个问题的方法就是换一个大的RAM。


还有一种可能,就是在程序中有操作RAM的代码,这也会导致RAM中内容被修改,出现错误的指令。


程序中途跑飞


上一条中的问题也有可能导致程序中途跑飞,此外还有一种可能就是指针问题。

指针没有正确初始化,使用了未初始化的指针,或者是指针没有正确回收,导致出现野指针,是最常见的,也是最容易导致程序跑飞的原因。出现问题应最先考虑此因素。


排除了以上的因素后,可以根据那些常规方法,比如查看LR寄存器的值,找到出现问题的语句等方法来查找具体原因。


更换新外部RAM时要注意的问题


更换新RAM之前先看RAM的手册和芯片的手册,看清楚使用的芯片支持不支持新的RAM,我就因为没看清楚手册导致买了芯片不支持的RAM,既费钱又费力。。。。

芯片user manul上一般都有一个表,表中就是它所支持的所有RAM的类型。如下图:



先查清楚再买芯片,血淋淋的教训。。。


不同的RAM读写规则有些会有所不同,配置也不尽相同,所以在更换新RAM时要仔细读懂RAM的datasheet,对其清楚掌握。

基本上需要配置的最主要参数有以下几个:页大小,外部总线地址映射(行,列,bank),空间大小,位数,读写的算法(在RAM自己的寄存器中配置);

外部总线地址映射要与芯片对应,然后通过上表来确定配置寄存器的值。(程序在RAM中调试要修改jlink的ini文件)



结语:暂时就想到了这些,以上的问题都是我在实际项目中碰到的问题,和一些经验介绍。由于我自己也学艺不精,能力有限,所以难免有错误的地方,希望路过的大神可以帮忙指正。同时声明,仅供参考。


转载请注明出处:waitig's blog


版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。