S3c2410软件调试总结

发布者:HeavenlyJoy444最新更新时间:2013-12-05 来源: chinaitlab关键字:S3c2410  软件调试 手机看文章 扫描二维码
随时随地手机看文章

硬件平台介绍
      我的硬件平台主要是 S3c2410 + FPGA(cyclone EP1C6),出于成本的考虑,我买了一块2410的核心板,然后自己画了一块底板,主要的模块有:

S3c2410 arm920 CORE RISC CPU
EP1C6 Altera cyclone series Fpga
AT89S52 atmel 51
RTL8019as 10M network device
Sdram x2 total: 64M byte
K9F5608 Nand flash 32M byte
AM29LV160D x2 NOR flash total: 4M byte
64LV25616 SRAM 512K byte
UDA1341 IIS Interface
24C256 EEPROM
USB Host 1, Dev 1
SD interface
UART x2

ADS下C语言的入口方式和ROM镜像文件的生成
       这部分介绍下ADS下如何生成可以运行的ROM镜像文件,我们知道当程序下载到flash中运行的时候,对于RW、ZI数据就存在着两个环境,一个 load环境,一个是exec环境,有时候由于速度的需要RO数据也要重新加载,那么对RO数据也是有两个环境。编译器产生ROM镜像文件时候,这三块数据的存放依次为RO、RW、ZI,并且地址空间时连续的。但是到了运行的时候,RW数据必须被拷贝到SDRAM(SRAM)中以支持读写,这就是我们所谓的运行环境。那么就要有一段代码去完成这个任务,在本章中我们介绍如何生成这段代码。

      玩过2410的朋友都知道2410初始化代码中有一段搬运RW和ZI初始化的代码,没错,它确实能够在一定程度上完成上面所说的任务,只要我们在生成二进制可执行代码的时候在编译器链接项的地方填写正确的RO&RW地址,(比如RO = 0, RW = 0x30000000), 那么将程序下到 NOR flash的零地址并从nor flash启动,启动代码会将RW&ZI数据弄到0x30000000,程序就能跑起来了。

    但是各位有没有想过,怎么把RO代码弄到SDRAM中(有时候这是必须的,比方后面我将提到用nor flash的bootloader烧写nor flash)?如果直接设RO=0x30000000,那么这段代码下载到0地址肯定跑不起来,除非是ROPI,这个要求就高了。这里我们有必要从介绍 ADS中规定的C语言入口开始,ADS中从初始化汇编代码跳到main函数有两种方式,main和__main:

1,在__main入口的模式下,汇编代码的指令为 b __main, 编译器在跳转到main之前还要作一系列的工作,这其中就包括对运行环境的初始化,在中提到: copies nonroot(RO&RW) execution regions from load addr to exec addr, and Zeros ZI region. 借助编译器,我们就可以定义更为复杂的运行环境,这里要用到scatter文件(.scf),比如我们要的目标运行环境是:将启动代码以外的所有代码都拷贝到SDRAM的初始地址中运行,比且把RW段设在0x30800000,那么对应的scf文件如下:

FLASH 0x0 0x200000
{
EXEC1 0x0 0x200000
{
2410init.o(Init, +First)
__main.o(+RO) ; copy code
* (Region$$Table) ; RO/RW addresses to copy
* (ZISection$$Table) ; ZI addresses to zero
}
EXEC2 0x30000000 0x00800000
{
*(+RO)
}
SDRAM 0x30800000 0x00800000
{
*(+RW,+ZI)
}
}
;Sections named Region$$Table and ZISection$$Table which contain the addresses of the code/data to be copied.

当然,在这种模式下,有些入口函数必须自己重定义,比如__user_initial_stackheap,具体参见ADS文档。

2, main入口模式即简单的跳转,这里起始不用“main”这个名字也无所谓。那么编译器不会作任何的初始化,所有运行环境的建立都要* 我们自己,这就是大家看到的那段搬运代码存在的理由。但是它实现一些简单的运行环境是可取的,如果用scf定义的复杂环境,虽然我相信是可以做到的,但是可能会比较麻烦。我还没深究。

    另外,这里提一下semihost,因为我们在看ADS的东西的时候经常出现这个词,我也一直受其困扰。这里我简单说一下自己的见解,semihost 仅仅是一种调试手段,它的机理就是利用MULTI_IDE等工具捕捉目标环境运行过程中产生的值为0x123456的SWI中断,然后向上位机的ADS 软件发送对应的调试信息。对于我们最后的应用代码来说,都是nonsemihost类型的。如果我们在调试中使用semihost,那么只要在最后重定义 ADS中的一些使用到的库函数(比如fputc),代码就可以从semihost向nonsemihost的类型转变。不过到目前为止,我还没体会到 semihost的威力。[page]


2410启动代码分析
   这一章主要对目前广泛流行的2410启动代码进行分析:S3C2410的初始化代码主要涉及到对系统主要模块的配置、运行环境的建立、系统时钟、MMU等模块的配置,下面按执行顺序依次都各个部分进行分析:

程序入口:(ResetHandler)
在程序一开始,首先进行的一些操作主要保证初始化程序能够顺利的运行, 因此主要包括关闭WDT、中断,配置锁相环等。

配置memory接口
memory接口是确保数据访问正确的基本保障,此处主要配置SFR寄存器中0x48000000开始的memory接口寄存器组, 确保每个bank的位宽、访问类型(waitable)以及时序参数正确。如果没有特别的要求,一般来说时序参数使用默认值即可。

初始化堆栈

ARM有6种运行模式,必须为每一种模式提供独立的堆栈空间,在堆栈设置之前是不能进行C函数的调用的。arm的堆栈模式 是从高地址递减的,我的所有代码统一将堆栈的首地址设在0x33ff8000处,往低依次为FIQ、IRQ、Abort、Undef、SVC,其中
SVC和User模式不予区分。堆栈大小一般可在头文件或者当前文件中修改。

运行空间的初始化
这段代码主要完成两个功能,一是将RW数据搬运到RW空间(我们生成ROM镜像时,RW数据是跟在RO数据之后的),二是 初始化ZI数据段。当然,这段代码存在的前提是代码的运行环境只是标准的两段式:一段RO空间和一段RW空间;并且在C程序
入口时没有调用编译器的链接库(__main)。后者已经提供相应的功能,并且支持更加复杂的运行环境定义(使用SCF文件),
(关于这一点,我在介绍ADS中C代码的启动模式时已经详细介绍)。

__rt_lib_init
在ADS1.2的环境中,如果在C入口没有调用编译器的链接库(__main),那么在C程序一开始要调用该函数以初始化运行时的函数库,以保证对ADS提供的某些库函数能够正常调用。从这个函数开始,我们已经在C语言环境下了。

MMU初始化
2410的MMU支持1级&2级地址映射,在我们目前大部分应用中均采用1级section模式的地址映射,一个section的大小为1M,也就是说从逻辑地址到物理地址的转变是这样的一个过程:
一个32位的地址,高12位决定了该地址在页表中的index,这个index的内容决定了该逻辑section对应的物理section; 低20位决定了该地址在section中的偏移(index)。
因此从0x0~0xffffffff的地址空间总共可以分成0x1000(4K)个section,页表中每项的大小为32个bit,因此页表的大小为0x4000(16K)。在我的代码中所有程序的页表统一存放在地址0x33ff8000。
每个页表项的内容如下:

bit: 31 20 19 12 11 10 9 8 5 4 3 2 1 0
content: Section对应的物理地址 NULL AP 0 Domain 1 C B 1 0

最低两位(10)是section分页的标识。
AP:Access Permission,区分只读、读写、SVC&其它模式。
Domain:每个section都属于某个Domain,一个有16个Domain,每个Domain的属性由CP15的R3寄存器控制。在我得所有程序中,都只包含两个Domain,一个是SFR地址以下(包括SFR)的空间,可访问; 另一个是SFR以上的空间,不可访问。
C、B:这两位决定了该section的cache&write buffer属性,这与该段的用途(RO or RW)有密切关系。不同的用途要做不同的设置。

C B 具体含义
0 0 无cache,无写缓冲,任何对memory的读写都反映到ASB总线上。

对 memory 的操作过程中CPU需要等待。
0 1 无cache,有写缓冲,读操作直接反映到ASB总线上。写操作CPU将数据写

入 到写缓冲后继续运行,由写缓冲进行ASB操作。
1 0 有cache,写通模式,读操作首先考虑cache hit;写操作时直接将数据写入

写缓冲,如果同时出现cache hit,那么也更新cache。
1 1 有cache,写回模式,读操作首先考虑cache hit;写操作也首先考虑cache,如果hit,则只修改cache,并将cache对应半行的dirty比特置位;如果miss,则写入写缓冲,触发ASB总线操作。

在我的程序中内存空间的分配统一采用了文末的MEMORY图。虽然MMU只是使用了逻辑地址到物理地址的linear transfer(值不改变),但是由于MMU能够引入cache&write buffer,因此系统性能有很大的提高!

配置时钟比、重新设置PLL
2410内部有三个时钟:FCLK、HCLK、PCLK,分别供CPU、AHB总线和APB总线使用,为了降低功耗,一般都选择周期比为1:2:4的合理配置。 同时将PLL配置为运行环境时钟,一般都达到最高202M。

IO初始化
将IO口配置为对应的功能选项,同时一般会点亮相应的LED灯。

中断初始化
2410的内存空间没有remap的机制,应该中断入口时钟位于零地址。因此中断服务机制可以描述如下:
首先,不管使用那种启动方式,必须确保一下代码段位于内存的0x0地址:
b ResetHandler
b HandlerUndef ;handler for Undefined mode
b HandlerSWI ;handler for SWI interrupt
b HandlerPabort ;handler for PAbort
b HandlerDabort ;handler for DAbort
b . ;reserved
b HandlerIRQ ;handler for IRQ interrupt
b HandlerFIQ ;handler for FIQ interrupt
除ResetHandler外,其余各项都是由如下的宏定义的一段代码:
HandlerFIQ HANDLER HandleFIQ
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack
ldr r0,=$HandleLabel ;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
这段代码的含义是通过堆栈将中断向量表中的内容赋给PC指针(如HandleFIQ是存放着FIQ服务程序入口地址的地址),自然程序就跳到相应的入口地址。
可见,中断向量表存放的是各个中断服务程序的入口地址,它是用来被加载的,而并不是可执行代码。为了统一,所有示例程序都将中断向量表放在0x33ffff00开始的地址,并根据入口地址依次排列。
需要注意的是如果各种模式的服务程序用C语言定义,那么类型必须用__irq定义,以保证能够正确返回。[page]

初始化串口
串口统一选用UART0,模式采用115200、1bit STOP、No Parity。

最后跳转到我们自己的应用程序!

附:我得程序所使用的地址空间结构以及MMU中C、B的设置:

Blank Area: RW_FAULT 0x5b000000 ~ 0xffffffff

Sram & SFR: NCNB 0x40000000 ~ 0x4affffff

Blank Area: RW_FAULT 0x34000000 ~ 0x3fffffff

Int_Vec, Stack, MTT: CNB 0x33f00000 ~ 0x33ffffff

SDRAM Download: NCNB 0x31000000 ~ 0x33efffff

SDRAM Exec RW: CB 0x30800000 ~ 0x30ffffff

SDRAM Exec R CNB 0x30000000 ~ 0x307fffff

Bank5, FPGA: NCNB 0x28000000 ~ 0x2fffffff

Bank4, FPGA: NCNB 0x20000000 ~ 0x27ffffff

Bank3, Bottom NIC: NCNB 0x18000000 ~ 0x1fffffff

Bank2, Bottom Flash: CNB 0x10000000 ~ 0x17ffffff

Bank1, Bottom Sram: CNB 0x08000000 ~ 0x0fffffff

Bank0, Flash or Sram: CNB 0x00000000 ~ 0x07ffffff


Nor Flash Bootloader
这是我着手写的第一个程序,我的想法是让这个程序同时支持通过串口对Nand 和 Nor FLASH的烧写,如果不进行任何烧写,那么就跳到Nor Flash的第二个section启动应用程序,这样一来,即使脱离JTGA,我也可以使用串口进行盲调。

由于有现成的初始化文件和flash烧写的示例程序,开发起来还比较快。当然也遇到了一些问题,一开始连flash的device ID都读不出来,后来发现我指针没有定义成volatile类型,flash的操作时序被编译器优化了;再者,在对Nor Flash进行操作时,bank0在MMU中的类型一定要设为NCNB,这样比较保险。

遇到最大的问题就是下面的了,一开始我用jtag把程序下载到0x30000000的地方运行,对Nor Flash的烧写完全正常,但是当把程序下载到Nor Flash中启动运行后,再对Nor Flash的section 2进行烧写时,就出现了问题。所幸没多久我就意识到了问题,将程序放在Nor Flash中运行,同时有对同一片flash进行操作,那么操作时序势必会被CPU的指令读取时序所破坏,因此程序必须搬运到SDRAM中运行。

但是启动地址有必须是零地址,所以我采用了前文提到的scatter文件的方法,将非必要的代码全部搬到sdram中运行,scf文件格式就是前文中的那个。当然采用了__main的入口,调用了ADS的链接库,让它帮忙建立程序的运行环境。

至此,Nor Flash Bootloader可以顺畅无忧的实现其功能了。

关键字:S3c2410  软件调试 引用地址:S3c2410软件调试总结

上一篇:S3C2410通过IIS总线与音频芯片UDA1380进行通信
下一篇:嵌入式开发arm技术JTAG接口解读

推荐阅读最新更新时间:2024-03-16 13:31

s3c2410 CACHES, WRITE BUFFER
在上一篇文档中我向大家介绍MMU的工作原理和对s3c2410 MMU部分操作进行了讲解。我们知道MMU存在的原因是为了支持虚拟存储技术,但不知道你发现了没有,虚拟存储技术的使用会降低整个系统的效率,因为与传统的存储技术相比,虚拟存储技术对内存的访问操作多了一步,就是对地址进行查表(查找映射关系),必须先从虚拟地址中分解出页号和页内偏移,根据页号对描述符进行索引(这就是一个查表过程)得到物理空间的首地址,这样做的代价是巨大的(其实这也正是时间效率与空间效率之间矛盾的一个体现),对某些嵌入式系统来说这简直就是恶梦。那么在引入了虚拟存储技术之后有没有方法在时间效率与空间效率这个矛盾之间取得一个平衡点呢?答案是有,我们可以通过一种技术从最大
[单片机]
<font color='red'>s3c2410</font> CACHES, WRITE BUFFER
s3c2410 4X4矩阵键盘驱动
//驱动代码如下.主设备号设为232 ,适用GEC2410 十六键矩阵键盘 #include linux/config.h #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/ioport.h #include asm/io.h #include linux/errno.h #include linux/types.h #include asm/system.h #include linux/cdev.h #include asm/uaccess.h #include asm
[单片机]
存储、NAND FLASH控制器实验(S3C2410)
本实验介绍如何使用SDRAM,这需要设置13个寄存器。呵呵,别担心,这些寄存器很多是类似的,并且由于我们只使用了BANK6,大部分的寄存器我们不必理会: 1.BWSCON:对应BANK0-BANK7,每BANK使用4位。这4位分别表示: a.STx:启动/禁止SDRAM的数据掩码引脚,对于SDRAM,此位为0;对于SRAM,此位为1。 b.WSx:是否使用存储器的WAIT信号,通常设为0 c.DWx:使用两位来设置存储器的位宽:00-8位,01-16位,10-32位,11-保留。 d.比较特殊的是BANK0对应的4位,它们由硬件跳线决定,只读。 对于本开发板,使用两片容量为32Mbyt
[单片机]
基于Linux和S3C2410的嵌入式图象传输系统设计
1 引言 如何更好的获得监控现场的图象数据一直是棘手的一个问题,传统的方法是采用CCD摄象机获取现场的视频信息,这种方法易于实现,但成本较高。随着ARM系列处理器应用的越来越广和基于linux的嵌入式技术的迅速发展,利用linux自身带有的TCP/IP协议来实现远程监控、图象传输已成为可能。本文提出的正是一种这样的方法,利用市场上很常见的中星微系列的USB摄象头来得到现场的图象数据,利用linux内核中的Video4Linux编程接口函数采集图象,并把得到的图象通过Internet传输到上位机PC上,在PC上实现图象的保存和显示。 2 硬件系统设计原理 系统的硬件功能框图如图1所示,CPU采用的是三星公司的S3C2410。该
[嵌入式]
linux驱动:s3c2410_ts/s3c2440_ts模块加载流程
前言 通过分析s3c2410_ts/s3c2440_ts模块加载流程,分析linux驱动中的 总线-设备-驱动模型 以及 输入子系统框架 。 主要流程分析图示 s3c2440_ts 主要流程分析 系统初始化 MACHINE_START(SMDK2410, SMDK2410 ) MACHINE_START(SMDK2410, SMDK2410 ) /* @TODO: request a new identifier and switch * to SMDK2410 */ /* Maintainer: Jonas Dietsche */ .phys_io = S3C2410_PA_UART, .io_
[单片机]
S3C2410 -- UART
自动流控模式 S3C2410的UART0和UART1都可以通过各自的nRTS和nCTS信号来实现自动流控。 在自动流控(AFC)模式下nRTS取决于接收端的状态,而nCTS控制了发送断的操作。具体地说:只有当nCTS有效时(表明接收方的FIFO已经准备就绪来接收资料了),UART才会将FIFO中的资料发送出去。在UART接收资料之前,只要当接收FIFO有至少2-byte空余的时候,nRTS就会被置为有效。图5-12是UART 自动流控模式的连接方式 图5-12 中断/DMA请求产生 S3C2410的每个UART都有7种状态,分别是:溢出覆盖(Overrun)错误、奇偶校验错误、帧出错、断线错误、接收就绪、发送缓冲空闲、发
[单片机]
<font color='red'>S3C2410</font> -- UART
基于S3C2410的氢气浓度监测系统设计
引言 零碳排放的氢燃料作为一种高效、清洁、可再生的能源,得到了国际能源界的广泛认同。氢气也在石油化工、电子工业、食品工业、航空航天工业等领域有了广泛应用。然而,氢气是一种无色无味、携带极不方便、极易泄漏的气体,在室温和标准大气压下,氢气与空气的混合比例达到4.1%~74.1%时遇明火极易爆炸。为了减小使用氢气的安全隐患,开发出一套安全、可靠、灵敏度高的氢气浓度监测系统具有十分重要的意义。 1 系统总体结构设计 采集到的氢传感信号经过低噪声放大电路进行放大处理,并在低通滤波器滤除信号中的高频噪声。然后,经A/D转换器送入ARM处理器S3C2410,ARM处理器再调用应用程序对采集到的数据进行数字处理,最后实时显示浓度值,并
[测试测量]
基于<font color='red'>S3C2410</font>的氢气浓度监测系统设计
skyeye模拟s3c2410 linux下程序
在前面的基础上,下面开始利用skyeye自带的testsuites中的资源来运行自己的程序的方法 1.首先是下载下载skyeye-1.2.5_REL.tar.gz,然后解压该文件 2.使用skyeye模拟板子s3c2410运行某个linux 首先进入解压完的目录,然后 cd ./linux/s3c2410/s3c2410x-2.6.14 skyeye –c skyeye.conf –e vmlinux 注意的是skyeye的版本问题,我是用的是skyeye-1.2.6的,其他版本可能不能够使用。 然后出现 Welcome to ......(arm linux) ARMLinux for Skyeye 3.编写hello.
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved