您的位置:首页 > 其它

基于NAND Flash的RL-FlashFS实现

2012-01-04 16:04 309 查看
RL-ARM版本:4.22

NAND Flash芯片:K9F1208U0C

处理器:STR912FAW4x

软件平台:裸奔

编译环境:MDK-ARM Professional Version: 4.23

目标:基本文件系统操作

RL-FlashFS是RL-ARM的一部分,它可以脱离RTX内核独立运行,所以为了降低调试难度,我采用了裸奔的方式。

1. 添加RL-FlashFS函数库

将\Keil\ARM\RV31\LIB下的FS_ARM_L.lib复制出来,并添加到MDK项目中。

2. 添加并修改File_Config.c

从\Keil\ARM\RL\FlashFS\Config目录复制File_Config.c,并修改。下图是对该文件的配置,只修改了与处理器和K9F1208相关的内容,其它的保持默认:



3. 添加Retarget.c并预定义STDIO宏

从\Keil\ARM\RL\FlashFS\Config目录复制Retarget.c。

为了使用printf等标准输入输出功能,需要预定义STDIO宏。

在MDK中右击Retarget.c,选择“Options for File 'Retarget.c' ...”,然后选择“C/C++”标签,在“Define”中填入STDIO,如下图:



当然,也可以直接在Retarget.c中修改:

/* The following macro definitions may be used to translate this file:

STDIO - use standard Input/Output device
(default is NOT used)
*/
#define STDIO


4. 编写sendchar和getkey函数

这两个函数在Retarget.c中调用。

int sendchar(int ch) {
while (UART_GetFlagStatus(UART0, UART_FLAG_TxFIFOFull) == SET);
UART_SendData(UART0, (u8)ch);
return ch;
}
int getkey(void) {
while (UART_GetFlagStatus(UART0, UART_FLAG_RxFIFOEmpty) == SET);
return (UART_ReceiveData(UART0));
}


5. 配置启动代码中的heap大小

RL-FlashFS使用了动态内存分配来缓存数据,手册给的堆空间最小值是0x1000,这里我用了大一点的值:

修改STR91x.s:

Heap_Size       EQU     0x00002000


6. 编写NAND Flash芯片驱动

这一步是实现文件系统的关键,也是相对有难度的地方,因为这里需要搞清楚NAND Flash芯片的操作。Keil的例子可作为参考,位置在\Keil\ARM\RL\FlashFS\Drivers目录。

不过如果已经将NAND Flash芯片使用于其它文件系统,那问题就比较简单了,将原来的驱动贴过来稍微改一下就可以了。

此外,驱动函数中的NAND_DRV_CFG *cfg参数的作用是为了同一类型芯片的兼容处理,根据File_Config.c的配置,确定NAND_DRV_CFG结构中各项的值。实际上,为了降低难度,只要让RL-FlashFS跑起来,完全没有必要对NAND_DRV_CFG结构进行处理,只需要对特定芯片编写驱动即可。

下面是K9F1208的驱动代码:

//file: nand_k9f1208.c

#include <File_Config.h>

//NAND Area definition
#define CMD_AREA                   		(U32)(1<<1) 		/* A1 = CLE  high */
#define ADDR_AREA                  	(U32)(1<<2)  		/* A2 = ALE high */
#define DATA_AREA                  	((U32)0x00000000)

//命令定义
#define NAND_CMD1_READ1_00				((U8)0x00)
#define NAND_CMD1_READ1_01				((U8)0x01)
#define NAND_CMD1_READ2					((U8)0x50)
#define NAND_CMD1_READ_ID					((U8)0x90)
#define NAND_CMD1_RESET					((U8)0xFF)
#define NAND_CMD1_PAGE_PROG				((U8)0x80)
#define NAND_CMD1_BLOCK_ERASE			((U8)0x60)
#define NAND_CMD1_BLOCK_PROT1			((U8)0x41)
#define NAND_CMD1_BLOCK_PROT2			((U8)0x42)
#define NAND_CMD1_BLOCK_PROT3			((U8)0x43)
#define NAND_CMD1_READ_STAT				((U8)0x70)
#define NAND_CMD1_READ_PROT_STAT			((U8)0x74)

#define NAND_CMD2_PAGE_PROG				((U8)0x10)
#define NAND_CMD2_BLOCK_ERASE			((U8)0xD0)
////////////////////////////////////////////////////////

#define GET_1st_BYTE(DATA)       	(U8)((DATA)& 0xFF)
#define GET_2nd_BYTE(DATA)       	(U8)(((DATA)& 0xFF00) >> 8)
#define GET_3rd_BYTE(DATA)       	(U8)(((DATA)& 0xFF0000) >> 16)
#define GET_4th_BYTE(DATA)       	(U8)(((DATA)& 0xFF000000) >> 24)

#define NAND_WAIT_TIMEOUT			100000

typedef struct
{
U8 Fail			: 1;
U8 Not_Use		: 5;
U8 Ready		: 1;
U8 nWP			: 1;		//Not Write Protected
} NAND_Status;

/*-----------------------------------------------------------------------------
*      NAND driver prototypes
*----------------------------------------------------------------------------*/
U32 Init         (NAND_DRV_CFG *cfg);
U32 UnInit       (NAND_DRV_CFG *cfg);
U32 PageRead     (U32 row, U8 *buf, NAND_DRV_CFG *cfg);
U32 PageWrite    (U32 row, U8 *buf, NAND_DRV_CFG *cfg);
U32 BlockErase   (U32 row, NAND_DRV_CFG *cfg);

/*----------------------------------------------------------------------------
NAND Device Driver Control Block
*----------------------------------------------------------------------------*/
const NAND_DRV nand0_drv = {
Init,
UnInit,
PageRead,
PageWrite,
BlockErase,
};

void nand_io_write_cmd(U8 cmd)
{
*(volatile U8 *)(Bank_NAND_ADDR | CMD_AREA) = cmd;
}

void nand_io_write_addr(U8 addr)
{
*(volatile U8 *)(Bank_NAND_ADDR | ADDR_AREA) = addr;
}

U8 nand_io_read_data(void)
{
U8 data;

data = (*(volatile U8 *)(Bank_NAND_ADDR | DATA_AREA));

return data;
}

void nand_io_write_data(U8 data)
{
*(volatile U8 *)(Bank_NAND_ADDR | DATA_AREA) = data;
}

NAND_Status nand_io_read_status(void)
{
U8 data;

nand_io_write_cmd(NAND_CMD1_READ_STAT);

data = nand_io_read_data();

return (*(NAND_Status *)(&data));
}

//1: ready, 0: timeout
int nand_io_wait_status_ready(void)
{
U32 timeout = 0;
NAND_Status status;

status.Ready = 0;

while ((timeout < NAND_WAIT_TIMEOUT) && (status.Ready == 0))
{
status = nand_io_read_status();
timeout++;
}

if (timeout < NAND_WAIT_TIMEOUT)
return 1;
else
return 0;

}

void nand_delay(int n)
{
int i = 0;
int j = 0;
int temp = 0;

for (i = 0; i < n; i++)
for (j = 0; j < 65535; j++)
temp++;
}

/*-----------------------------------------------------------------------------
*      Initialise NAND flash driver
*
*  *cfg = Pointer to configuration structure
*
*  Return: RTV_NOERR             - NAND Flash Initialisation successful
*          ERR_NAND_HW_TOUT      - NAND Flash Reset Command failed
*          ERR_NAND_UNSUPPORTED  - Page size invalid
*----------------------------------------------------------------------------*/
static U32 Init (NAND_DRV_CFG *cfg) {
return RTV_NOERR;
}

/*-----------------------------------------------------------------------------
*      Uninitialise NAND flash driver
*  *cfg = Pointer to configuration structure
*
*  Return: RTV_NOERR         - UnInit successful
*----------------------------------------------------------------------------*/
static U32 UnInit(NAND_DRV_CFG *cfg) {
return RTV_NOERR;
}

/*-----------------------------------------------------------------------------
*      Read page
*  row  = Page address
*  *buf = Pointer to data buffer
*  *cfg = Pointer to configuration structure
*
*  Return: RTV_NOERR         - Page read successful
*          ERR_NAND_HW_TOUT  - Hardware transfer timeout
*          ERR_ECC_COR       - ECC corrected the data within page
*          ERR_ECC_UNCOR     - ECC was not able to correct the data
*----------------------------------------------------------------------------*/
static U32 PageRead(U32 row, U8 *buf, NAND_DRV_CFG *cfg) {
U32 ret = ECC_NOERR;
int i = 0;

nand_io_write_cmd(NAND_CMD1_READ1_00);
nand_io_write_addr(0);
nand_io_write_addr(GET_1st_BYTE(row));
nand_io_write_addr(GET_2nd_BYTE(row));
nand_io_write_addr(GET_3rd_BYTE(row));

if (nand_io_wait_status_ready())
{
nand_io_write_cmd(NAND_CMD1_READ1_00);

for (i = 0; i < 528; i++)
buf[i] = nand_io_read_data();
}
else
ret = ERR_NAND_HW_TOUT;

return ret;

}

/*-----------------------------------------------------------------------------
*      Write page
*  row  = Page address
*  *buf = Pointer to data buffer
*  *cfg = Pointer to configuration structure
*
*  Return: RTV_NOERR         - Page write successful
*          ERR_NAND_PROG     - Page write failed
*          ERR_NAND_HW_TOUT  - Hardware transfer timeout
*----------------------------------------------------------------------------*/
static U32 PageWrite(U32 row, U8 *buf, NAND_DRV_CFG *cfg) {
U32 ret = RTV_NOERR;
NAND_Status status;
int i = 0;

nand_io_write_cmd(NAND_CMD1_READ1_00);

nand_io_write_cmd(NAND_CMD1_PAGE_PROG);

nand_io_write_addr(0);
nand_io_write_addr(GET_1st_BYTE(row));
nand_io_write_addr(GET_2nd_BYTE(row));
nand_io_write_addr(GET_3rd_BYTE(row));

for (i = 0; i < 528; i++)
nand_io_write_data(buf[i]);

nand_io_write_cmd(NAND_CMD2_PAGE_PROG);

if (nand_io_wait_status_ready())
{
status = nand_io_read_status();

if (status.Fail)
ret = ERR_NAND_PROG;
}
else
ret = ERR_NAND_HW_TOUT;

return ret;

}

/*-----------------------------------------------------------------------------
*      Erase block
*  row  = Block address
*  *cfg = Pointer to configuration structure
*
*  Return: RTV_NOERR         - Block erase successful
*          ERR_NAND_ERASE    - Block erase failed
*          ERR_NAND_HW_TOUT  - Hardware transfer timeout
*----------------------------------------------------------------------------*/
static U32 BlockErase(U32 row, NAND_DRV_CFG *cfg) {
NAND_Status status;
U32 ret = RTV_NOERR;

nand_io_write_cmd(NAND_CMD1_BLOCK_ERASE);

nand_io_write_addr(GET_1st_BYTE(row));
nand_io_write_addr(GET_2nd_BYTE(row));
nand_io_write_addr(GET_3rd_BYTE(row));

nand_io_write_cmd(NAND_CMD2_BLOCK_ERASE);

if (nand_io_wait_status_ready())
{
status = nand_io_read_status();

if (status.Fail)
ret = ERR_NAND_ERASE;
}
else
ret = ERR_NAND_HW_TOUT;

return ret;

}


其中Bank_NAND_ADDR地址需要根据不同的平台进行定义。

7. 运行例程

选用Keil提供的其中一个例程。复制\Keil\ARM\Boards\Atmel\SAM3U-EK\RL\FlashFS\NAND_File目录下的NAND_File.c、NAND_File.h和Getline.c,然后添加到MDK中。

修改NAND_File.c,去掉与例程硬件相关的内容,添加当前的硬件相关内容:

头文件引用:

//#include <SAM3U.H>                    /* ATSAM3U definitions                 */
#include "File_Config.h"
#include "NAND_File.h"
//#include "Serial.h"
#include "my_init.h"


main函数:

//SystemInit();                               /* initialize clocks           */
//SER_Init ();                                /* initialize serial interface */
my_init();


修改Getline.c函数,使之能够正常读取用户输入(至于为什么不能正常输入,我没有深究,也有可能是我的终端配置不对)

#if 0
case CR:                             /* CR - done, stop editing line   */
*lp = c;
lp++;                              /* increment line pointer         */
cnt++;                             /* and count                      */
c = LF;
#endif


编译烧写后,将板子的UART0连到PC的串口,通过命令行测试文件系统的功能。

 

8. 参考资料

http://download.csdn.net/detail/zoogar/3983092 -- RL-ARM User's Guide

http://download.csdn.net/detail/zoogar/3983085 -- Building Applications with RL-ARM - Getting Started

http://blog.csdn.net/xunpo/article/details/6996668 -- XUNPO写的RL-FlashFS移植
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  flash cmd io structure byte file