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.ini

InitSDRAM();                                // Initialize memory

LOAD ..\SDRAM_obj\uc1788.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 offset SP = _RDWORD(0x10000000); // Set stack pointer
PC = _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中内容被改动,出现错误的指令。

  • 程序中途跑飞

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

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

排除了以上的因素后,能够依据那些常规方法,比方查看LR寄存器的值,找到出现故障的语句等方法来查找详细原因。

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

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

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

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

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

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

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

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

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

keil程序在外部RAM中调试的问题总结(个人的一点经验总结)的更多相关文章

  1. Ubuntu系统中初次下载Android源码的一点经验

    这阵子突然心血来潮,想看看android的源代码,所以这一两天晚上都在折腾下载这个东西. (其实在GitHub上可以在线看的,不过不太喜欢在线看,URL附上 https://github.com/an ...

  2. 第49章 在SRAM中调试代码—零死角玩转STM32-F429系列

    第49章     在SRAM中调试代码 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. 在SRAM、FLASH中调试代码的配置方法(附详细步骤)

    因为STM32的FLASH擦写次数有限(大概为1万次),所以为了延长FLASH的使用时间,我们平时调试时可以选择在SRAM中进行硬件调试.除此之外,SRAM 存储器的写入速度比在内部 FLASH 中要 ...

  4. STM32F103_外部RAM用作运存---IS62WV51216

    https://www.cnblogs.com/lilto/p/9548736.html STM32F103_外部RAM用作运存   概述 SRAM的简介 折腾过电脑的朋友都知道,当电脑运行比较卡的时 ...

  5. STM32F103_外部RAM用作运存

    概述 SRAM的简介 折腾过电脑的朋友都知道,当电脑运行比较卡的时候,我们可以通过给电脑加装内存条来改善电脑的性能.那么号称微型计算机的单片机能不能像电脑一样加装内存条呢?装内存条倒是不行,但是我们可 ...

  6. [STM32F4xx 学习] 如何在RAM中调试程序

    在RAM中调试程序指的是将程序下载到RAM里面(而不是Flash里面),然后在RAM中执行程序.调试. 为什么要在RAM中调试程序?总结起来有以下两点原因: 1. Flash 擦写次数有限,STM32 ...

  7. Keil 程序调试窗口

    上一讲中我们学习了几种常用的程序调试方法,这一讲中将介绍Keil提供各种窗口如输出窗口.观察窗口.存储器窗口.反汇编窗口.串行窗口等的用途,以及这些窗口的使用方法,并通过实例介绍这些窗口在调试中的使用 ...

  8. keil将程序装入外部FLASH具体解释

    在实际项目中,常常出现芯片的内部FLASH空间不够的情况,这就须要将程序分一部分装到外部FLASH中. 为了让大家能少走些弯路,在这里把我在这当中遇到的一些问题和经验教训给大家分享一下. 仅供參考,假 ...

  9. 在Chrome+Visual Studio中调试asp.net程序很慢的问题(Firefox也有类似问题)

    在Chrome+Visual Studio中调试asp.net程序很慢的问题(Firefox也有类似问题) 今天开始起在Chrome中调试,发现问题主要出在菜单栏(layout文件)中,google了 ...

随机推荐

  1. cnBlog 的windows live writer 客户端配置

    重装系统后总是忘,备个档 CNBLOG 博客名 cnblog 日志帐户 http://www.cnblogs.com/liulaocai2/ 用户:359444066 密码:同QQ密码,比QQ少一位 ...

  2. chrome使用技巧(转)good

    阅读目录 写在前面 快速切换文件 在源代码中搜索 在源代码中快速跳转到指定的行 使用多个插入符进行选择 设备模式 设备传感仿真 格式化凌乱的js源码 颜色选择器 改变颜色格式 强制改变元素状态(方便查 ...

  3. Scilab 的画图函数(1)

    Scilab 的画图函数 plot 函数 最主要的是 plot 函数,与 matlab 中的plot 函数类似. xdata = linspace(1,10,50); ydata = sin(xdat ...

  4. C利用宏语言(#,##,do…while(0)盛大)

    C利用宏语言(#,##.do-while(0)盛大) 1.使用宏预先定义__FILE__,__FUNCTION__.__LINE__. #include <stdio.h> void fu ...

  5. 最快的方法来清除Chrome浏览器DNS高速缓存

    最快的方法是直接数据url.那么不需要清除dns高速缓存. chrome://net-internals/#dns 一般步骤,要经过下列几项. Chrome - > 扳手 - > 选项 - ...

  6. B/S VS C/S

    从软件project的学习到如今的机房合作,我们一直在学习C/S,进入牛腩才正式进入了对B/S的了解,确切点牛腩则是对此的一个过渡,起到了承上启下的作用!看牛腩,事实上最大的感受就是他不止要设计到页面 ...

  7. 第十七章——配置SQLServer(2)——32位和64位系统中的内存配置

    原文:第十七章--配置SQLServer(2)--32位和64位系统中的内存配置 前言: 本文讲述32位和64位系统中的内存配置,在SQLServer 2005/2008中,DBA们往往尝试开启AWE ...

  8. maple 教程

    1 初识计算机代数系统Maple 1.1 Maple简说 1980年9月, 加拿大Waterloo大学的符号计算机研究小组成立, 開始了符号计算在计算机上实现的研究项目, 数学软件Maple是这个项目 ...

  9. Android使用HttpURLConnection下载图片

    讲到http就必须要了解URI和URL URI (uniform resource identifier)统一资源标志符: URL(uniform resource location )统一资源定位符 ...

  10. Codeforces 338D GCD Table 中国剩余定理

    主题链接:点击打开链接 特定n*m矩阵,[i,j]分值为gcd(i,j) 给定一个k长的序列,问能否匹配上 矩阵的某一行的连续k个元素 思路: 我们要求出一个解(i,j) 使得 i<=n &am ...