Keil MDK使用J-LINK分别在Sram,Nor Flash以及Sdram中调试代码的原理和方法

一、概述

MDK开发ARM裸机程序时,在调试阶段通常是先让程序在SDRAM中执行,以加快调试速度,也避免频繁烧写Nor Flash,因此需要知道如何指定程序在哪个位置执行。本文以realarm 2410开发板为例,进行描述。该开发板使用S3C2410A做为CPU,有2MB的 Nor Flash,以及64MB的SDRAM,4KB的SRAM。程序可直接在Nor Flash中调试和运行,如果代码小于4KB,也可以直接在SRAM中运行,然而在SDRAM 中运行,就需要事先用脚本初始化SDRAM,才能把程序加载到SDRAM中执行。

realarm2410使用Nor Flash时的内存映射,如下图:


图1

下面详细说明各种情况。

二、程序在Nor Flash中调试

由图1可见,CPU复位后PC指针为0,正好代码在Flash中执行,因此,无需修改PC指针,仅需在程序的初始化部分初始化SDRAM,以及分配好Stack以及Heap则可,要使用分散加载文件*.sct指定程序链接加载的位置,分散加载文件如下:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_ROM1 0x0 0x00200000  {    ; load region size_region
  ER_ROM1 0x0 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_STACK 0x33ff3000   {  ; RW data
   *(STACK)
  }
  RW_HEAP 0x33ef3000   {  ; RW data
   *(HEAP)
  }
  RW_RAM1 0x30000000 0x04000000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM1 0x40000000 0x00001000  {
   .ANY (+RW +ZI)
  }
}

分散加载文件LoadToFlash.sct

该分散加载文件把RO指定到0x0开始大小为0x200000的位置,即2MB的Flash中,RW指定在起始地址为0x30000000大小为0x4000000的64MB的SDRAM中,0x40000000开始的大小为0x1000的4KB的SRAM也作为RW区使用,而Stack则在SDRAM的0x33ff3000开始,Heap则在0x33ef3000开始。大小在初始化程序中指定,如下:

UND_Stack_Size  EQU     0x00000400
SVC_Stack_Size  EQU     0x00001000
ABT_Stack_Size  EQU     0x00000400
FIQ_Stack_Size  EQU     0x00001000
IRQ_Stack_Size  EQU     0x00001000
USR_Stack_Size  EQU     0x00001800

Stack_Size      EQU     (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + 
                         FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size)

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size

Stack_Top       EQU     Stack_Mem + Stack_Size



Heap_Size       EQU     0x00100000

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
Heap_Mem        SPACE   Heap_Size

那么,SDRAM除了20KB的Stack和1MB的 Heap外,都当成了RW。SDRAM分配图如下:



图2

总而言之,要实现Flash调试代码,需实现以下步骤:

  1. 通过设计分散加载文件,指定RO在Flash,同时分配好其它的RW以及Stack和Heap的地址,并配置工程使用分散加载文件来链接;

  2. S3C2410A.s要初始化SDRAM,并分配好Stack和Heap;
  3. 工程中设置使用J-LINK为Flash编程,并设置好Flash的编程算法,勾选调试前需更新代码;
  4. 在工程设置中设置为调试前更新代码;具体需特别说明的工程设置图如下:

图3:指定Link按照LoadToFlash.sct规则执行


图4:指定使用J-LINK/J-TRACK ARM来调试程序


图5:一定要勾选Update Target before Debugging

图5按下settings按键,设置Flash下载设置和编程算法,realarm2410使用的SST39VF1601,MDK有现成的编程算法,直接按下ADD按键,选择芯片型号则可,如图6。


图6:Flash编程设置

如此,在MDK中执行start debug则可进入Flash中调试代码了。

提供跑马灯程序的MDK工程,注意选择好Target为DebugInFlash。

跑马灯的MDK工程下载

三、程序在SRAM中调试

有了前面在Flash中调试所述的原理基础,设置为SRAM中调试就好办了,按以下步骤:

  1. 要保证程序小于4KB,RO放到SRAM中;

  2. 如果使用的RW段、Stack和Heap还是放到SDRAM中,那么依然要在S3C2410A.s中初始化;
  3. Debug前要执行一个初始化脚本,因为SRAM 地址从0x40000000开始,因此需要在初始化脚本中把PC指针设置到0x40000000中;
  4. 一定不可勾选调试前更新代码这个选项,否则start debug时会提示错误,实际上SRAM调试的代码不可烧写到Flash中执行。

附上分散加载文件和工程配置图如下:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_ROM1 0x40000000 0x00001000  {    ; load region size_region
  ER_ROM1 0x40000000 0x00001000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_STACK 0x33ff3000   {  ; RW data
   *(STACK)
  }
  RW_HEAP 0x33ef3000   {  ; RW data
   *(HEAP)
  }
  RW_RAM1 0x33000000 0x00e00000  {  ; RW data
   .ANY (+RW +ZI)
  }
}
 

图7:设置Debug的初始化文件为init_sram_RunFromSram.ini

init_sram_RunFromSram.ini文件如下:

FUNC void SetupForStart (void) {

// <o> Program Entry Point
  PC = 0x40000000;
}


SetupForStart();                        // Setup for Running


图8:不可勾选Update target before Debugging,可设为使用外部工具

提供跑马灯程序的MDK工程下载,注意选择好Target为DebugInSram。

跑马灯的MDK工程下载

四、程序在SDRAM中调试

有了前面所述的原理基础,设置为SDRAM中调试基本和SRAM的相似,但是,有以下两个不同点:

  1. SDRAM不受4KB大小限制;

  2. SDRAM需要初始化才能使用,因此在debug初始化文件中需要增加初始化SDRAM,并且把要调试程序的按照axf格式加载到SDRAM中;
  3. 初始化程序S3C2410A.s中不可再初始化,因为debug初始化脚本已经初始化过了,而且加载了程序,如果再初始化那会把程序给破坏点了。

还是用分散加载文件指定RO、RW、Stack以及Heap的位置,把RO分配到SDRAM的起始的2MB中,其它和前面一样,文件如下:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_ROM1 0x30000000 0x00200000  {    ; load region size_region
  ER_ROM1 0x30000000 0x00200000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_STACK 0x33ff3000   {  ; RW data
   *(STACK)
  }
  RW_HEAP 0x33ef3000   {  ; RW data
   *(HEAP)
  }
  RW_RAM1 0x31000000 0x03000000  {  ; RW data
   .ANY (+RW +ZI)
  }
  RW_IRAM1 0x40000000 0x00001000  {
   .ANY (+RW +ZI)
  }
}

Debug初始化文件如下:

FUNC void SetupForStart (void) {

// <o> Program Entry Point
  PC = 0x30000000;
}


FUNC void Init (void) {
  _WDWORD(0x4A000008, 0xFFFFFFFF);      // Disable All Interrupts

  _WDWORD(0x53000000, 0x00000000);      // Disable Watchdog Timer

                                        // Clock Setup
                                        // FCLK = 150 MHz, HCLK = FCLK/2 MHz, PCLK = HCLK/2 MHz
  _WDWORD(0x4C000000, 0x0FFF0FFF);      // LOCKTIME
  _WDWORD(0x4C000014, 0x0000000F);      // CLKDIVN
  _WDWORD(0x4C000004, 0x00043011);      // MPLLCON
  _WDWORD(0x4C000008, 0x00038021);      // UPLLCON
  _WDWORD(0x4C00000C, 0x001FFFF0);      // CLKCON

                                        // Memory Controller Setup for SDRAM
  _WDWORD(0x48000000, 0x22000000);      // BWSCON
  _WDWORD(0x4800001C, 0x00018005);      // BANKCON6
  _WDWORD(0x48000020, 0x00018005);      // BANKCON7
  _WDWORD(0x48000024, 0x008404F3);      // REFRESH
  _WDWORD(0x48000028, 0x00000032);      // BANKSIZE

  _WDWORD(0x4800002C, 0x00000020);      // MRSRB6
  _WDWORD(0x48000030, 0x00000020);      // MRSRB7

  _WDWORD(0x56000000, 0x000003FF);      // GPACON: Enable Address lines for SDRAM

}


// Reset chip with watchdog, because nRST line is routed on hardware in a way
// that it can not be pulled low with ULINK

_WDWORD(0x40000000, 0xEAFFFFFE);        // Load RAM addr 0 with branch to itself
CPSR = 0x000000D3;                      // Disable interrupts
PC   = 0x40000000;                      // Position PC to start of RAM
_WDWORD(0x53000000, 0x00000021);        // Enable Watchdog
g, 0                                    // Wait for Watchdog to reset chip

Init();                                 // Initialize memory
LOAD .\led_InSdram.axf INCREMENTAL      // Download program
SetupForStart();                        // Setup for Running

脚本中的Init函数对寄存器的操作含义可以查阅S3C2410的寄存器手册,实现的就是关中断,看门狗,设置时钟,初始化内存控制器。LOAD .\led_InSdram.axf INCREMENTAL作用就是把led_InSdram.axf文件加载进去,axf为elf格式的文件,本身带有加载的地址,因此只要分散加载文件按这只正确了,编译链接后生成的axf文件就有了正确的加载地址;最后把PC设置到RO的基址0x30000000执行代码。

S3C2410A.s需关闭内存控制器的初始化功能,找到这一行代码:MC_SETUP        EQU     1;改为MC_SETUP        EQU     0。

提供跑马灯程序的MDK工程下载,注意选择好Target为DebugInSdrSram。并记得修改MC_SETUP        EQU     0。

跑马灯的MDK工程下载
时间: 2024-11-13 21:58:03

Keil MDK使用J-LINK分别在Sram,Nor Flash以及Sdram中调试代码的原理和方法的相关文章

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

因为STM32的FLASH擦写次数有限(大概为1万次),所以为了延长FLASH的使用时间,我们平时调试时可以选择在SRAM中进行硬件调试.除此之外,SRAM 存储器的写入速度比在内部 FLASH 中要快得多,所以下载程序到SRAM中的速度较快. 所以我们很有必要建立两个版本的工程配置,在SRAM中调试程序完毕后,再把代码下载到FLASH中即可.这篇笔记主要分享在keil5中配置FLASH调试与SRAM调试的详细配置方法及如何切换两种配置. 本篇笔记以STM32F103ZET6为例.其FLASH大

ROM、RAM、DRAM、SRAM和FLASH的区别

ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是Random Access Memory的缩写.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,典型的RAM就是计算机的内存. RAM有两大类,一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲.另一种称为动态RAM(Dynamic RAM/D

18.11 ROM、RAM、DRAM、SRAM和FLASH区别

ROM(Read Only Memory)和RAM(Random Access Memory)指的都是半导体存储器.ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,但是访问速度快.典型的RAM就是计算机的内存. RAM有两大类,一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备,但是也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲.另一种称为动态RAM(Dynamic RAM/DRAM),D

什么是ROM、RAM、DRAM、SRAM和FLASH的区别

ROM 和 RAM 区别: ROM : Read Only Memory RAM : Random Access Memory ROM在系统停止供电的时候仍然可以保持数据, RAM通常都是在掉电之后就丢失数据,典型的RAM就是计算机的内存. RAM有两大类: 一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲.另一种称为动态. RAM(Dynamic RAM/DRAM

KEIL MDK 查看代码量、RAM使用情况--RO-data、RW-data、ZI-data的解释(转)

源:KEIL MDK 查看代码量.RAM使用情况--RO-data.RW-data.ZI-data的解释 KEIL RVMDK编译后的信息 Program Size: Code=86496 RO-data=9064 RW-data=1452 ZI-data=16116 Code是代码占用的空间; RO-data是 Read Only 只读常量的大小,如const型; RW-data是(Read Write) 初始化了的可读写变量的大小; ZI-data是(Zero Initialize) 没有初

STM32F10x随笔(keil mdk)

STM32F10x(Keil+MDK) by HYH | 2017 年 11 月 3 日 下午 8:51 一.安装后keil MDK环境后,就可直接开发arm了. 备用下载链接:http://pan.baidu.com/s/1qYNtrys 密码:wqpy 最好安装最新版的. 二.RT-Thread简单使用. 1.编译. 1)打开工程 在bsp\Stm32F10x下有相应的工程文件,打开即可. 2).下载设备包. 网址:http://www.keil.com/dd2/pack/#/eula-co

Keil MDK与h-jtag联调

keil MDK也是可以借助h-jtag进行单步调试,写出来与大家一起分享一下. keil MDK编译器使用V4.01版本,下载地址: http://www.embedinfo.com/down-list.asp?id=714   (需要注册一下) h-jtag使用V1.0版本(请注意,一定要用V1.0或者以上版本才可以与mdk兼容),下载地址 http://www.hjtag.com/download/H-JTAG%20V1.0%20Preview.zip 分别安装MDK与h-jtag 两个软

Keil MDK从未有过的详细使用讲解

转自博客:http://blog.csdn.net/zhzht19861011/article/details/5846510 这博主关于MDK 的使用的文章,写的得TM的好  TM的实用! 真心收藏! 熟悉Keil C 51的朋友对于Keil MDK上手应该比较容易,毕竟界面是很像的.但ARM内核毕竟不同于51内核,因此无论在设置上还是在编程思想上,都需要下番功夫研究的.本文以MDK V4.03为例,详细的写一下MDK的设置.界面.工具.可能会有些杂乱,但我想所涉及的东西都是最常用的:可能不是

Keil MDK忽略某一警告

使用Keil MDK调试程序的时候,没有习惯在每个文件的末尾增加一个空白行,结果文件一多,编译时产生的警告就一大堆,排错都得用滚轮滚好久,就一个空白行还得出警告,烦死了,烦死了,烦死了!实在受不了了,查阅了mdk的帮助文档,发现可以通过增加控制选项的方式,屏蔽某一固定码的警告.具体方式如下: 点击编译,查看警告编码:我这边产生的空白行警告是1,所以,打开工程配置菜单,点击C/C++选项卡,在Misc Controls里面输入: --diag_suppress=1 其中的1就是警告编码,然后点击确