keil程序在外部RAM中调试的问题总结(个人的一点经验总结)
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中起始地址出错
例如以下图所看到的:
我分析出现这个现象的原因是在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中调试的问题总结(个人的一点经验总结)的更多相关文章
- Ubuntu系统中初次下载Android源码的一点经验
这阵子突然心血来潮,想看看android的源代码,所以这一两天晚上都在折腾下载这个东西. (其实在GitHub上可以在线看的,不过不太喜欢在线看,URL附上 https://github.com/an ...
- 第49章 在SRAM中调试代码—零死角玩转STM32-F429系列
第49章 在SRAM中调试代码 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- 在SRAM、FLASH中调试代码的配置方法(附详细步骤)
因为STM32的FLASH擦写次数有限(大概为1万次),所以为了延长FLASH的使用时间,我们平时调试时可以选择在SRAM中进行硬件调试.除此之外,SRAM 存储器的写入速度比在内部 FLASH 中要 ...
- STM32F103_外部RAM用作运存---IS62WV51216
https://www.cnblogs.com/lilto/p/9548736.html STM32F103_外部RAM用作运存 概述 SRAM的简介 折腾过电脑的朋友都知道,当电脑运行比较卡的时 ...
- STM32F103_外部RAM用作运存
概述 SRAM的简介 折腾过电脑的朋友都知道,当电脑运行比较卡的时候,我们可以通过给电脑加装内存条来改善电脑的性能.那么号称微型计算机的单片机能不能像电脑一样加装内存条呢?装内存条倒是不行,但是我们可 ...
- [STM32F4xx 学习] 如何在RAM中调试程序
在RAM中调试程序指的是将程序下载到RAM里面(而不是Flash里面),然后在RAM中执行程序.调试. 为什么要在RAM中调试程序?总结起来有以下两点原因: 1. Flash 擦写次数有限,STM32 ...
- Keil 程序调试窗口
上一讲中我们学习了几种常用的程序调试方法,这一讲中将介绍Keil提供各种窗口如输出窗口.观察窗口.存储器窗口.反汇编窗口.串行窗口等的用途,以及这些窗口的使用方法,并通过实例介绍这些窗口在调试中的使用 ...
- keil将程序装入外部FLASH具体解释
在实际项目中,常常出现芯片的内部FLASH空间不够的情况,这就须要将程序分一部分装到外部FLASH中. 为了让大家能少走些弯路,在这里把我在这当中遇到的一些问题和经验教训给大家分享一下. 仅供參考,假 ...
- 在Chrome+Visual Studio中调试asp.net程序很慢的问题(Firefox也有类似问题)
在Chrome+Visual Studio中调试asp.net程序很慢的问题(Firefox也有类似问题) 今天开始起在Chrome中调试,发现问题主要出在菜单栏(layout文件)中,google了 ...
随机推荐
- UML学习(一)类图和对象图
对象是一个概念,一种抽象或者事物.对象能够是具有现实意义的事物,也能够是抽象的一个概念.比方,一家公司或者一个进程. 类是一组对象的集合或者抽象的概念.类具有同样的属性和方法. 介绍完基本对象和类的基 ...
- 跟我extjs5(03--在项目过程中加载文件)
跟我extjs5(03--在项目过程中加载文件) 上一节中用sencha工具自己主动创建了一个项目.而且能够在浏览器中查看. 如今我们来看看js类载入过程. 例如以下图所看到的: watermark/ ...
- Android 浏览器开发WebView setBlockNetworkImage本末
含义本身防止网络数据图片 webSettings.setBlockNetworkImage(true); 停止发布数据 webSettings.setBlockNetworkImage(false); ...
- java提高篇(八)-----实现多重继承
多重继承指的是一个类可以同时从多于一个的父类那里继承行为和特征,然而我们知道Java为了保证数据安全,它只允许单继承.有些时候我们会认为如果系统中需要使用多重继承往往都是糟糕的设计,这个时候我们往往需 ...
- uitableView 选择跳过后, 跳回 颜色变化 问题
今天遇到这个问题 谁也因此没有满足这方面的需求 今天会见 网上办理登机手续 未找到 好 我只能说自己的问题 但 幸好,kai哥 就攻克了 ! 就是在- (void)tableView:(UITabl ...
- SQL Server 开发利器 SQL Prompt 6.5 T-SQL智能感知分析器 下载地址 完全破解+使用教程
SQL脚本越写越多,总是觉得编写效率太过于低下,这和打字速度无关.在我个人编写SQL脚本时,至少会把SQL的格式排列成易于阅读的,因为其他人会阅读到你的SQL,无论是在程序中或是脚本文件中,良好的排版 ...
- 【剑指offer学习】求和为定值的两个数(拓展)
接着上面一篇文章: http://blog.csdn.net/u013476464/article/details/40651451 接下来我们拓展一下题目,如果数组是乱序的,并且规定数组中的元素所有 ...
- UVA11396-Claw Decomposition(二分图判定)
题目链接 题意:能否将一张无向连通图分解成多个爪型.每一条边仅仅能属于一个爪型,每一个点的度数为3. 思路:当图分解成类干个爪型时,每条边仅仅属于一个爪子,所以每条边的两个点一定要处于2个不同的鸡爪中 ...
- Team Services and Team Foundation Server官方资料入口
Team Foundation Server msdn 中文文档入口 Team Services or Team Foundation Server www.visualstudio.com 英文文档 ...
- UI设计规范
iphone\ipad.android UI设计规范对比 http://blog.163.com/leenell@yeah/blog/static/95840991201302210451710/ A ...