×
单片机 > 单片机程序设计 > 详情

TQ210 —— NandFlash

发布时间:2021-05-07 发布时间:
|

TQ210 开发板板载一片 1Gbyte 的 NAND FLASH——K9K8G08U0B,通过查询K9K8G08U0B 芯片手册可以得到如下信息:(理论知识不再介绍)

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]);

}

}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈msp430f5529入门(2)----时钟配置.例程分析