/******************** (C) COPYRIGHT 2010-2015 launch ********************
* File Name : k9f1g08.c
* Author : zhanghonghu
* Version : V1.0
* Date : 05/01/2010
* Description :
本文件提供k9f1g08的如下操作:
读取flash ID(探测flash)
flash 检错
读flash
写flash
擦除flash
flash空间管理
*******************************************************************************/
#include "global.h"
#include "string.h"
// flash function cmd
// read
#define FLASH_CMD_READ1 0x00
#define FLASH_CMD_READ2 0x30
//read for copy back
#define FLASH_CMD_READ_B1 0x00
#define FLASH_CMD_READ_B2 0x35
// read id
#define FLASH_CMD_READ_ID 0x90
// reset
#define FLASH_CMD_RESET 0xff
// page program
#define FLASH_CMD_PAGE_PRO1 0x80
#define FLASH_CMD_PAGE_PRO2 0x10
//cache program
#define FLASH_CMD_CACHE_PRO1 0x80
#define FLASH_CMD_CACHE_PRO2 0x15
// copy-back program
#define FLASH_CMD_COPY_B_PRO1 0x85
#define FLASH_CMD_COPY_B_PRO2 0x10
// block erase
#define FLASH_CMD_ERASE1 0x60
#define FLASH_CMD_ERASE2 0xd0
// random data input
#define FLASH_CMD_DATA_IN 0x85
// random data output
#define FLASH_CMD_DATA_OUT1 0x05
#define FLASH_CMD_DATA_OUT2 0xe0
// read status
#define FLASH_CMD_READ_STATUS 0x70
#define FLASH_BUSY (1 << 6) // 器件忙标志
#define FLASH_OK (1 << 0) // 器件操作成功标志
typedef struct
{
uint32 page_size;
uint32 block_size;
uint8 spare_size;
uint8 bit_type;
uint8 access_min;
}Flash_pro;
Flash_pro nand_type;
/*************************************************************************************************/
// 以下为硬件相关,移植到其他平台时需要更改
// start hw
// 引脚描述
/* LPC2119单片机的引脚 flash芯片的引脚
P1.23 ClE // 命令锁存使能端 高电平有效 作用于WE上升沿
P1.22 ALE // 地址锁存使能端 高电平有效 作用于WE上升沿
P1.18 CE/ // 片选 低电平有效
P1.20 WE/ // 写使能 低电平有效
P1.21 RE/ // 读使能 在该口的下降沿把数据送到IO口
P0.27 R/B // 操作状态指示信号 低表示忙 高表示已经结束,准备好了
WP // 写保护口 本例直接接高电平了,容易出问题
PRE // 上电读使能,直接接高电平
P0.23-P0.16(8位端口) D7-D0
*/
#define FLASH_CLE (1<<23) // p1.23
#define FLASH_ALE (1<<22) // p1.22
#define FLASH_CE (1<<18) // p1.18
#define FLASH_WE (1<<20) // p1.20
#define FLASH_RE (1<<21) // p1.21
#define FLASH_READY (1<<27) // p0.27
#define FLASH_WP
#define SET_FLASH_ALE() IO1SET = FLASH_ALE //FALE
#define CLR_FLASH_ALE() IO1CLR = FLASH_ALE
#define SET_FLASH_CLE() IO1SET = FLASH_CLE //FCLE
#define CLR_FLASH_CLE() IO1CLR = FLASH_CLE
#define SET_FLASH_CE() IO1SET = FLASH_CE //FCE
#define CLR_FLASH_CE() IO1CLR = FLASH_CE
#define SET_FLASH_WE() IO1SET = FLASH_WE //FWE
#define CLR_FLASH_WE() IO1CLR = FLASH_WE
#define SET_FLASH_RE() IO1SET = FLASH_RE //FRE
#define CLR_FLASH_RE() IO1CLR = FLASH_RE
#define SET_FLASH_WP()
#define CLR_FLASH_WP()
#define FLASH_READY_VALUE ((IO0PIN >> 27)&0x00000001)
void nand_data_dir_out(void)
{
IO0DIR |= 0x00ff0000;
}
void nand_data_dir_in(void)
{
IO0DIR &= 0xff00ffff;
}
void nand_data_out( uint8 mIndex )
{
IO0PIN = (IO0PIN & 0xff00ffff) | (mIndex << 16);
}
uint8 nand_data_in(void)
{
return ((uint8)(IO0PIN >> 16));
}
// end hw
/*************************************************************************************************/
static uint8 nand_busy_wait(void);
static void nand_write_cmd(uint8 cmd);
static void nand_write_add(uint16 column_add,uint16 row_add);
static uint8 nand_read_status(void);
static void nand_reset(void);
uint8 nand_work_ok(void);
uint32 nand_read_ID(void);
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void nand_init(void)
{
uint32 id;
// io
IO1DIR |= FLASH_CLE | FLASH_ALE | FLASH_CE | FLASH_WE | FLASH_RE; // 设置为输出
IO0DIR = IO0DIR & (~FLASH_READY); // 设置为输入
nand_data_dir_out();
SET_FLASH_CE();
SET_FLASH_WE();
SET_FLASH_RE();
CLR_FLASH_WP();
CLR_FLASH_CLE();
CLR_FLASH_ALE();
// reset
nand_reset();
// test
uart0_send_string("flash id is:");
id = nand_read_ID();
PrintHex(id>>24);
PrintHex(id>>16);
PrintHex(id>>8);
PrintHex(id);
nand_valid_block_check();
}
// 与平台无关系
/*******************************************************************************
* Function Name :
* Description : 忙等待
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_busy_wait(void)
{
int i;
while(0 == FLASH_READY_VALUE)
{
i++;
delay();
if(i >= 60000)
{
return 0;
}
}
return 1;
}
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void nand_write_cmd(uint8 cmd)
{
CLR_FLASH_CE(); // 片选
SET_FLASH_CLE();
CLR_FLASH_WE();
nand_data_out(cmd);
SET_FLASH_WE();
CLR_FLASH_CLE();
SET_FLASH_CE();
}
/*******************************************************************************
* Function Name : void nand_write_add(uint16 column_add,uint16 row_add)
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void nand_write_add(uint16 column_add,uint16 row_add)
{
CLR_FLASH_CE(); // 片选
SET_FLASH_WE();
SET_FLASH_ALE();
CLR_FLASH_WE();
nand_data_out((uint8)(column_add));
SET_FLASH_WE();
delay();
CLR_FLASH_WE();
nand_data_out((uint8)((column_add >> 8) & 0x0f));
SET_FLASH_WE();
delay();
CLR_FLASH_WE();
nand_data_out((uint8)(row_add));
SET_FLASH_WE();
delay();
CLR_FLASH_WE();
nand_data_out((uint8)(row_add >> 8));
SET_FLASH_WE();
delay();
CLR_FLASH_ALE();
SET_FLASH_CE();
}
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void nand_write_byte(uint8 bdata)
{
SET_FLASH_WE();
CLR_FLASH_CE();
CLR_FLASH_WE();
delay();
nand_data_out(bdata);
delay();
SET_FLASH_WE();
SET_FLASH_CE();
}
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_read_byte(void)
{
uint8 data;
nand_data_dir_in();
SET_FLASH_WE();
CLR_FLASH_CE();
CLR_FLASH_RE();
// delay();
nand_busy_wait();
data = nand_data_in();
SET_FLASH_CE();
SET_FLASH_RE();
nand_data_dir_out();
return data;
}
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : status
*******************************************************************************/
uint8 nand_read_status(void)
{
nand_write_cmd(FLASH_CMD_READ_STATUS);
return (nand_read_byte());
}
/*******************************************************************************
* Function Name :
* Description :
* Input : None
* Output : None
* Return : status
*******************************************************************************/
void nand_reset(void)
{
nand_write_cmd(FLASH_CMD_RESET);
nand_busy_wait();
}
/*******************************************************************************
* Function Name :
* Description : 检查flash是否OK
* Input : None
* Output : None
* Return : 1 OK
*******************************************************************************/
uint8 nand_work_ok(void)
{
uint8 status;
while(1)
{
status = nand_read_status();
if((status & FLASH_BUSY))
{
break;
}
}
status = nand_read_status();
if (!(status & FLASH_OK))
{
return 1;
}
else
{
return 0;
}
}
/*******************************************************************************
* Function Name :
* Description : 参考datasheet add为0
* Input : None
* Output : None
* Return : flash id
1byte maker code
2byte device code
3byte don't care
4byte Page Size, Block Size, Spare Size, Organization,Serial access minimum
第4字节比较重要
*******************************************************************************/
uint32 nand_read_ID(void)
{
uint32 id;
uint8 data[4];
id = 0;
nand_write_cmd(FLASH_CMD_READ_ID);
nand_write_add(0,0);
data[0] = nand_read_byte();
data[1] = nand_read_byte();
data[2] = nand_read_byte();
data[3] = nand_read_byte();
if(0x00 == (data[3]&0x03))
{
nand_type.page_size = 1;
}
else if(0x01 == (data[3]&0x03))
{
nand_type.page_size = 2;
}
else
{
}
if((data[3]&0x04))
{
nand_type.spare_size = 8;
}
else
{
nand_type.spare_size = 16;
}
if(0x00 == ((data[3] >> 4)&0x03))
{
nand_type.block_size = 64;
}else if(0x01 == ((data[3] >> 4)&0x03))
{
nand_type.block_size = 128;
}else if(0x02 == ((data[3] >> 4)&0x03))
{
nand_type.block_size = 256;
}
else
{
}
if(data[3]&0x40)
{
nand_type.bit_type = 16;
}
else
{
nand_type.bit_type = 8;
}
id = (id << 8) + data[0];
id = (id << 8) + data[1];
id = (id << 8) + data[2];
id = (id << 8) + data[3];
return id;
}
/*******************************************************************************
* Function Name : uint8 nand_read_data(uint32 page_index,uint32 block_index,uint8 *buf)
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_read_data(uint32 page_index,uint32 block_index,uint8 *buf)
{
uint16 column_add,row_add;
uint16 block_cnt,page_cnt; // 所处块数及第几页
uint32 i;
// 计算row_add地址
block_cnt = block_index;
page_cnt = page_index;
column_add = 0;
row_add = (block_cnt << 6) | page_cnt;
nand_write_cmd(FLASH_CMD_READ1);
nand_write_add(column_add,row_add);
nand_write_cmd(FLASH_CMD_READ2);
nand_busy_wait();
nand_data_dir_in();
CLR_FLASH_CE();
for(i = 0; i < BYTES_PER_PAGE;i++)
{
CLR_FLASH_RE();
delay(); // 必须加延时,否则数据会出现移位问题
buf[i] = nand_data_in();
SET_FLASH_RE();
}
SET_FLASH_CE();
nand_data_dir_out();
return 1;
}
/*******************************************************************************
* Function Name : uint8 nand_read_oob(uint32 page_index,uint32 block_index,uint8 *buf)
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_read_oob(uint32 page_index,uint32 block_index,uint8 *buf)
{
uint16 column_add,row_add;
uint16 block_cnt,page_cnt; // 所处块数及第几页
uint32 i;
// 计算row_add地址
block_cnt = page_index;
page_cnt = block_index;
column_add = BYTES_PER_PAGE;
row_add = (block_cnt << 6) | page_cnt;
nand_write_cmd(FLASH_CMD_READ1);
nand_write_add(column_add,row_add);
nand_write_cmd(FLASH_CMD_READ2);
nand_busy_wait();
nand_data_dir_in();
CLR_FLASH_CE();
for(i = 0; i < BYTES_PER_PAGE_SPARE;i++)
{
CLR_FLASH_RE();
delay();
buf[i] = nand_data_in();
SET_FLASH_RE();
}
SET_FLASH_CE();
nand_data_dir_out();
return 1;
}
/*******************************************************************************
* Function Name : uint8 nand_write_data(uint32 page_index,uint32 block_index,uint8 *buf)
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_write_data(uint32 page_index,uint32 block_index,uint8 *buf)
{
uint16 column_add,row_add;
uint16 block_cnt,page_cnt; // 所处块数及第几页
uint32 i;
uint8 status;
// 计算row_add地址
block_cnt = page_index;
page_cnt = block_index;
column_add = 0;
row_add = (block_cnt << 6) | page_cnt;
nand_write_cmd(FLASH_CMD_PAGE_PRO1);
nand_write_add(column_add,row_add);
nand_busy_wait();
CLR_FLASH_CE();
for(i = 0; i < BYTES_PER_PAGE_SPARE;i++)
{
CLR_FLASH_WE();
delay();
nand_data_out(buf[i]);
SET_FLASH_WE();
}
nand_write_cmd(FLASH_CMD_PAGE_PRO2);
// delay_ms(1);
status = nand_work_ok();
SET_FLASH_CE(); // 其实这个已经可以不要,为了统一格式
return status;
}
/*******************************************************************************
* Function Name : uint8 nand_write_oob(uint32 page_index,uint32 block_index,uint8 *buf)
* Description : 编程附加数据,size不要超过64 每块的第0页和第1页的附加数据的第1个字节不要改动
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_write_oob(uint32 page_index,uint32 block_index,uint8 *buf)
{
uint16 column_add,row_add;
uint16 block_cnt,page_cnt; // 所处块数及第几页
uint32 i;
uint8 status;
// 计算row_add地址
block_cnt = page_index;
page_cnt = block_index;
column_add = BYTES_PER_PAGE;
row_add = (block_cnt << 6) | page_cnt;
nand_write_cmd(FLASH_CMD_PAGE_PRO1);
nand_write_add(column_add,row_add);
nand_busy_wait();
CLR_FLASH_CE();
for(i = 0; i < BYTES_PER_PAGE_SPARE;i++)
{
CLR_FLASH_WE();
delay();
nand_data_out(buf[i]);
SET_FLASH_WE();
}
nand_write_cmd(FLASH_CMD_PAGE_PRO2);
// delay_ms(1);
status = nand_work_ok();
SET_FLASH_CE(); // 其实这个已经可以不要,为了统一格式
return status;
}
/*******************************************************************************
* Function Name : uint8 nand_block_erase(uint32 block_index)
* Description :
* Input : None
* Output : None
* Return : None
*******************************************************************************/
uint8 nand_erase(uint32 block_index)
{
uint16 row_add;
uint8 status;
// 计算row_add地址
row_add = (block_index << 6) & 0xffc0;
nand_write_cmd(FLASH_CMD_ERASE1);
nand_write_add(0,row_add);
nand_write_cmd(FLASH_CMD_ERASE2);
delay_ms(1);
status = nand_work_ok();
return status;
}
// 建立坏块表
// K9F1G08U0A 共1024块, 出厂至少有1004块为好块, Block0 必为好块
// Block0 : 存放坏块及坏块跳转表,
// page0: 存放坏块标志,1024字节对应1024块,坏块为0x00,好块为0xFF.
// page1: 存放跳转块的BlockIndex,每一个BlockIndex使用2字节表示,1024块占用2048字节
// other: Reserved
// Blk1~960 : 保存数据
// BlkN>960 : 程序先整片检查坏块,使用检查出来的Index大于960的好块为替换块.
/*******************************************************************************
* Function Name :
* Description : 检查指定块是否坏区,并标记
* Input : None
* Output : None
* Return : 1有效 0无效
*******************************************************************************/
uint8 NandBlockCheck(uint32 block_index)
{
uint8 buf[64];
if(nand_read_oob(0,block_index,buf))
{
if(0xff == buf[0])
{
if(nand_read_oob(1, block_index, buf))
{
if(0xff == buf[0])
{
return 1;
}
else
{
// uart0_send_string("the sec page data is:");
// PrintHex(buf[NF_ID_IVILID_NUM]);
// uart0_send_string("\r\n");
}
}
}
else
{
// uart0_send_string("the first page data is:");
// PrintHex(buf[NF_ID_IVILID_NUM]);
// uart0_send_string("\r\n");
}
}
return 0;
}
/*******************************************************************************
* Function Name :
* Description : 检查flash坏区
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void nand_valid_block_check(void)
{
uint16 i;
for(i = 0; i < BLOCKS_PER_CHIP; i++)
{
if(NandBlockCheck(i))
{
}
/*
else
{
uart0_send_string("Block ");
PrintHex(i >> 8);
PrintHex(i);
uart0_send_string("is invalid\r\n");
}
*/
}
}