K9F1208 的硬件连接图
RnB: 低电平时,表明某个写入、读写或擦除操作正在进行。完成后,恢复高电平。
CLE: 命令锁存;
ALE: 地址锁存;
NFCE: 芯片使能。
Samsung 的 K9F1208U0B NAND Flash ,存储容量为 64MByte × 8Bit , 3.3V 供电。
操作模式:先擦除,再写。擦除以块为单位,读写以页 ( 扇区 ) 为单位。
K9F1208U0B: 4096 块, ( 16K + 512 ) Bytes/ 块;
1 块, 32 页, ( 512 + 16 ) Bytes/ 页。
1 个存储器器件 =528Bytes × 32 页× 4096 块 = 64MBytes + 2048KBytes( 作为备用 )
对 528 字节一页的写操作所需时间的典型值是 200µs ,而对 16K 字节一块的擦除操作典型值也仅需 2ms 。每一页中的数据读出速度也很快,平均每个字节只需 50ns ,已经与一般的 SRAM 相当。
8 位 I/O 端口采用地址、数据和命令复用的方法。这样既可以减少引脚数,还可使接口电路简洁。
启动代码
i = search_params();
if(!i)
Uart_Printf("Found boot params/n");
else if(i==-1)
{
Uart_Printf("Fail to found boot params!/n");
save_params();
}
else if(i==-2)
Uart_Printf("Fail to read EEPROM!/n");
search_params
<1>InitNandFlash 初始化 Nand Flash
1、 InitNandCfg 初始化 Nand Flash 配置 时钟等等
2、 ReadChipId 读取 flash 的 ID 号 返回 ID 号
(1) 使能 Flash 配置 NFChipEn (rNFCONT &= ~(1<<1))
(2) 写命令 读 ID 号 (rNFCMD = (0x90) 命令设置寄存器
(3) 写地址 (rNFADDR = (0x00)) 地址设置寄存器
(4) 等待 flash 空闲,判断状态寄存器的第 0 位 0 繁忙 1 空闲 , 准备好
在 flash 繁忙状态下是不能进行读写操作的 等待空闲状态
(5) 读取数据寄存器的值 保存 ID 号 ID 号 16 位的双字节数据
id = RdNFDat()<<8;
id |= RdNFDat();
(6) 禁止 Flash NFChipDs (rNFCONT |= (1<<1))
(7) 返回 ID 号
3 、判读返回的 ID 号 注: K9S1208 的 ID 号为 0xEC76
if((i==0x9873)||(i==0xec75))
NandAddr = 0;
else if(i==0xec76)
NandAddr = 1;
else {
if(info)
puts("Chip id error!!!/n");
have_nandflash = 0;// 读取 ID 失败
return;
}
have_nandflash = 1 // 读取 ID 成功
<2>InitNandFlash 之后 判读 have_nandflash 的值 确定 ID 是否正确读取
1 、如果 ID 读写正确
page = NandPart[0].offset>>9; // 偏移地址除以 512 地址 第几页,每页有 512 字节
page_cnt = NandPart[0].size>>9; // 空间大小除以 512 ,共有几页,每页有 512 字节
注:
struct Partition {
U32 offset ;
U32 size;
char *name;
};
static struct Partition NandPart [] = {
{0, 0x00030000, "boot"}, //192K
{0x00030000, 0x001d0000, "kernel"}, //1856K
{0x00200000, 0x01e00000, "rootfs"}, //30M
{0x02000000, 0x02000000, "ext-fs1"}, //32M
{0, 0 , 0}
};
while(page_cnt--) {
ReadPage(page+page_cnt, dat);// 读一页中的数据 放在 dat 中 512 字节数据
if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) // 判断 10 个字符是否相同
{
ret = 0;
break;
}
ReadPage(U32 addr, U8 *buf) 读一页中的数据 地址,读出的数据要存放的地址
(1) 使能 Flash
(2) 写命令 WrNFCmd(0x00);
(3) 写地址 WrNFAddr(0);
(4) 写 addr 地址的低八位
(5) 写 addr 地址的高八位
(6) 如果 NandAddr=1 , K9S1208 写 addr 地址的高十六位 32 位的地址
(7) 使能 ECC (rNFCONT |= (1<<4))
(8) 等待空闲状态
(9) 把数据寄存器的数据放入缓冲区中,以页为单位读
for(i=0; i<512; i++)
buf[i] = RdNFDat();
/ (10) 关闭 Flash
2、 如果读取 ID 不正确
memcpy(dat, (void *)(NOR_PARAMS_OFFSET), 512); //MMU 没有设置 就用 original 地址 if(!strncmp(boot_params.start.flags, pBP->start.flags, 10)) // 拷贝启动标志位参数
ret = 0;
<3> 禁止 Flash DsNandFlash(); (rNFCONT &= ~1)
<4> 如果前边都完成没有问题 ret=0; 否则 ret= -1;
// 把 boot_params 的数据放入到 BootParams 中
if(!ret) {
ParamItem *pPIS = &pBP->start, *pPID = &boot_params.start;
for(; pPID<=&boot_params.user_params; pPIS++, pPID++)// 一个个比较个数
// 判读 flags 个数是否相同 若相同,返回 0 小于返回负数,否则返回正数
if(!strncmp(pPID->flags, pPIS->flags, sizeof(pPID->flags)))
pPID->val = pPIS->val;// 把数据给了 pPID->val
// 把 pPIS->flags 中的数据 , 启动参数,复制到 boot_params.string 中
strncpy(boot_params.string, pPIS->flags, boot_params.user_params.val+1);
// boot_params.user_params.val 定义为 {"userpara", sizeof(DEFAULT_USER_PARAMS)}, 若个数不对,清除刚才复制的数据 user 值赋 0
if(boot_params.user_params.val!=strlen(pPID->flags))
{
memset(boot_params.string, 0, sizeof(boot_params.string));
boot_params.user_params.val = 0;
}
}
else
{
//printf("Fail to find boot params! Use Default parameters./n");
//don't printf anything before serial initialized!
}
注:
typedef struct {
char flags[12];
unsigned int val;
} ParamItem ;
typedef struct {
ParamItem start;
ParamItem cpu_clk;
ParamItem boot_delay;
ParamItem serial_sel;
ParamItem serial_baud;
ParamItem machine;
ParamItem run_addr;
ParamItem root_sel;
ParamItem tty_sel;
ParamItem initrd_addr;
ParamItem initrd_len;
ParamItem mem_cfg;
ParamItem devfs_sel;
ParamItem osstor;
ParamItem user_params;
char string[128];
} BootParams
// 小于等于 512 个字节 , 最多保存 24 个 ITEM 和 128 字节用户定义的字符串
BootParams boot_params = {
{"bootpara", 1}, //0=boot without parameters,1=boot with parameters
{"cpuclk", 2}, //0=200M, 1=300M, 2=400M, 3=440M
{"rundelay", 0}, //0 seconds
{"serial", 1}, //0=serial port 0, 1=serial port 1
{"baudrate", 115200},// 波特率
{"machine", 193},
{"runAddr", 0x30400000},
{"rootfs", 0},
{"tty", 1},
{"initrdA", 0},
{"initrdL", 0},
{"memsize", 0x04000000},
{"devfs", 1},
{"ostore", 0}, //0=nand, 1=nor
{"userpara", sizeof(DEFAULT_USER_PARAMS)},
DEFAULT_USER_PARAMS
};
///
作者:宇帆 cfanlwn
时间:2010-01-19 15:34:21