基于NAND Flash的RL-FlashFS实现

本文详细介绍了在STR912FAW4x处理器上移植RL-FlashFS文件系统的步骤,包括添加函数库、配置文件、编写NAND Flash驱动等,适用于裸机环境下的文件系统开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.youkuaiyun.com/detail/zoogar/3983092 -- RL-ARM User's Guide

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

http://blog.youkuaiyun.com/xunpo/article/details/6996668 -- XUNPO写的RL-FlashFS移植
--------------------- 
版权声明:本文为优快云博主「zoogar」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/zoogar/article/details/7174887

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值