SEP4020在芯片上电时可以根据SystemSetup[2:0]硬件连线决定启动方式。如下,
SystemSetup[2:0]
000: NOR 启动
001: NAND 启动 3 级地址,512 字节/页
010: NAND 4 级地址 512 字节/页
011: NAND 4 级地址 2K 字节/页
100: NAND 5 级地址 2K 字节/页
当选择为nandflash启动时,芯片上电时,系统0地址将被映射到NandFlash控制器的FIFO处,即0x110002000地址。硬件自动根据跳线设置向NandFlash发出读命令,将第一页代码读取到NandFlash控制器的FIFO中,CPU从此FIFO中取指并执行,直到取完这一页的数据。需要注意的是,系统刚上电或复位时,NandFlash 控制器的FIFO 具有唯一地址0x00000000,而0x11000200 地址(一般情况下的NandFlash 控制器FIFO 地址)不可访问;而当NandFlash 第一页的数据被搬空后(对于512+16 字节的NandFlash 而言,即132 条指令或数据字),系统零地址将自动恢复到CSA 自选上,系统的地址映射将恢复到原始状态。
在手册介绍存储器一章有这样一句话,
由于SEP4020 的NandFlash 控制器没有设计FIFO 状态寄存器,因此只能使用DMA 来搬运数据,而且必需将当前NandFlash 操作产生的数据(528、272 或16 个字节)全部搬运,否则将对下一次操作产生不可预料的影响。
一。DMA模块的使用
可以看出这个启动代码要先会用DMA,下面简要介绍下DMA模块的使用
直接内存访问(DMA)方式,是一种完全由硬件执行I/O 交换的工作方式。在这种方式中,DMA 控制器从CPU 完全接管对总线的控制,数据交换不经过CPU,而直接在存储器之间或内存和I/O 设备之间进行。DMA 方式一般用于高速传送成组的数据。DMA 控制器在获得总线仲裁器或CPU 授权占用总线后,将向内存和外设发出地址和控制信号,修改地址,对传送的字的个数计数,并且以中断方式向CPU 报告传送操作的结束。DMA 技术用硬件的方法,在外设与主存之间开辟数据交换的直接通路,且在数据传送过程中不再经CPU 的中转与控制,从而让CPU 空出时间去处理其它任务,实现外设与内存之间传送数据和CPU 执行程序这两大任务的并行进行
例程如下,
外设(地址为dsadr)到存储器(地址为dtadr)的DMA 方式,传输1K 字节。源外设号为:psda。
- *(RP) DMAC_INTINTERRCLR |= 0x1; //(1)
- *(RP) DMAC_INTINTERRCLR &= ~(0x1);
- *(RP) DMAC_INTTCCLEAR |= 0x1;
- *(RP) DMAC_INTTCCLEAR &= ~(0x1);
- *(RP) DMAC_C0SRCADDR = dsadr; //(2)
- *(RP) DMAC_C0DESTADD = dtadr; //(3)
- *(RP) DMAC_C0CONTROL = ( 1024 << 14 ) + (0 << 9 ) + ( 0 << 6 ) + ( 5 << 3 ) + 5; //(4)
- /*配置通道配置信息到DMaCCxConfiguration 寄存器中。如果使能位已被置位,那么该DMA
- 通道将被自动使能。*/
- /* DMA通道0配置寄存器*/
- /* 非链表传输方式,控制方:DMAC,存储器到存储器,通道使能。*/
- *(RP) SrcPeripheral = psda ;
- *(RP) DMAC_C0CONFIGURATION = ( 0 << 15 ) + ( SrcPeripheral << 7 ) + (0<< 6 ) +
- (0<< 4 ) + (0<< 3 ) + ( 0 << 1 ) + 1;//(5)
- while(((*(RP)( DMAC_INTTCSTATUS)) & 0x1) != 0x1 ){ //(6)
- delay(10);
- }
(1)选择一个具有所需优先级的空闲的DMA通道,示例选择的是通道0,配置DMACIntTCClear和DMACIntErrClr 寄存器,清除您想使用的通道上的所有未响应的中断.
DMAC_INTINTERRCLR表示DMACIntErrClr寄存器,此寄存器介绍如下,
只写寄存器 DMACIntErrClr 用于清除错误中断。特定通道的位写高时,将清除状态寄存器(中断状态寄存器DMACIntStatus和错误中断状态寄存器DMACIntErrorStatus)中相应通道的中断响应位。在系统应用中,如果要清除某个中断需要先对该为写1,然后接着再对该位写0。低电平对寄存器的响应位无效。所以*(RP) DMAC_INTINTERRCLR |= 0x1;*(RP) DMAC_INTINTERRCLR &= ~(0x1);这两句对通道0完成了先写1再写0.
DMAC_INTTCCLEAR表示DMACIntTCClear寄存器,此寄存器介绍如下,
只写寄存器 DMACIntTCClear 用于清除传输完成中断。特定通道的位写高时,将清除状态寄存器中相应通道的中断响应位。在系统应用中,如果要清除某个中断需要先对该为写1,然后接着再对该位写0。低电平对寄存器的响应位无效。代码原理同上。
(2)设置DMA的源地址(外设地址)
(3)设置DMA的目标地址(内存地址)
(4)DMAC_C0CONTROL表示DMACC0Control通道0控制寄存器,其中各位意义
2:0 SourceBurst,源(SBSize)Burst 尺寸 ,代码中5=101 ,101B:8,表示源地址尺寸为一个字节。
(5)DMAC_C0CONFIGURATION表示DMACC0Configuration通道0配置寄存器,( 0 << 15 )第15位通道号为0(0号通道,应与实际相符)。( SrcPeripheral << 7 )第七位是源的外设号如果是存储器这些位将被忽略,SrcPeripheral是上条语句的psda(0110)。(0<< 6 )第6位表示控制方是谁,0是DMAC,1是外设。(0<< 4 )传输完成中断屏蔽,0表示不屏蔽。(0<< 3 )第3位中断错误屏蔽,0表示不屏蔽。( 0 << 1 )?第1位表示传输类型,此处应为10,表示外设到存储器,这里源码应是写错了,写成0了。第0位通道使能位,1表示使能。
(6)每隔10个delay检查DMAC_INTTCSTATUS(DMACIntTCStatus传输完成中断寄存器),这个的第0位即通道0上的传输是否完成。
二。nand flash控制模块
我们再来分析一下一个nandflash的读函数。
- U32 NandRead(U32 DestAddr,U32 NandPage)
- {
- U32 i,NTM = 0x0;
- *(RP)DMAC_C0SRCADDR = EMI_NAND_DATA; //(1)
- *(RP)DMAC_C0DESTADD = DestAddr;
- *(RP)DMAC_C0CONFIGURATION = 0x31d; //(2)
- *(RP)EMI_NAND_COM = NAND_CMD_READ0; //(3)
- delay(3000);
- i = *(RP)EMI_NAND_IDLE;
- while((i&0x1) != 0x1) //(4)
- {
- delay(30);
- NTM++;
- if(NTM == 0x5) break;
- i = *(RP)EMI_NAND_IDLE;
- }
- if(NTM >= 0x5) return E_HA; //读超时
- return E_OK; //读完成
- }
(1)EMI_NAND_DATA是nandflash FIFO寄存器地址0x11000200这是nandflash的数据接口。将它配置为DMA的传输源地址。
(2)0x31d = 110 0 0 1 1 10 1 = (5<<7)源外设位nand + (0<<6)控制方为DMA + (1<<4)屏蔽完成中断 + (1<<3)屏蔽错误中断 + (2<<1)传输类型为从外设到存储器 +1通道使能。
(3)EMI_NAND_COM(NAND_CMD控制字寄存器),NAND_CMD_READ0是配置好的nand命令。0-7位是控制命令的第一字节,8-15第二个字节命令,30位表示是几个字节命令,0为1个字节,1为两个字节。
(4)通过NandFlash 空闲寄存器判断NandFlash 是否完成操作,EMI_NAND_IDLE(NAND FLASH空闲寄存器NAND_IDLE),第0位,0表示忙,1表示空闲。
三、nand flash启动代码分析。
数据手册中推荐的nandflash启动步骤如下,
1) 上电或复位时,NandFlash 控制器根据SystemSetup 不同设置,向NandFlash 发出相应地址和Read0 命令,将4 条指令读取到FIFO(4 级深度,32Bit 宽度)中,CPU 从FIFO中取指,当4条指令取空后,NandFlash 控制器再从NandFlash 中获取4 条指令(16Byte),CPU 继续从FIFO 中取指并执行。
2) 烧写在 NandFlash 第一页中的用户启动指令首先配置DMA 控制器,预备将第二页的数据(指令)搬运到RAM 中,源地址即NandFlash 控制器的FIFO 地址0x11000200。由于此时NandFlash 控制器的FIFO只能被0x00000000 地址选通,所以此时尽管NandFIFO中有数据,DMA 也不会开始搬运。
3) 配置 NandFlash 控制器,包括NandFlash 型号相关配置,写入第二页的地址,为第二页的搬运作准备。将来只需要将0x80000000 写入到NandFlash 的命令寄存器,就可以开始搬运第二页的代码。
4) 写指令到 RAM,并配置相应的寄存器。为第六步、第七步的执行准备代码。注意,第六步和第七步操作所使用的指令不是预先写在NandFlash 中的,而是使用指令“构造”出来的。
5) 控制 PC 跳转,跳转到第四步写下的指令处。
6) 执行第四步构造出来的指令,首先清空 NandFlash 控制器的FIFO。由于第一页中有效的启动代码可能会少于512+16 个字节,所以此时有残余的第一页的数据在NandFIFO中,这些残余数据会影响到后面的操作,因此需要在此处清除。需要注意的是,在清除完成之前,只能通过0x00000000 地址访问NandFlash 控制器的FIFO;一旦将残余数据
清除完成,系统零地址将恢复到CSA 上,此时将可以使用 0x11000200 来访问NandFlash控制器的FIFO。由于已经在第二步中初始化了DMA,一旦FIFO 中有数据,将触发DMA 的搬运动作。
7) 继续执行第四步构造出来的指令,将 0x80000000 写入到NandFlash 控制器的命令寄存器中。由于已经在第三步中初始化了NandFlash 控制器的其它寄存器,一旦将命令写到了寄存器,将启动NandFlash 第二页的读操作。DMA 开始将第二页的数据搬运到RAM中。
8) 等待 DMA 搬运完成,控制PC 跳转到RAM 中第二页指令所在的地址,开始执行第二页的指令。一般来说,第二页中将继续完成其它相关硬件的初始化,并将系统映像从NandFlash 搬运到RAM 中,然后跳转到系统映像的入口地址,启动软件系统。
启动代码如下(分析即是注释),
- AREA ONE, CODE, READONLY
- ENTRY
- ;;;;;;;;;;;;;;;;;;;;;;;;;配置DMA控制器;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- mov r0,#0x11000000 ;r0:EMI基址0x11000000
- add r1,r0,#0x1000 ;r1:DMAC基址 0x11001000
- add r2,r0,#0x100 ;r2 NandFlash控制器基地址0x11000100
- add r3,r0,#0x200 ;r3:Nand_Data,NandFlash控制器FIFO入口0x11000200
- str r3,[r1] ;DMA源地址0x11000200 ->0x11001000,设置DMA源地址为nand的FIFO
- mov r4,#0x04000000 ;0x04000000是片内内存ESRAM的地址
- add r4,r4,#0x100 ;r4:NandFlash第二页即将搬运到的地址:0x04000100
- str r4,[r1,#0x4] ;DMA目标地址 0x04000100 ->0x11001004,设置DMA目标地址。
- mov r3,#0x210000 ;
- add r3,r3,#0x2400 ;
- add r3,r3,#0x9b ;
- str r3,[r1,#0xc] ;DMA 0通道控制寄存器DMACC0Control,0x0021249b ->1100100c。
- ;解释以上各个位,0x0021249b = 10000100--1--0--010--010--011--011 从前至后
- ; 10000100:传输尺寸132,(后面位设置传输宽度是32位)。即528字节
- ; 1: 传输目的地址自增加,即内部内存地址
- ; 0: 传输源地址不自增,因为一直要读NandFlash FIFO寄存器(地址0x11000200)
- ; 010: 传输目的数据宽度32bit
- ; 010: 传输源数据宽度32bit
- ; 011: 传输目的尺寸 4 (nandflash必须为4)
- ; 011: 传输源尺寸 4 (nandflash必须为4)
- mov r3,#0x310
- add r3,r3,#0xd
- str r3,[r1,#0x10] ;配置DMA通道使能寄存器DMACCxConfiguration,0x31d ->11001010
- ;0x31d = 110--0--0--1--1--10--1
- ; 110: 传输源类型,nand
- ; 0: 控制方,DMAC
- ; 0: 保留位
- ; 1: 传输完成中断屏蔽位,屏蔽完成中断
- ; 1: 传输错误中断屏蔽位,屏蔽错误中断
- ; 10: 传输方向类型,外设到存储器
- ; 1: 通道使能,使能。
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;配置Nand Flash控制器;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- mov r3,#0x100 ;为什么页内地址要是0x100 = 256 ,(读半个页吗?!),这里应该是nand flash是x16结构
- str r3,[r2] ;第二页地址写入到地址寄存器NAND_ADDR1,0x100 ->11000100,
- ;存放前4个字节的地址,如果5级地址即存放前(低)4个字节的地址
- ;(同时2K页的flash中有个疑问)--2K页的--K9F1G08U0C没有数据手册,不知道是不是通用K9F1G08数据手册,这个应该是4级地址还是5级地址
K9F1G08数据手册 中是4级的,但在项目的代码中为什么按5级地址,并且可以用--
- mov r3,#0x6300000
- add r3,r3,#0x2800
- add r3,r3,#0x57
- str r3,[r2,#0x18] ;配时序寄存器1 0x06302857 ->11000118
- ;0x06302857 = 110--0--011--000000--101000--0101--0111
- ; 110: 在读状态字时,write到read之间的等待周期,默认值
- ; 0: 保留位
- ; 011: 在发送32位地址时截取几个地址,011表示4个 因为是4级地址。
- ; 000000: 保留位
- ; 101000: 发完主控方信息后等待几个周期,默认值。
- ; 0101: 读脉冲数据宽度,默认值
- ; 0111: 写脉冲数据宽度,默认值
- mov r3,#0x510000
- add r3,r3,#0x4300
- add r3,r3,#0x53
- str r3,[r2,#0x28] ;配时序寄存器2 0x00514353 ->11000128
- ;0x00514353 = 0--1--0--100--010100--0011--01--01--00--11
- ; 0: 页大小,0是512B
- ; 1: ECC硬件实现还是软件,1是软件
- ; 0: 保留
- ; 100: Ready到Re位低的时钟周期数,默认值
- ; 010100:ALE低到Ready时的时钟周期数,默认值
- ; 0011: Re信号保持为高的时钟周期,默认值
- ; 01: CLE信号为高的时钟周期,默认值
- ; 01: ALE信号位高的时钟周期,默认值
- ; 00: 保留位
- ; 11: We信号为高的时钟周期数,默认值
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;将4条指令写到0x04000000,清空NandFlash控制器;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;以下代码主要是将4条指令写入ESRAM中,4条指令功能是循环读取nandflash FIFO 直到将一页数据读完(nand_idle为1)
- mov r5, #0x04000000 ;写到ESRAM地址
-
- mov r3,#0xE5000000
- add r3,r3,#0x910000
- str r3,[r5],#0x4 ;0x04000000:0xE5910100( ldr r0,[r1] ;读NandFlash控制器的FIFO,清空数据* )
- ;0xE5910100 这是一条指令的机器码 翻译成汇编就是ldr r0,[r1],
- ;此句将此指令放入片内内存起始地址,并且将r5片内内存起始地址指针加4,运行到这句时r1应为0(此代码最后会将r1设置为0
- ;然后在跳转到0x04000000),此时硬件将0x0地址被映射Nand的 FIFO
- add r3,r3,#0x10000
- add r6,r3,#0x24
- str r6,[r5],#0x4 ;0x04000004:0xE5920024( ldr r0,[r2,#0x24] ;读Nand_Idle )
- ;;r2在跳转到0x04000000前是0x11000100,加24,0x11000124,nand flash 空闲寄存器。最低位0是忙,1是空闲。
-
- mov r7,#0xE3000000
- add r7,r7,#0x500000
- str r7,[r5],#0x4 ;0x04000008:0xE3500000( cmp r0,#0 如果不为1,代表还有数据 )
-
- mvn r8,#0
- and r8,r8,#~0xF5000000
- and r3,r8,#~0x4
- str r3,[r5],#4 ;0x0400000C:0x0AFFFFFB( beq 0x04000000 ;如果还有数据,继续读)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;后续指令搬运第二页代码至0x04000100;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- mov r3,#0xe5000000
- add r3,r3,#0x820000
- add r3,r3,#0x3000
- add r3,r3,#0x4
- str r3,[r5],#0x4 0x04000010:0xe5823004( str r3,[r2,#4] ;写入NandFlash读命令 )
- ;r2+4 等于 0x11000104,nand flash命令控制字寄存器。r3在跳入前被设置为0x80000000。
- ;31位是nand flash 使能位,nand flash 地址寄存器在前面设置了(0x100 ->11000100)
- str r6,[r5],#0x4 ;0x04000014:0xE5920024( ldr r0,[r2,#0x24] ;读Nand_Idle ),
- ;r6是上一段设置了的是0xE5920024
- str r7,[r5],#0x4 ;0x04000018:0xE3500000( cmp r0,#0 ;如果不为1,代表还有数据 )
- ;r7是上一段设置了的是0xE3500000
-
- and r3,r8,#~0x3
- str r3,[r5],#4 ;0x0400001C:0x0AFFFFFC( beq 0x04000014 ;如果还有数据,继续等待DMA搬运完成 )
- ;是DMA自动搬运到内存,一直读Nand_Idle寄存器,检查nand是否空闲了即可。
-
- mov r3,#0xe1000000
- add r3,r3,#0xa00000
- add r3,r3,#0xf000
- add r3,r3,#0x4
- str r3,[r5],#0x4 ;0x3000000c:0xe1a0f004( mov pc,r4 ;跳转到0x04000100执行第二页代码 )
- ;从跳转地址我们可以看出,这里的一页数据0x100=256,不是之前认为的一页是512。
- ;这里还是留了一些疑问,512页flash数据手册中有00h读(从一页的开始),和01读(从一页中部读)。
- ;那到底一个读命令是读一页(512),还是读半页(256).????
-
- mov r0,#0x04000000 ;r0:0x04000000 第一次跳转的地址
- mov r1,#0x0 ;r1:0x00000000 清空NandFlash控制器的FIFO用*
-
- ;r2:0x11000100 NandFlash控制器基地址,+4 NandFlash命令寄存器
- mov r3,#0x80000000 ;r3:0x80000000 NandFlash读命令,搬运第二页代码至0x04000100
- mov pc,r0
- END
分析nand flash启动的第二部分,这部分应该烧写到flash的第二页。这页中的代码会被第一页的代码搬运到0x40000000片内内存,然后执行。
- AREA TWO, CODE, READONLY
- ENTRY
- ;;;;;;;;;;;;;;;;;;;;;;;;;SET PMU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ldr r4, =0x10001000 ;PMCR,配置系统频率为88M
- ldr r5, =0x0000400b
- str r5, [r4,#0x4]
-
- mov r5, #0x00000001 ;配置PMDR,芯片工作模式为NORMAL
- str r5, [r4,#0x14]
-
- ldr r5, =0x0000c00b
- str r5, [r4,#0x4] ;96M
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;SET EMI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ldr r4, =0x11000018 ;SDRAM时序配置寄存器1
- ldr r5, =0x1E104177
- str r5, [r4]
-
- ldr r5, =0x80001860
- str r5, [r4,#0x4] ;SDRAM时序配置寄存器2
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;REMAP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ldr r4, =0x11000020 ; 重映射cse到0地址
- ldr r5, =0x0000000b ; 101(CSE)-1(使能)
- str r5, [ r4 ]
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;ADDR and LOOPS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ldr r3, =0x260 ;读出的页数
- ldr r6, =0x2000 ;NandAddr,Page 32,Block 2
- ldr r7, =0x30700000 ;DstAddr
- ;这个芯片如果用这个启动代码,uboot等要烧写在flash的第2块,一块32页。且uboot也不需要再搬运,因为这里已经搬运过了。
- ;uboot会被搬运到0x30700000处,内存的7M处。
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;配置Nand Flash控制器;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ldr r4, =0x11000100 ;EMI_Nand base addr
-
- ldr r5, =0x06302857
- str r5, [r4,#0x18] ;NandConfig1:
- ;0x06302857 = 110--0--011--000000--101000--0101--0111
- ; 110: 在读状态字时,write到read之间的等待周期,默认值
- ; 0: 保留位
- ; 011: 在发送32位地址时截取几个地址,011表示4个 因为是4级地址。
- ; 000000: 保留位
- ; 101000: 发完主控方信息后等待几个周期,默认值。
- ; 0101: 读脉冲数据宽度,默认值
- ; 0111: 写脉冲数据宽度,默认值
- ldr r5, =0x00514353
- str r5, [r4,#0x28] ;NandConfig2:0x00514353
- 0x00514353 ->11000128
- ;0x00514353 = 0--1--0--100--010100--0011--01--01--00--11
- ; 0: 页大小,0是512B
- ; 1: ECC硬件实现还是软件,1是软件
- ; 0: 保留
- ; 100: Ready到Re位低的时钟周期数,默认值
- ; 010100:ALE低到Ready时的时钟周期数,默认值
- ; 0011: Re信号保持为高的时钟周期,默认值
- ; 01: CLE信号为高的时钟周期,默认值
- ; 01: ALE信号位高的时钟周期,默认值
- ; 00: 保留位
- ; 11: We信号为高的时钟周期数,默认值
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;开始搬运;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ldr r10, =0x11000100 ;EMI_NAND_ADDR1,+4 for EMI_NAND_COM NAND_ADDR1
- ldr r11, =0x11001004 ;DMA Dst ADDR reg DMA目的地址
- ldr r8, =0x80000000 ;Nand Read Command
- NextPage
- ;;;;;;;;;;;;;;;;;;;;;;;;;配置DMA控制器;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ldr r4, =0x11001000 ;DMAC Base ADDR DMA源地址
-
- ldr r5, =0x11000200
- str r5, [r4] ;SrcAddr reg:NandFIFO
-
- ldr r5, =0x0021249b
- str r5, [r4,#0xc] ;DMAConfig:0x0021249b
- 0x0021249b = 10000100--1--0--010--010--011--011 从前至后
- ; 10000100:传输尺寸132
- ; 1: 传输目的地址自增加,即内部内存地址
- ; 0: 传输源地址不自增,因为一直要读NandFlash FIFO寄存器(地址0x11000200)
- ; 010: 传输目的数据宽度32bit
- ; 010: 传输源数据宽度32bit
- ; 011: 传输目的尺寸 4 (nandflash必须为4)
- ; 011: 传输源尺寸 4 (nandflash必须为4)
- ldr r5, =0x0000030d
- str r5, [r4,#0x10] ;DMAEnable:0x0000030d,不屏蔽传输完成中断
- ;0x30d = 110-0-0-0-1--10--1
- ; 110: 传输源类型,nand
- ; 0: 控制方,DMAC
- ; 0: 保留位
- ; 0: 传输完成中断屏蔽位,不屏蔽完成中断
- ; 1: 传输错误中断屏蔽位,屏蔽错误中断
- ; 10: 传输方向类型,外设到存储器
- ; 1: 通道使能,使能。
- str r7, [r11] ;DstAddr,base is 0x30700000,step is 0x200
-
- str r6, [r10] ;NandAddr,base is 0x2000(Page 32),step is 0x100(one page)
-
- str r8, [r10,#0x4] ;Send the command to read one page
-
- ;;;;;;;;;;;;;;;;;;判断NandFlash控制器空闲,需要额外延时;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ldr r1, =0x11000124
- WaitIdle
- ldr r2, [r1]
- ands r2, r2, #0x1
- beq WaitIdle ;等待Nand_ilde寄存器空闲。
-
- ands r4, r6, #0x1f00 ;r6中保存nand flash内地址
- cmp r4, #0x00
- bne Nextblock
- ;32页一块,1f = 31,与1f(1 1111),就等于,地址如果是块的起始那与的结果就等于0
- ;如果不等于0,即不是块的起始页。就跳转到Nextblock,
- ;;;;其实这段的意思就是,如果是每块的第一页,就不跳转,下面有检查坏块的段
- ;;;;如果不是每块的第一页就跳过坏块检查,接着进行下一页的搬运。
-
- add r4, r7, #0x200 ;r7对应内存地址,内存地址加512,赋值给r4
- ldrb r4, [r4,#0x5] ;读取从页起始对于的内存开始的第6个字节。
- cmp r4, #0xff ;和0xff比较
- beq Nextblock ;如果相等就跳到继续下一页搬运的地方
- add r6, r6, #0x2000 ;如果是坏块就将nand地址加一个块的地址,读下一个块,注意内存的目的地址是没加的。
- B NextPage
- ;;;;这段是坏块检查用的,坏块信息被存在每块的第一个页的oob的第6个字节,如果此字节不是0xff就是坏块
- ;;;;这个程序中,我们每次是搬运一页的,一页实际上有512+16个字节。将这一页读到内存后我们,程序中递增内存是
- ;;;;每次地址0x200(512字节),oob区域在512字节的后面。所以将r7,内存目标地址加512,就是这次读出数据的oob
- ;;;;区域起始地址,再加5就是,坏块标记字节。
- ;;??这里有疑问:一个00的读命令,究竟是读多少个字节512还是528.(这里看应该是528),那50读命令是专门读oob区域的
- ;;??,看来我之前的理解是有误的。现在看来oob区域也可以被00h命令读到,01h命令到底多多少还不清楚(256还是256+16),
- ;;??50h命令应该就只读16字节吧。
-
- Nextblock
- add r7, r7, #0x200 ;内存地址+200 = 512
- add r6, r6, #0x100 ;flash地址+100 =256 ,难道说是X16的flash
- ;累加nand地址和内存地址。
- mov r9,#0x3
- delay
- subs r9,r9,#1 ;延迟
- bne delay
-
- subs r3, r3, #0x1 ;要读取的总页数减1,
- bne NextPage ;如果要读取的总页数还没递减到0,就继续读。
-
- ldr r0, =0x30700000
- mov pc,r0
-
- END
分析此代码也是为了理解清楚nand flash的相关知识,但现在还是有一些没有搞的清楚。接下来好好看看并顺便一下翻译flash数据手册。
阅读(2354) | 评论(0) | 转发(1) |