基于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相关的内容,其它的保持默认:
![](http://hi.csdn.net/attachment/201201/4/0_1325660001emal.gif)
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,如下图:
![](http://hi.csdn.net/attachment/201201/4/0_132565623575gd.gif)
当然,也可以直接在Retarget.c中修改:
4. 编写sendchar和getkey函数
这两个函数在Retarget.c中调用。
5. 配置启动代码中的heap大小
RL-FlashFS使用了动态内存分配来缓存数据,手册给的堆空间最小值是0x1000,这里我用了大一点的值:
修改STR91x.s:
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的驱动代码:
其中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,去掉与例程硬件相关的内容,添加当前的硬件相关内容:
头文件引用:
main函数:
修改Getline.c函数,使之能够正常读取用户输入(至于为什么不能正常输入,我没有深究,也有可能是我的终端配置不对)
编译烧写后,将板子的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移植
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相关的内容,其它的保持默认:
![](http://hi.csdn.net/attachment/201201/4/0_1325660001emal.gif)
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,如下图:
![](http://hi.csdn.net/attachment/201201/4/0_132565623575gd.gif)
当然,也可以直接在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移植
相关文章推荐
- PXA270-基于ARM9内核Processor外部NAND FLASH的控制实现
- 【安富莱原创开源应用第2期】基于RL-USB和RL-FlashFS的完整NAND解决方案,稳定好用,可放心用于产品批量
- 基于BCH算法的ECC在MLC Nand Flash中的实现[zz]
- 基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现
- 基于smdk2410 开发板u-boot-1.2.0 nand flash读写操作及其命令的实现(续)
- 【RL笔记】基于tensorflow实现RL的policy based算法
- 基于ARM9内核Processor外部NAND FLASH的控制实现
- 基于DM9161的RL-TCPnet实现
- 基于JZ2440的NAND FLASH的驱动程序的实现
- 基于ARM9内核Processor外部NAND FLASH的控制实现
- 【原创开源应用第5期】基于RL-USB+RL-FlashFS的外挂U盘解决方案
- BlogEngine.Net架构与源代码分析系列part3:数据存储——基于Provider模式的实现
- asp.net 基于ajaxfileupload.js 实现文件异步上传
- 贝叶斯网络结构学习(基于BDAGL工具箱的MATLAB实现)
- 移动网络游戏实现流程 -- 基于Cocos2d-x引擎和pomelo服务器框架
- (新手向)基于Bootstrap的简单轮播图的手机实现
- 微信红包的算法实现探讨(基于PHP)
- 【Spring】——AOP实现原理(基于JDK和CGLIB)
- 通过 Terracotta实现基于Tomcat的Web应用集群