TQ210 —— NandFlash
发布时间:2020-12-15 20:00:40 所属栏目:百科 来源:网络整理
导读:TQ210 —— nandflash ? ? TQ210 开发板板载一片 1Gbyte 的 NAND FLASH——K9K8G08U0B,通过查询K9K8G08U0B 芯片手册可以得到如下信息:(理论知识不再介绍) K9K8G08U0B : (1G + 32M) x 8bit 总大小 Data Register : (2K + 64) x 8bit 数据寄存器 Page Prog
TQ210 —— nandflash
K9K8G08U0B : (1G + 32M) x 8bit 总大小 Data Register : (2K + 64) x 8bit 数据寄存器 Page Program : (2K + 64)Byte 页编程 Block Erase : (128K + 4K)Byte 块擦除 Page Read: (2K + 64)Byte 页读 ? 我们需要按上面这个地址周期表来发地址。 对NFDATA 寄存器的定义(参考 S5PV210 芯片手册 4.3.1.1 8-bit NAND Flash Memory Interface) ?? ?#define NFDATA (*(volatile unsigned char *)0xB0E00010) NFCONF 寄存器中 3 个时间参数稍微比计算的值大些(大 1 就可以),否则会出现读写不稳定 下面几种操作流程中对于发送地址的周期数:有的是 5 个周期,有的是 3 个周期,有的是 1 个周期。 1、 擦除流程 (1)片选 (2)发命令 0x60 (3)发页地址(块对齐,3 个周期) (4)发命令 0xD0 (5)等待 NAND 空闲 (6)取消片选 2、 写数据 (1)片选 (2)发命令 0x80 (3)发地址(页对齐, 5 个周期) (4)连续发送一页数据 (5)发命令 0x10 (6)等待 NAND 空闲 (7)取消片选 3、 读数据 1) 片选 2) 发命令 0x00 3) 发地址(页对齐, 5 个周期) 4) 发命令 0x30 5) 等待 NAND 空闲 6) 连续读一页数据 7) 取消片选 4、 读ID 1) 片选 2) 发命令 0x90 3) 发 0 地址( 1 个周期) 4) 连续读 5 个字节的 ID 5) 取消片选 #include "types.h" #define NFCONF (*(volatile u32 *)0xB0E00000) #define NFCONT (*(volatile u32 *)0xB0E00004) #define NFCMMD (*(volatile u32 *)0xB0E00008) #define NFADDR (*(volatile u32 *)0xB0E0000C) #define NFDATA (*(volatile u8 *)0xB0E00010) #define NFSTAT (*(volatile u32 *)0xB0E00028) #define MP0_1CON (*(volatile u32 *)0xE02002E0) #define MP0_3CON (*(volatile u32 *)0xE0200320) #define MP0_6CON (*(volatile u32 *)0xE0200380) #define PAGE_SIZE 2048 #define BLOCK_SIZE (PAGE_SIZE * 64) /* 等待NAND准备好 */ static void inline nand_wait_ready() { while(!(NFSTAT & (1 << 0))); } /* 片选 */ static void inline nand_select_chip() { NFCONT &= ~(1 << 1); } /* 取消片选 */ static void inline nand_deselect_chip() { NFCONT |= (1 << 1); } /* 发命令 */ static void inline nand_cmd(u32 cmd) { NFCMMD = cmd; } /* 发地址(5个周期) */ static void nand_addr(u32 addr) { u32 col = addr % PAGE_SIZE; /* 页内偏移 */ u32 row = addr / PAGE_SIZE; /* 页地址 */ NFADDR = col & 0xFF; NFADDR = (col >> 8) & 0x7; NFADDR = row & 0xFF; NFADDR = (row >> 8) & 0xFF; NFADDR = (row >> 16) & 0x07; } /* 读1byte数据 */ static u8 inline nand_read() { return NFDATA; } /* 写1byte数据 */ static void inline nand_write(u8 data) { NFDATA = data; } /* 复位NAND */ static void nand_reset() { nand_select_chip(); nand_cmd(0xFF); nand_wait_ready(); nand_deselect_chip(); } /* NAND初始化 */ void nand_init() { /* HCLK_PSYS=133MHz(7.5ns) */ NFCONF = (0x1 << 23) | /* Disable 1-bit and 4-bit ECC */ /* 下面3个时间参数稍微比计算出的值大些(我这里依次加1),否则读写不稳定 */ (0x3 << 12) | /* 7.5ns * 2 > 12ns tALS tCLS */ (0x2 << 8) | /* (1+1) * 7.5ns > 12ns (tWP) */ (0x1 << 4) | /* (0+1) * 7.5 > 5ns (tCLH/tALH) */ (0x0 << 3) | /* SLC NAND Flash */ (0x0 << 2) | /* 2KBytes/Page */ (0x1 << 1); /* 5 address cycle */ /* ** The setting all nCE[3:0] zero can not be allowed. Only ** one nCE can be asserted to enable external NAND flash ** memory. The lower bit has more priority when user set all ** nCE[3:0] zeros. */ NFCONT = (0x1 << 1) | /* Disable chip select */ (0x1 << 0); /* Enable NAND Flash Controller */ /* ** Port Map ** CE1->Xm0CSn2-> MP01_2 ** CE2->Xm0CSn3-> MP01_3 ** CE3->Xm0CSn4-> MP01_4 ** CE4->Xm0CSn5-> MP01_5 ** CLE->Xm0FCLE-> MP03_0 ** ALE->Xm0FALE-> MP03_1 ** WE->Xm0FWEn-> MP03_2 ** RE->Xm0FREn-> MP03_3 ** RB1->Xm0FRnB0->MP03_4 ** RB2->Xm0FRnB1->MP03_5 ** RB3->Xm0FRnB2->MP03_6 ** RB4->Xm0FRnB3->MP03_7 ** IO[7:0]->Xm0DATA[7:0]->MP0_6[7:0] */ MP0_1CON &= ~(0xFFFF << 8); MP0_1CON |= (0x3333 << 8); MP0_3CON = 0x22222222; MP0_6CON = 0x22222222; nand_reset(); } /* 读NAND ID */ void nand_read_id(u8 id[]) { int i; nand_select_chip(); nand_cmd(0x90); NFADDR = 0x00; for (i = 0; i < 5; i++) id[i] = nand_read(); nand_deselect_chip(); } /* 擦除一个块 */ void nand_erase(u32 addr) { if (addr & (BLOCK_SIZE - 1)) { printf("not block alignn"); return; } u32 row = addr / PAGE_SIZE; nand_select_chip(); nand_cmd(0x60); NFADDR = row & 0xff; NFADDR = (row >> 8) & 0xff; NFADDR = (row >> 16) & 0x07; nand_cmd(0xD0); nand_wait_ready(); nand_deselect_chip(); } /* 读一页数据 */ void nand_read_page(u8 *buf,u32 addr) { if (addr & (PAGE_SIZE - 1)) { printf("not page alignn"); return; } int i; nand_select_chip(); nand_cmd(0); nand_addr(addr); nand_cmd(0x30); nand_wait_ready(); for(i = 0; i < PAGE_SIZE; i++) { *buf++ = nand_read(); } nand_deselect_chip(); } /* 随机读:从任意地址读任意字节的数据 */ void nand_read_random(u8 *buf,u32 addr,u32 size) { nand_select_chip(); nand_cmd(0); nand_addr(addr); nand_cmd(0x30); nand_wait_ready(); int i; u32 col = addr % PAGE_SIZE; /* 页内偏移 */ for(i = col; i < size + col; i++) { nand_cmd(0x05); NFADDR = i & 0xFF; NFADDR = (i >> 8) & 0x7; nand_cmd(0xE0); *buf++ = nand_read(); } nand_deselect_chip(); } /* 写一页数据 */ void nand_write_page(u8 *buf,u32 addr) { if (addr & (PAGE_SIZE - 1)) { printf("not page alignn"); return; } int i; nand_select_chip(); nand_cmd(0x80); nand_addr(addr); nand_wait_ready(); for(i = 0; i < PAGE_SIZE; i++) { nand_write(*buf++); } nand_cmd(0x10); nand_wait_ready(); nand_deselect_chip(); } #include "types.h" #include "uart.h" // 这个文件前面UART串口博客有 void bzero(u8 *s,int size) { int i = 0; for (; i < size; i++) s[i] = 0; } void main() { u8 buf[2048]; int i; bzero(buf,2048); nand_read_id(buf); printf("nID:"); for (i = 0; i < 5; i++) { printf("%X ",buf[i]); } putchar('n'); nand_erase(0x80000); /* 擦除以0x80000地址开始的一个块 */ for (i = 0; i < 2048; i++) buf[i] = i % 255; nand_write_page(buf,0x80000); /* 写入1页数据到0x80000地址 */ bzero(buf,2048); nand_read_page(buf,0x80000); /* 从0x80000地址读取一页数据 */ /* 打印读取到的数据,与写入的数据一致 */ for (i = 0; i < 100; i++) { if (i % 16 == 0) putchar('n'); printf("%X ",buf[i]); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |