跳至主要内容

【转】vivi开发笔记(九):SDRAM实验

文章说明:calmarrow(lqm)参考thisway.diy的《S3C2410完全开发》

文章引自:http://piaoxiang.cublog.cn

 
    现在基本熟悉了GNU as、ld、objdump、objcopy。可以进行后续的基本实验了。今天把s3c2410的memory controller看了,结合《s3c2410完全开发》实验五,实现了一个sdram的简单实验。源代码如下,下面重点分析s3c2410复位后的内存映射,及其应用。
 
一、基本配置
    EDUKIT-III采用核心子板加扩展板的设计方式,我学习ARM9,所以采用s3c2410的核心子板。核心子板资源如下:
 
    MCU      : S3C2410A
    SDRAM    : 两片HY57V561620CT-H
    NOR FLASH: AM29LV160DB-90EC
 
    扩展板资源:
 
    NAND FLASH: K9F5608UOC
 
二、nand flash boot分析
 
    S3C2410支持从nor/nand flash、eeprom等rom类型的介质启动。现在我想做的是从外部nand flash启动,首先看datasheet第一部分:
 

NAND Flash Boot Loader
・ Supports booting from NAND flash memory
・ 4KB internal buffer for booting
・ Supports storage memory for NAND flash memory after booting

 
    可以明确,首先,s3c2410支持从nand flash存储介质启动,其次,在硬件上,s3c2410除了提供相应的逻辑外,还提供了一个4K的sram作为buffer用于nand启动。最后,s3c2410支持从nand flash启动之后的内存分配形式(也就是说,从nand flash启动之后和从nor flash启动之后的内存分配形式是不同的。s3c2410支持这两种形式,可以说是相对于其他的MCU不同的地方。)
 
    然后看datasheet的第六部分:nand flash controller。overview中首先讲述了用nand flash代替nor flash作为启动介质的原因(成本低)。
 

    S3C2410X boot code can be executed on an external NAND flash memory. In order to support NAND flash boot loader, the S3C2410X is equipped with an internal SRAM buffer called 'Steppingstone'. When booting, the first 4
KBytes of the NAND flash memory will be loaded into Steppingstone and the boot code loaded into Steppingstone will be executed.
    Generally, the boot code will copy NAND flash content to SDRAM. Using hardware ECC, the NAND flash data validity will be checked. Upon the completion of the copy, the main program will be executed on the SDRAM.

 
    可以很明显的看出,s3c2410x启动代码从外部nand flash启动的流程:上电复位后,s3c2410自动读取nand flash的前4KBytes的数据到内部sram buffer中,这个硬件的sram buffer被称为"Steppingstone"。然后执行下载到steppingstone的代码,这部分代码完成将nand flash的内容复制到sdram中,在复制时,利用硬件的ECC验证数据有效性。完成复制后,主程序就开始从sdram执行。
 
    过程应该是很清晰。但是首先怀疑的是,s3c2410如何实现自动读取nand flash的前4KBytes数据到内部sram buffer当中。网上为什么没人就这点产生疑问,并深入分析呢?我分析可能有两种方法:一是像at91rm9200一样,内部集成一个小的rom,固化代码,这部分代码的作用就是完成自动读取功能;二是完全用硬件实现。仔细看了框图,发现s3c2410只有internal sram buffer,并没有rom,所以最大可能就是硬件实现。看一下硬件框图figure6-1,可以发现hardware ECC编解码器,可以看到internal buffer(4KB),另外注意的一个地方是,存在着control state machine和buffer control,而且之间有粗体线链接。也就是说明了用一个控制状态机实现了自动读取4KB数据的过程,完全的硬件实现。如下图所示:
 
    明确了这个问题之后,对从硬件上电到nand flash启动就比较清晰了。而且,也就理解为什么vivi的stage1的head.S必须要小于4KB,因为internal sram buffer只有4KB。如果要完成一个比较复杂的bootloader,那也应该尽量简化stage1,完成基本的初始化之后,把剩余的工作量都放到将nand flash的代码搬移到sdram之后进行。
 
三 memory controller分析
 
    看datasheet第五部分。s3c2410比较特殊,支持1G的内存空间,分为8个bank,每个bank128MBytes,128MB×8=1GB。但是在这8个bank中,又有所不同,并且nand flash不对应任何bank,它是通过一组寄存器来访问的,可看上面框图的register bank。
 

― Total 8 memory banks
   Six memory banks for ROM, SRAM, etc.
   Remaining two memory banks for ROM, SRAM, SDRAM, etc .
― Seven fixed memory bank start address
― One flexible memory bank start address and programmable bank size

 
    可以推断出,sdram应该在bank6,起始地址固定为128M*6=0x30000000,在此之后,就要根据sdram的大小和位宽来决定了,而且有个注意的地方是,bank7必须和bank6一样大小。参考figure5-1和table 5-1就非常清晰了。现在EDUKIT-III上用了两片SDRAM,型号是HY57V561620CT-H,查看datasheet,它是4banks×4M×16bit=256Mbits=32Mbytes,那么两片组合起来就是64MBytes,位宽是32bit,所以bank6的地址范围是[0x30000000-0x33ffffff],bank7的地址范围是[0x34000000-0x37ffffff]。查看s3c2410 table 5-2,可以知道bank选择地址线为A[25:24]--->BA[1:0]。
 
    关于sdram,还应该知道刷新频率和列宽度。HY57V561620CT-H datasheet中,有:
 

 Auto refresh and self refresh
8192 refresh cycles / 64ms
Programmable Burst Length and Burst Type
  - 1, 2, 4, 8 or Full page for Sequential Burst
  - 1, 2, 4 or 8 for Interleave Burst
Programmable CAS Latency ; 2, 3 Clocks

 
    所以刷新频率为64ms/8192=7.8125us。
 
    查看PIN DESCRIPTION,可以看出A0-A12为地址,其中ROW Address为RA[0:12],Column Address为CA[0-8],显然CAS的位数为9bits。
 
四、实验内容分析
 
    实验内容很简单,就是完成基本的初始化之后,把steppingstone的4K数据搬移到sdram中。然后在sdram中执行灯循环点亮程序。结合这个实验,也可以很清晰的明白,前面几个基本实验,从nand flash启动后,所有代码只是搬移到了steppingstone中,也就是实际执行时是在steppingstone中,也就是boot internal sram(4KB)中执行的,所以运行时域和加载时域都是0x00000000,设置的堆栈可以是1024,也可以是4096,但是注意一是最大为4096,二是保证不与可执行代码发生冲突。在这个程序中,运行时域和加载时域是不相同的。加载时域是0x00000000,但是运行时域是0x30000000。《s3c2410完全开发》对这个地方讲解不是太详细。经过实验,和王老师的帮助,弄清楚了到底怎么回事。现在关于运行时域和加载时域的具体分析如下:
 
    根据nand flash的特点,初始代码的加载时域为0x00000000,也就是当前PC的值为0x00000000,两种跳转指令b(l)等只能相对寻址,最大范围是+/-32MBytes,所以如果不改变PC的话,不可能能利用b或者bl跳转到sdram的空间中。跳转指令ldr则不受此寻址空间的限制,可以进行绝对寻址。需要了解的一个细节就是,链接后所有的标号都是基于运行地址的,比如运行地址为0x30000000,那么第一个标号_start地址就是0x30000000,所以可以利用ldr的绝对寻址来完成到sdram的跳转。下面根据编写的sdram的反汇编来进行分析:
 
    首先看在不去除符号信息的前提下:
 

sdram: $(OBJS)
        $(LD) $(LDFLAGS) $^ -o $@.o
        $(OBJDUMP) -D $@.o >$@_s
        $(OBJCOPY) -O binary -S $@.o $@

 
    这里是反汇编的结果:
 

Disassembly of section .text:

30000000 <_start>:
30000000:       e3a00453        mov     r0, #1392508928 ; 0x53000000
30000004:       e3a01000        mov     r1, #0  ; 0x0
30000008:       e5801000        str     r1, [r0]
3000000c:       eb00000c        bl      30000044 <memsetup>
30000010:       eb000003        bl      30000024 <copy_steppingston_to_sdram>
30000014:       e59ff088        ldr     pc, [pc, #88]   ; 300000a4 <mem_cfg_val+0x34>

30000018 <setup_stack>:
30000018:       e3a0d30d        mov     sp, #872415232  ; 0x34000000
3000001c:       eb000023        bl      300000b0 <main>

30000020 <stop>:
30000020:       eafffffe        b       30000020 <stop>

 
    可以很明显的看出,_start为0x30000000,stop为0x30000020。也就是说,经过链接之后,symbol table中的存放位置都是基于运行起始地址0x30000000的。但是需要注意的是,开始运行是PC的值为0x00000000,虽然bl 30000040 <memsetup>是30000040,但是要注意,此处指令为bl,所以只能相对寻址,而不能够绝对寻址,也就是说,它只能跳转到距离0x30000000为0x40的位置,这点查看bl的汇编指令说明就比较清晰了。
 

        ldr pc, =setup_stack
setup_stack:
        ldr sp, =stack_top
        bl main

 
    利用上面的技巧,就可以把PC的值装载到sdram的空间,因为之前代码搬移已经完成了,所以,后续的工作都已经工作在sdram的空间中了。
 
    如果在利用objcopy去除了符号信息之后,反汇编之后的结果只能是以0开始的相对地址,也就看不出上面的东西了,所以,要理解还应该是采用上面的分析方法。这点在《s3c2410完全开发》上是没有详细说明的。写到这里,自己已经比较清晰了。关于其他的分析,《s3c2410完全开发》已经比较详细了,可以参考。
 
    程序源代码如下:
 
文件: sdram.tar.gz
大小: 2KB
下载: 下载

评论

此博客中的热门博文

【转】AMBA、AHB、APB总线简介

AMBA 简介 随着深亚微米工艺技术日益成熟,集成电路芯片的规模越来越大。数字IC从基于时序驱动的设计方法,发展到基于IP复用的设计方法,并在SOC设计中得到了广泛应用。在基于IP复用的SoC设计中,片上总线设计是最关键的问题。为此,业界出现了很多片上总线标准。其中,由ARM公司推出的AMBA片上总线受到了广大IP开发商和SoC系统集成者的青睐,已成为一种流行的工业标准片上结构。AMBA规范主要包括了AHB(Advanced High performance Bus)系统总线和APB(Advanced Peripheral Bus)外围总线。   AMBA 片上总线        AMBA 2.0 规范包括四个部分:AHB、ASB、APB和Test Methodology。AHB的相互连接采用了传统的带有主模块和从模块的共享总线,接口与互连功能分离,这对芯片上模块之间的互连具有重要意义。AMBA已不仅是一种总线,更是一种带有接口模块的互连体系。下面将简要介绍比较重要的AHB和APB总线。 基于 AMBA 的片上系统        一个典型的基于AMBA总线的系统框图如图3所示。        大多数挂在总线上的模块(包括处理器)只是单一属性的功能模块:主模块或者从模块。主模块是向从模块发出读写操作的模块,如CPU,DSP等;从模块是接受命令并做出反应的模块,如片上的RAM,AHB/APB 桥等。另外,还有一些模块同时具有两种属性,例如直接存储器存取(DMA)在被编程时是从模块,但在系统读传输数据时必须是主模块。如果总线上存在多个主模块,就需要仲裁器来决定如何控制各种主模块对总线的访问。虽然仲裁规范是AMBA总线规范中的一部分,但具体使用的算法由RTL设计工程师决定,其中两个最常用的算法是固定优先级算法和循环制算法。AHB总线上最多可以有16个主模块和任意多个从模块,如果主模块数目大于16,则需再加一层结构(具体参阅ARM公司推出的Multi-layer AHB规范)。APB 桥既是APB总线上唯一的主模块,也是AHB系统总线上的从模块。其主要功能是锁存来自AHB系统总...

【转】GPIO编程模拟I2C入门

ARM编程:ARM普通GPIO口线模拟I2C  请教个问题: 因为需要很多EEPROM进行点对点控制,所以我现在要用ARM的GPIO模拟I2C,管脚方向我设 置的是向外的。我用网上的RW24C08的万能程序修改了一下,先进行两根线的模拟,SDA6, SCL6,但是读出来的数不对。我做了一个简单的实验,模拟SDA6,SCL6输出方波,在示波 器上看到正确方波,也就是说,我的输出控制是没问题的。 哪位大哥能指点一下,是否在接收时管脚方向要设为向内?(不过IOPIN不管什么方向都可 以读出当前状态值的阿) 附修改的RW24C08()程序: #define  SomeNOP() delay(300); /**/ /* *********************************  RW24C08   **************************************** */ /**/ /* ----------------------------------------------------------------------------- ---  调用方式:void I2CInit(void)   函数说明:私有函数,I2C专用 ------------------------------------------------------------------------------- -- */ void  I2CInit( void ) ... {  IO0CLR  =  SCL6;      // 初始状态关闭总线  SomeNOP();  // 延时   I2CStop();  // 确保初始化,此时数据线是高电平 }   /**/ /* ---------------------------------------------------------------------------- ----  调用方式:void I2CSta...

【转】cs8900网卡的移植至基于linux2.6内核的s3c2410平台

cs8900网卡的移植至基于linux2.6内核的s3c2410平台(转) 2008-03-11 20:58 硬件环境:SBC-2410X开发板(CPU:S3C2410X) 内核版本:2.6.11.1 运行环境:Debian2.6.8 交叉编译环境:gcc-3.3.4-glibc-2.3.3 第一部分 网卡CS8900A驱动程序的移植 一、从网上将Linux内核源代码下载到本机上,并将其解压: #tar jxf linux-2.6.11.1.tar.bz2 二、打开内核顶层目录中的Makefile文件,这个文件中需要修改的内容包括以下两个方面。 (1)指定目标平台。 移植前:         ARCH?= $(SUBARCH) 移植后: ARCH            :=arm (2)指定交叉编译器。 移植前: CROSS_COMPILE ?= 移植后: CROSS_COMPILE   :=/opt/crosstool/arm-s3c2410-linux-gnu/gcc-3.3.4-glibc-2.3.3/bin/arm-s3c2410-linux-gnu- 注:这里假设编译器就放在本机的那个目录下。 三、添加驱动程序源代码,这涉及到以下几个方面。(1)、从网上下载了cs8900.c和cs8900.h两个针对2.6.7的内核的驱动程序源代码,将其放在drivers/net/arm/目录下面。 #cp cs8900.c ./drivers/net/arm/ #cp cs8900.h ./drivers/net/arm/ 并在cs8900_probe()函数中,memset (&priv,0,sizeof (cs8900_t));函数之后添加如下两条语句: __raw_writel(0x2211d110,S3C2410_BWSCON); __raw_writel(0x1f7c,S3C2410_BANKCON3); 注:其原因在"第二部分"解释。 (2)、修改drivers/net/arm/目录下的Kconfig文件,在最后添加如...