历史上的今天
返回首页

历史上的今天

今天是:2025年03月10日(星期一)

正在发生

2020年03月10日 | Arm 2440——Nand flash启动模式详解(LED程序为例)

2020-03-10 来源:eefocus

断断续续的研究arm也有2个月了,现在才感觉理解了arm在Nand flash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说,趁着还没有忘记学习过程中的感受,直接进入正题。


大家都知道,arm在Nand flash启动模式下启动时系统会将Nand flash中的前4KB代码拷贝到SRAM(也就是Steppingstone中),由SRAM配置中断向量表和完成Nand flash访问的必要初始化,然后将Nand flash中的全部程序代码拷贝到SDRAM中,最后由SRAM跳转到SDRAM,然后程序就正常执行了,这一过程看上去很简单,但是真正理解这一过程还是不简单的,尽管这样,还是想告诉大家仔细理解还是比较容易理解这个过程的。如果您是ADS用户,你省去了很多麻烦,但我不确定你省去的这些麻烦是否值得,这里介绍的是一种麻烦的方式,linux下的led程序。


代码Head.s


.extern main

.text

.global _start

_start:

    b reset

 

reset:

    ldr sp,=4096

    bl disable_watch_dog

    bl clock_init

    bl memsetup

    bl copy_steppingstone_to_sdram

    ldr pc,=on_sdram

 

on_sdram:

    msr cpsr_c,#0xdf

    ldr sp,=0x34000000

    ldr lr,=halt_loop

    ldr pc,=Main

 

halt_loop:

    b halt_loop

我认为,最需要理解的就是这段代码了。先简单的解释下这段代码。


(1)由于arm执行reset之后pc会被清零,也就是reset中断的中断入口地址,因此,第一条指令就是b reset,跳转到reset中断处理函数。


(2)由于这里硬件配置都是C语言来完成的,而且我们的初始代码比较小,完全不会超出4KB,因此可以在SRAM使用堆栈,故将SP设置为4096,以提供C运行环境


(3)接下来的3个bl分别完成了关闭看门够定时器,配置时钟信号和存储器配置的工作,第四个bl是将SRAM的4KB空间内的代码拷贝到了SDRAM中。


(4)接下来的ldr句将pc赋值为on_sdram的地址,实现了从SRAM到SDRAM的跳转(下面会讲为什么)


(5)on_sdram中切换到了了系统模式然后分配了系统模式堆栈,将链接寄存器设置为halt_loop然后就跳转到了SDRAM中的Main


上面的解释只是大体上说明了代码的意思,但是初学者总会有个疑问就是为什么ldr pc,=on_sdram就实现了从SRAM到SDRAM的跳转呢?我被这个问题困扰了很长时间,到今天才想明白了这个问题,问题的关键就是相对跳转和绝对跳转的问题。为了说明这个问题我先解释一下bl指令跟ldr指令在执行过程中的区别。


B指令是相对跳转指令,B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间),同样的,BL、BX都是相对跳转。


LDR伪指令是将第二操作直接赋值给第一操作数,当执行ldr pc,=Main时是将Main的绝对地址赋值给了PC。


好了,知道这两个指令的区别之后我们来看代码是如何实现的从SRAM到SDRAM的跳转,首先需要指出,2440的开发板有SRAM和SDRAM,SRAM是从地址0x00000000开始的4KB内存空间,SDRAM是从0x30000000开始的64M空间。


无论用ADS编译还是用arm-linux-gcc编译都会将代码链接到0x30000000以后(也就是SDRAM中),ADS用户可以通过查看ADS的工程配置,其中有项配置是RO起始地址是0x30000000,linux用户在链接时需要用-T指定代码的其实地址为0x30000000。


根据编译原理,在链接阶段程序中函数的地址就已经确定了,也就是说函数的实际地址都在0x30000000之后,而程序的入口函数也就是这里的_start的地址就是0x300000000,其他函数都会大于这个数。


但是由于arm上电后系统会将Nand flash的前4KB代码拷贝到SRAM中,也就是_start函数开始的4KB指令将被拷贝到SRAM中执行,根据上例,在0x00000000处执行的指令就是“b reset”,由于b是相对跳转,是在当前pc值的基础上加减某个数而跳转到将要执行的代码处,因此,pc加减该数之后将到达reset函数的位置,故reset函数不能写到4KB之外的空间中,否则arm的启动将会失败,同样的,接下来的几个bl都是执行的相对跳转,所以都相对当前pc进行的跳转,由于Nand flash总共只有64M的空间,所以相对跳转是不可能会跳转到SDRAM的,因为跳转到SDRAM至少要发生0x30000000的跳转,而这个相对位移远远大于64M。


而ldr pc,=Main是将Main函数的实际地址赋值给pc,而Main的实际地址是在0x30000000之后,这样,就从SRAM跳转到了SDRAM。


由于这个过程设计到了硬件格局和编译原理,所以对一般人来讲,理解起来确实比较困难,而且受本人水平限制,很多地方只能说是只可意会不可言传,如果误导了大家请大家谅解。当然如果看到这里还不能理解arm的启动过程可以留言讨论这个问题。下面是相关的其他代码,我附在这里,2440addr.h没有贴出,由于我也是使用arm自带示例程序中的代码,而且代码有四千多行,多数地址是没有用到的。其他的代码如下


代码Init.s

#include "2440addr.h"

 

void disable_watch_dog(void);

void clock_init(void);

void memsetup(void);

void copy_steppingstone_to_sdram(void);

void inituart(void);

 

void disable_watch_dog(void)

{

rWTCON = 0;

}

 

void clock_init(void)

{

rCLKDIVN  = 0x03;

 

/*

*如果HDIVN非0,CPU的总线模式应该从

*“fast bus mode”变为“asynchronous 

*bus mode”

*/

__asm__(

"mrc    p15, 0, r1, c1, c0, 0n"

"orr    r1, r1, #0xc0000000n"

"mcr    p15, 0, r1, c1, c0, 0n"

   );

 

rMPLLCON = (92<<12)|(1<<4)|(2);

//rMPLLCON =  ((0x5c<<12)|(0x01<<4)|(0x02));

}

void memsetup(void)

{

volatile unsigned long *p = (volatile unsigned long *)0x48000000;

/* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

* 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到

* SDRAM之前就可以在steppingstone中运行

*/

/* 存储控制器13个寄存器的值 */

p[0] = 0x22011110;     //BWSCON

p[1] = 0x00000700;     //BANKCON0

p[2] = 0x00000700;     //BANKCON1

p[3] = 0x00000700;     //BANKCON2

p[4] = 0x00000700;     //BANKCON3  

p[5] = 0x00000700;     //BANKCON4

p[6] = 0x00000700;     //BANKCON5

p[7] = 0x00018005;     //BANKCON6

p[8] = 0x00018005;     //BANKCON7

/* REFRESH,

* HCLK=12MHz:  0x008C07A3,

* HCLK=100MHz: 0x008C04F4

*/ 

p[9]  = 0x008C04F4;

p[10] = 0x000000B1;     //BANKSIZE

p[11] = 0x00000030;     //MRSRB6

p[12] = 0x00000030;     //MRSRB7

}

void copy_steppingstone_to_sdram(void)

{

unsigned int *pdwSrc  = (unsigned int *)0;

unsigned int *pdwDest = (unsigned int *)0x30000000;

while (pdwSrc < (unsigned int *)4096)

{

*pdwDest = *pdwSrc;

pdwDest++;

pdwSrc++;

}

}

注意:由于我们的代码比较小,远小于4KB,因此arm启动时自动拷贝到SRAM中的4KB代码包含我们的全部代码,因此copy操作我是将stepingstone中的4KB代码拷贝到了SDRAM中,在实际应用中代码多数是超过4KB,因此copy函数应该是将Nand flash中的全部代码拷贝到SDRAM,这样才能成功运行ARM。

代码Main.c:


#include "2440addr.h"

 

void Delay(int i)

{

int m,n,p;

for(m = 0; m != i; ++ m)

{

for(n = 0; n != 255; ++ n)

{

for(p = 0; p != 255; ++ p)

;

}

}

}

 

void Main()

{

int count;

int leds[4] = {0x1c0, 0x1a0, 0x160, 0xe0};

 

rGPBCON=0x00155555;

rGPBUP=rGPBUP&0xFF00;

 

while(1)

{

for(count = 0; count != 4; ++ count)

{

rGPBDAT=leds[count];

if(count%2)

rGPBDAT+=1;

Delay(2);

}

}

}


链接文件led.lds如下:

SECTIONS

{

. = 0x30000000;

.text : {*(.text)}

.rodata ALIGN(4) : {*(.rodata)}

.data ALIGN(4) : {*(.data)}

.bss ALIGN(4) : {*(.bss) *(COMMON)}

}


makefile如下:

objects:=Head.o Init.o Main.o

 

led.bin : $(objects)

arm-linux-ld -Tled.lds -nostdlib -o led_elf $^

arm-linux-objcopy -O binary -S led_elf $@

arm-linux-objdump -D -m arm led_elf > led.dis

 

%.o:%.c

arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.s

arm-linux-gcc -Wall -O2 -c -o $@ $<;

.PYTHON:clean

clean:

rm -f led.bin led_elf led.dis *.o


如上除了2440addr.h之外就都全了,另外需要指出的是2440addr.h中引用了Option.h,为了简化代码,可以将这句可以注释掉,在我们这段代码中完全用不到该文件相关功能。否则需要自行修改makefile文件完成Option.h相关的编译和链接工作。

推荐阅读

史海拾趣

Dailywell Electronics Co Ltd公司的发展小趣事

进入21世纪后,德利威电子加速了其国际化布局的步伐。2000年,公司在中国大陆东莞成立了德利威电子厂,并成功推动了5S运动(整理、整顿、清扫、清洁、素养),进一步提升了公司的管理水平。同时,公司还取得了ISO-9001国际认证标准,标志着其质量管理体系的进一步完善。此外,德利威电子还取得了德国TUV产品安规认证,进一步增强了其产品的国际竞争力。

Herth+Buss Fahrzeugteile GmbH & Co KG公司的发展小趣事
在特定情况下(如宠物活动、热气流等),可能引发误报。
Analog Power公司的发展小趣事

为了进一步扩大市场份额,Analog Power公司积极寻求与行业内外的合作伙伴建立战略合作关系。他们与多家知名企业建立了紧密的合作关系,共同开发新产品、开拓市场。通过合作,Analog Power不仅获得了更多的市场资源和技术支持,也提升了自身的品牌影响力和竞争力。

AOS公司的发展小趣事

进入20世纪,AOS公司开始将目光投向热水领域。1936年,公司研发出了著名的“金圭特护内胆”技术,这一创新在热水器行业中引起了革命性的变化。金圭内胆不仅提高了热水器的耐用性和安全性,也大幅提升了产品的能效。这一技术的推出使AOS公司迅速成为热水领域的领先者,并奠定了其在全球热水器市场的领导地位。

Anders DX公司的发展小趣事

除了热水领域,AOS公司还积极拓展其业务范围,涉足了水处理、空气净化等多个领域。公司坚持创新驱动的发展战略,不断投入研发资源,推出了一系列具有创新性和高性能的产品。这些产品的推出不仅丰富了AOS的产品线,也进一步提升了其在全球市场的竞争力。

Able Systems公司的发展小趣事

随着电子行业的快速发展,Able Systems公司不断引进新技术,对产品进行升级改进。公司在打印机的设计和制造方面结合独家采购的领先技术,确保产品能够满足最苛刻的要求。这种对技术创新的执着追求,使得Able Systems的产品在行业中始终保持领先地位。

问答坊 | AI 解惑

菜鸟向高手

各为前辈 大哥 大姐 有谁有有关PCB排板的精谈资料 发晚辈一份 在此万分感谢…

查看全部问答>

利用DB SDK短信成功应用于证券行业

证券行业普遍面临的问题: 信息交互问题:信息传递的时间段集中、信息交互量大,交互次数频繁,难以实现数据集中以及实时交互管理; 资讯服务问题:股市行情多变,客户不便随时随地及时准确的了解交易情况和信息; 系统及数据安全; 客户管理; ...…

查看全部问答>

找工作的看过来

我公司最近狂招人!职位有结构,电子,软件。…

查看全部问答>

请教edge编程开发问题

请教在进行基于edge的程序开发时,是否和基于gprs的开发代码是兼容的?还是要另外根据edge的特点来写代码? 哪里有相关编程资料了? 谢谢! …

查看全部问答>

波特率的问题请教

我对硬件不怎么了解,想问一下如果发送的硬件的波特率是19200,接收的波特率是9600,这之间可以进行准确通信么,就是19200的向9600的发送数据,后者可以识别发送的具体是什么么? 谢谢 …

查看全部问答>

485通讯大家谈

各位大侠好,最近遇到一个实际问题,和大家分享一下. 485通讯在家没有问题,然而到了工作现场,工作一段时间就不行了.拿到家里来又没有问题了. 奇怪? 另外现场总线的长度有个500~600m吧,我用的波特率为:2400; 现场接线属于星形接法,总线型在现场不 ...…

查看全部问答>

C2000最小系统板你最想DIY哪一种型号的?

大家来说说C2000最小系统板你最想DIY哪一种型号…

查看全部问答>

EXTI 寄存器中挂起寄存器(EXTI_PR)的问题

本人stm32还未入门者,图中画红线的这句话令我犯晕,既然该位被置’1’ 。为什么在该位中写入’1’可以清除它??各位大神求解释 …

查看全部问答>

ISE 10.1乘法器IP核调用

ISE10.1的乘法器IP核能调用吗?我的为什么用不了啊?或者是我的方法使用不对,,请各位指导一下啊~~感激不尽!!!…

查看全部问答>

请各位师兄师姐帮忙想个科研课题 做科研立项

小弟是刚开始学的51单片机,想做个科研立项,没有什么好的想法 ,麻烦各位师兄师姐帮帮忙,想下,最好是新颖些,难度不要太难,我想做一次就做好它,先谢谢大家了…

查看全部问答>