?一、 TQ2440上的nand flash是K9F2G08U0B
1.1 Page Block Device三者的关系(见datasheet P6)
1Page = (2k+64)Bytes
1Block = 64*Pages = 64*(2K+64)Byte=(128K+4k)Byte
1Device = 2048*Blocks = 2048*(64*Pages)Bytes
1.2 nand flash初始化
对于K9F2G08U0A的初始化,几乎所有的帖子都说:需要TACLS+TWRPH0+TWRPH1>=46ns,(其中TACLS = tCLS(12)+tALS(12) ?TWRPH0 = tWP(12) ?TWRPH1 = tCLH(5)+tALH(5)),所以TACLS?=0,TWRPH0=3,TWRPH1=0,?+TWRPH0+TWRPH1=50ns,满足要求。
但是修改nand flash的初始化配置:将TACLS=0;TWRPH0=1;TWRPH1=0; 也是正常的。但是TACLS=0;TWRPH0=0;TWRPH1=1;就不正常了。这三者需要满足的关系十分不解,还望高手指教。
1.3?读取数据时地址的发送
从K9F2G08X0B 电路图中可以看出:
? ? ? ??
NCON = 1 ; // 1: Advance NAND flash(1KWords/2KBytes page size,4/5 address cycle)
GPG13 = 1 ; // 1: Page=2KBytes(NCON = 1)
GPG14 = 1 ;? // 1: 5 address cycle(NCON = 1)
GPG15 = 0 ;? // 0: 8-bit bus width
从上述硬件连接中可以看出,需要5个时钟周期才发送一个完整的地址。
上图中column address(A0-A11 12位) Row Address(A12-A28 17位)
column address:
? ? 即页内的地址(0-2112) 1Page=(2k+64)Bytes,所以需要12位,但实际上不访问后面64个字节的,所以只需要11位即可
Row Address:
? ? 页地址,一共有2048*64=0x20000个页,需要17位指定。
二、代码
root@ubuntu:~/myboot# tree
.├── main.c├── Makefile├── nand.c├── sdram.c├── start.S└── u-boot.lds
2.1 start.S
- .text
- .global _start
- _start:
- _TEXT_BASE:
- ????.word 0x33d80000
-
- .globl _armboot_start
- _armboot_start:
- ????.word _start
-
- ????ldr r0,=0x53000000????
- ????mov r1,#0x0
- ????str r1,[r0]
-
- #define COCKTIME????0x4C000000????
- #define MPLLCON????????0x4C000004
- #define UPLLCON????????0x4C000008
- #define CLKCON????????0x4C00000C
- #define CLKSLOW????????0x4C000010
- #define CLKDIVN ????0x4C000014
- #define CAMDIVN ????0x4C000018
- ????/*FCLK:HCLK:PCLK=1:4:8*/
- ????ldr r0,=CLKDIVN
- ????mov r1,#0x05
- ????str r1,0)">
- ????mrc p15,r0,c1,c0,0
- ????orr r0,#0xc0000000
- ????mcr p15,0
-
- ????/*MPLL=(2*m*Fin)/(P*(1<<s)),m="(MDIV+8)," p="PDIV+2" s="SDIV*/
- ????ldr r0,=MPLLCON
- ????ldr r1,=((0x5C<<12)|(0x01<<4)|(0x01))
- ????str r1,[r0]
- ????
- ????ldr r0,=0x10000
- 1:
- ????sub r0,#1
- ????bne 1b
- ????/*UPLL=(m*Fin)/(P*(1<<s))," p="(PDIV+2)," s="SDIV*/
- ????ldr r0,=UPLLCON
- ????ldr r1,=((0x10<<12)|(0x01<<4)|(0x01))
- ????str r1,[r0]
- ????ldr r0,=0x10000
- 1:
- ????sub r0,#1
- ????bne 1b
-
- ????ldr sp,=1024*4
- ????bl init_sdram
-
- ????/*设置栈指向内存地址 (0x33d80000+128k)*/
- ????ldr sp,=0x33dA0000
-
- ????/*dest=0x33d80000 src=0x0 size=16k*/
- ????bl nand_init ;初始化nand flash
- ????ldr r0,=0x33d80000
- ????mov r1,#0x0
- ????ldr r2,=1024*16
- ????bl nand_read_page;将nand flash上的boot读到内存0x33d80000处,大小为16k
- ????
- ????ldr pc,_main;跳转到内存中的main中执行
- loop:
- ????b loop
- _main: .word main
2.2 nand.c
#define NFCONF ???????? (*(volatile unsigned int *) 0x4E000000)
#define NFCONT ???????? (*(volatile unsigned int *) 0x4E000004)
#define NFCMMD ???????? (*(volatile unsigned int *) 0x4E000008)
#define NFADDR ???????? (*(volatile unsigned int *) 0x4E00000C)
#define NFDATA ???????? (*(volatile unsigned char *) 0x4E000010) //注意:类型char
#define NFMECCD0 ???? (*(volatile unsigned int *) 0x4E000014)
#define NFMECCD1 ???? (*(volatile unsigned int *) 0x4E000018)
#define NFSECCD ???? (*(volatile unsigned int *) 0x4E00001C)
#define NFSTAT ???????? (*(volatile unsigned int *) 0x4E000020)
#define NFESTAT0 ???? (*(volatile unsigned int *) 0x4E000024)
#define NFESTAT1 ???? (*(volatile unsigned int *) 0x4E000028)
#define NFMECC0 ???? (*(volatile unsigned int *) 0x4E00002C)
#define NFMECC1 ???? (*(volatile unsigned int *) 0x4E000030)
#define NFMECC ???????? (*(volatile unsigned int *) 0x4E000034)
#define NFSBLK ???????? (*(volatile unsigned int *) 0x4E000038)
#define NFEBLK ???????? (*(volatile unsigned int *) 0x4E00003C)
/*nand command */
#define NAND_CMD_RESET ????0xFF
#define NAND_PAGE_SIZE????2048
#define NAND_PAGE_MASK????(NAND_PAGE_SIZE-1)
static void nand_chip_select(void)
{
????int i;
????NFCONT &= ~(1<<1);
????for(i=0; i<10; i++);
}
static void nand_chip_deselect(void)
{
????NFCONT |= (1<<1);
}
static void nand_write_cmd(unsigned char cmd)
{
????NFCMMD = cmd;
}
static void nand_write_addr(unsigned int addr)
{
????int col,page;
????int i;
????col = addr & NAND_PAGE_MASK;
????page = addr / NAND_PAGE_SIZE;
????
????NFADDR = col & 0xff;????????????/* Column Address A0~A7 */
????for(i=0; i<10; i++);????????
????NFADDR = (col >> 8) & 0x0f;????????/* Column Address A8~A11 */
????for(i=0; i<10; i++);
????NFADDR = page & 0xff;????????????/* Row Address A12~A19 */
????for(i=0; i<10; i++);
????NFADDR = (page >> 8) & 0xff;????/* Row Address A20~A27 */
????for(i=0; i<10; i++);
????NFADDR = (page >> 16) & 0x03;????/* Row Address A28~A29 */
????for(i=0; i<10; i++);
}
static void nand_wait_idle(void)
{
????while( !(NFSTAT & 0x01))
????????;
}
static void nand_reset(void)
{
????nand_chip_select();
????nand_write_cmd(NAND_CMD_RESET);
????nand_wait_idle();
????nand_chip_deselect();
}
static unsigned char nand_read_byte(void)
{
????return (NFDATA&0xFF);
}
void nand_init(void)
{
#define TACLS????0x0
#define TWRPH0 ????0x03
#define TWRPH1 ????0x0
????NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
????NFCONT = (0x01<<4)|(0x01<<1)|(0x01<<0);
????nand_reset();//初次使用时要先复位一下
}
/*调用这个函数时要保证size是按页对齐的*/
void nand_read_page(unsigned char * dest_addr,unsigned long src_addr,unsigned int size)
{
????int i,j;
????NFCONT &= ~(1<<1);
????for(i=0; i<10; i++);
????for(i=0; i<size (nand_page_size);="" i++)="" <="" li="" style="word-wrap: break-word;">
????{
????????nand_write_cmd(0x00);
????????nand_write_addr(src_addr+i*NAND_PAGE_SIZE);
????????nand_write_cmd(0x30);
????????nand_wait_idle();
????????//read one block
????????for(j=0; j<nand_page_size; j++)="" <="" li="" style="word-wrap: break-word;">
????????{
????????????*dest_addr = nand_read_byte();
????????????dest_addr ++;
????????}
????}
????nand_chip_deselect();
}