您的位置 首页 知识

FS2410 开发板上 Nand Flash 到内存的代码搬移

一、目的前面做过一个实验,搬移NandFlash里的前4k代码到内存指定位置,这其实是把SRAM从0x40000000开始的4K代码复…

一、意图

前面做过一个试验,搬移 Nand Flash 里的前 4k 代码到内存指定方位,这其实是把

SRAM 从 0x40000000 开端的 4K 代码复制到 SDRAM 的指定方位,并没有涉及到对 Nand

Flash 的操作。究其原因,开发板上电后,Nand Flash 开端的前 4K 数据会被主动复制到

SRAM 0x40000000 开端的 4K 区域里,这个区域被称为 “Steppingstone”。那咱们这次就来

操作 Nand Flash,读取它 4K 后的代码到 SDRAM 指定方位,并履行 SDRAM 中的代码。

二、代码

经过前面做的几个试验,咱们现已了解了 ARM 开发的根本流程,这能够让咱们更重视于

代码的逻辑。好,先来剖析文件 head.s:

@ 文件 head.s

@ 效果:封闭看门狗、SDRAM 的初始化设置、搬移 Nand Flash 4K 今后

@ 的代码到 SDRAM 的指定方位、履行 SDRAM 中的代码

.text

.global _start

_start:

ldr r0, =0x53000000@ Close Watch Dog Timer

mov r1, #0x0

str r1, [r0]

bl memory_setup @ Initialize memory setting

bl flash_to_sdram@ Copy code to sdram

ldr sp, =0x34000000@ Set stack pointer

ldr pc, =main @ execute the code in SDRAM

@ 文件 mem.s

@ 效果:SDRAM 的初始化设置

@ 关于初始化的更多细节,请参阅我的前一篇漫笔

.global memory_setup @ 导出 memory_setup, 使其对链接器可见

memory_setup:

mov r1, #0x48000000

adrl r2, mem_cfg_val

add r3, r1, #13*4

1:

@ write initial values to registers

ldr r4, [r2], #4

str r4, [r1], #4

cmp r1, r3

bne 1b

mov pc, lr

.align 4

mem_cfg_val:

.long 0x22111110 @ BWSCON

.long 0x00000700 @ BANKCON0

.long 0x00000700 @ BANKCON1

.long 0x00000700 @ BANKCON2

.long 0x00000700 @ BANKCON3

.long 0x00000700 @ BANKCON4

.long 0x00000700 @ BANKCON5

.long 0x00018005 @ BANKCON6

.long 0x00018005 @ BANKCON7 9bit

.long 0x008e07a3 @ REFRESH

.long 0x000000b2 @ BANKSIZE

.long 0x00000030 @ MRSRB6

.long 0x00000030 @ MRSRB7

@ 文件 flash.s

@ 效果:设置 Nand Flash 的操控寄存器、读取 Nand Flash

@ 中的代码到 SDRAM 的指定方位

.equ NFCONF, 0x4e000000

.equ NFCMD, 0x4e000004

.equ NFADDR, 0x4e000008

.equ NFDATA, 0x4e00000c

.equ NFSTAT, 0x4e000010

.equ NFECC, 0x4e000014

.global flash_to_sdram

flash_to_sdram:

@ Save return addr

mov r10,lr

@ Initialize Nand Flash

mov r0,#NFCONF

ldr r1,=0xf830

str r1,[r0]

@ First reset and enable Nand Flash

ldr r1,[r0]

bic r1, r1, #0x800

str r1,[r0]

ldr r2,=NFCMD

mov r3,#0xff

str r3,[r2]

@ for delay

mov r3, #0x0a

1:

subs r3, r3, #1

bne 1b

@ Wait until Nand Flash bit0 is 1

wait_nfstat:

ldr r2,=NFSTAT

ldr r3,[r2]

tst r3,#0x01

beq wait_nfstat

@ Disable Nand Flash

ldr r0,=NFCONF

ldr r1,[r0]

orr r1,r1,#0x8000

str r1,[r0]

@ Initialzie stack

ldr sp,=4096

@ Set arguments and call

@ function nand_read defined in nand_read.c

ldr r0,=0x30000000

mov r1,#4096

mov r2,#1024

bl nand_read

@ return

mov pc,r10

/* 文件 nand_read.c

* 效果:从 Nand Flash 中读取一块数据到 SDRAM 中的指定方位

*/

#define NFCONF (*(volatile unsigned long *)0x4e000000)

#define NFCMD (*(volatile unsigned long *)0x4e000004)

#define NFADDR (*(volatile unsigned long *)0x4e000008)

#define NFDATA (*(volatile unsigned long *)0x4e00000c)

#define NFSTAT (*(volatile unsigned long *)0x4e000010)

#define NFECC (*(volatile unsigned long *)0x4e000014)

#define NAND_SECTOR_SIZE 512

#define NAND_BLOCK_MASK 0x1ff

void wait_idle() {

int i;

for (i = 0; i < 50000; ++i) ;

}

int nand_read(unsigned char *buf, unsigned long start_addr, int size){

int i, j;

/*

* detect the argument

*/

if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

return -1;

}

/* chip Enable */

NFCONF &= ~0x800;

for (i=0; i<10; i++) {

;

}

for (i=start_addr; i < (start_addr + size); i+=NAND_SECTOR_SIZE) {

NFCMD = 0;

/* Write Address */

NFADDR = i & 0xff;

NFADDR = (i >> 9) & 0xff;

NFADDR = (i >> 17) & 0xff;

NFADDR = (i >> 25) & 0xff;

wait_idle();

for(j=0; j < NAND_SECTOR_SIZE; j++) {

*buf++ = (NFDATA & 0xff);

}

}

NFCONF |= 0x800; /* chip disable */

return 0;

}

注:Nand Flash 的设置和读取数据的首要流程简略介绍如下:

1. NFCONF = 0xf830

2. 在第一次操作NAND Flash前,一般复位一下:

NFCONF &= ~0x800 (使能NAND Flash)

NFCMD = 0xff (reset指令)

循环查询NFSTAT位0,直到它等于1

3. NFCMD = 0 (读指令)

4. 这步得略微留意一下,请翻开K9F1208U0M数据手册第7页,那个表格列出了在地址操

作的4个过程对应的地址线,A8没用到:

NFADDR = addr & 0xff

NFADDR = (addr>>9) & 0xff (留意了,左移9位,不是8位)

NFADDR = (addr>>17) & 0xff (左移17位,不是16位)

NFADDR = (addr>>25) & 0xff (左移25位,不是24位)

5. 循环查询NFSTAT位0,直到它等于1

6. 连续读NFDATA寄存器512次,得到一页数据(512字节)

7. NFCONF |= 0x800 (制止NAND Flash)

/* 文件 sdram.c

* 效果:循环点 FS2410 开发板上的 D9、D10、D11、D12

* 四个发光二极管。

*/

#define GPFCON (*(volatile unsigned long *)0x56000050)

#define GPFDAT (*(volatile unsigned long *)0x56000054)

int main()

{

int i,j;

while(1) {

for (i = 0; i <4; ++i) {

GPFCON = 0x1<<(8+i*2);

GPFDAT = 0x0;

// for delay

for(j=0;j<50000;++j) ;

}

}

}

/*

* 文件 nand.lds (lds 文件是衔接脚本)

*/

SECTIONS {

first 0x00000000 : { head.o mem.o flash.o nand_read.o }

second 0x30000000 : AT(4096) { sdram.o }

}

注:这个链接脚本是用来传给链接器的,其效果如下:

1. 将 head.o 放在 0x00000000 开端的地址处, mem.o、flash.o、and_read.o

顺次放在 head.o 后边, 它们的运转地址是 0x00000000

2. 将 sdram.o 放在地址 4096 开端处, 但它的运转地址是 0x30000000, 运转前需求

从 4096 处复制到 SDRAM 的 0x300000000 处

完好的衔接脚本文件方式如下:

SECTIONS {

secname start BLOCK(align) (NOLOAD) : AT(ldadr) {contents} >region :phdr =fill

}

并非每个选项都是有必要的,仅从 nand.lds 用到的来看:

(1) secname: 段名,关于 nand.lds, 段名为 first 和 second

(2) start: 本段的运转时地址,假如没有 AT(xxx),则本段的存储地址也是 start

(3) AT(ldadr): 界说本段存储(加载)的地址

(4) {contents}: 决议哪些内容放在本段,能够是整个方针文件,也但是方针文件中的某段

# 文件 Makefile

# 由代码文件生成方针文件,并根据衔接脚本 nand.lds 衔接方针文件,

# 最终将衔接生成的方针文件转换成二进制格局

sdram:head.s flash.s mem.s sdram.c

arm-linux-gcc -c -o head.o head.s

arm-linux-gcc -c -o mem.o mem.s

arm-linux-gcc -c -o flash.o flash.s

arm-linux-gcc -c -o nand_read.o nand_read.c

arm-linux-gcc -c -o sdram.o sdram.c

arm-linux-ld -Tnand.lds head.o mem.o flash.o nand_read.o sdram.o -o sdram_tmp.o

arm-linux-objcopy -O binary -S sdram_tmp.o sdram

clean:

rm -f *.o

rm -f sdram

三、编译、烧写、测验

Make 一下就会生成咱们要的文件 sdram, 将其经过 JTAG 烧入 Nand Flash ,Reset

一下开发板, 呵呵,赏识咱们的效果吧!

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/275677.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部