基于NAND Flash的RL-FlashFS实现

来源:互联网 发布:下载学英语软件 编辑:程序博客网 时间:2024/05/17 02:05

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_TIMEOUT100000typedef 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: timeoutint 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;elsereturn 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();}elseret = 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;}elseret = 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;}elseret = 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移植

原创粉丝点击