UFFS文件系统与NandFlash

1.硬件芯片驱动
在底层驱动函数中,需要针对具体的芯片特性,编写6个基础函数提供给上层UFFS系统调用。

ReadID()                   读芯片ID
EraseBlock()               块擦除
ReadPage()                 读一页数据区
ReadPageSpare()            读一页备份区
WritePage()                写一页数据区
WritePageSpare()           写一页备份区

并且针对不同的芯片归纳出特定某一款nand芯片的参数,

    typedef struct SNandInitInfo
    {
        rt_uint16_t uNandID     ; /* Nand Chip ID */
        rt_uint16_t uNandNbBlocks   ;块数量    
        rt_uint32_t   uNandBlockSize    ;块大小
        rt_uint16_t uNandSectorSize;       ;簇大小(页大小)
        rt_uint8_t  uNandSpareSize  ;备用区大小
        rt_uint8_t  uNandBusWidth   ;总线宽度
        rt_uint8_t  uNandBadOffset  ;坏块偏移
        char           name[16]     ; /* Nand Name */
    } SNandInitInfo, *PSNandInitInfo;

在nand配置文件中,可以定义一个结构,该结构内容包含多中NandFlash的信息,当我们移植了其他型号的NandFlash时,可以在NandFlash_InitInfo中找到对应的信息,这样代码基本不用修改,移植性很强: nand.c中针对常用nand芯片的信息有定义:

const struct SNandInitInfo NandFlash_InitInfo[] = {
        /*
        {0xecda, 0x800, 0x20000, 0x800, 0x40, 0x0,0x0, "K9F2G08U0M\0"},
        {0xecaa, 0x800, 0x20000, 0x800, 0x40, 0x0,0x0, "K9F2G08R0A\0"},
        */
        {0xec75, 0x800, 0x4000, 0x200, 0x10, 0x0,0x04, "k9f5608\0"}, /*add by misswhile*/
        {0xecf1, 0x400, 0x20000, 0x800, 0x40, 0x0,0x0, "K9F1G08U0M\0"}, /*add by misswhile*/
        {0xec76, 0x1000, 0x4000, 0x200, 0x10, 0x0,0x04, "K9F12808u0b\0"}, /*add by misswhile*/
        {0xeca5, 0x800, 0x4000, 0x200, 0x10, 0x0,0x0, "K9F1G08U0A\0"}, /*add by misswhile*/
        /*
        {0x20aa, 0x800, 0x20000, 0x800, 0x40, 0x0,0x0, "STMNAND02GR3B\0"},  
        {0x2caa, 0x800, 0x20000, 0x800, 0x40, 0x0,0x0, "MT29F2G08ABD\0"}, */
        {0,}
    };

2.更换芯片后,需要修改的配置文件。
在现有集中器项目中, “nandflash-interface.c”这一文件做了底层nand驱动与上层UFFS直接的兼容配置。目的是做到,在驱动层列出的芯片中。无论哪种芯片都可以不修改代码执行使用。

这一层的操作思路:
先通过标准函数ReadID() 读出该块nand的ID号。在通过ID号与NandFlash_InitInfo中进行比对。并查找出,该块nand的基础信息,记录在SNandInitInfo中。

在uffs初始化时将这些基础信息配置给uffs

static void setup_flash_storage(struct uffs_StorageAttrSt *attr ,PSNandInitInfo info)
    {
        attr->page_data_size  = info->uNandSectorSize;//NAND_PAGE_DATA_SIZE;        /* page data size */
        attr->pages_per_block  = info->uNandBlockSize/info->uNandSectorSize;//NAND_PAGES_PER_BLOCK; /* pages per block */
        attr->spare_size = info->uNandSpareSize;//NAND_PAGE_SPARE_SIZE;         /* page spare size */
        attr->block_status_offs = 4;//info->uNandBadOffset;//4;             /* block status offset is 5th u8 in spare */
        attr->ecc_opt = UFFS_ECC_SOFT;              /* ecc option */
        //attr->layout_opt = UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
        //attr->ecc_opt = UFFS_ECC_HW_AUTO;//UFFS_ECC_NONE;//UFFS_ECC_SOFT;              /* ecc option */
        attr->layout_opt = UFFS_LAYOUT_UFFS;//UFFS_LAYOUT_UFFS;        /* let UFFS do the spare layout */    
    }

并且在这一层,对读写函数也进行一层封装。目的是兼容不同叶大小的读写。
如在具体读写nand时,会根据该nand的叶大小来具体调用相比配的函数。(有写nand的页是2k 有的是512,所以需要兼容处理)

static int nand_read_page(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
                            u8 *spare, int spare_len)
    {
        u8 val = 0;
        int ret = UFFS_FLASH_NO_ERR;
        if (data && data_len > 0) {
            nand_read_page_data(dev, block, page, data, data_len, ecc);
        }

        if (spare && spare_len > 0) {
            nand_read_page_spare(dev,  block,  page, spare, 0, spare_len);
        }

        if (data == NULL && spare == NULL) {
            nand_read_page_spare(dev,  block,  page, &val, dev->attr->block_status_offs, 1);

            ret = (val == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK);
        }

        return ret;
    }

该层最终提供给上层UFFS3个函数,其余函数未被使用。

const  struct uffs_FlashOpsSt my_nand_driver_ops = {
        NULL,
        NULL,
        nand_read_page,        //ReadPageData
        NULL,                             //ReadPageSpareWithLayout
        nand_write_page,       //WritePageData
        NULL,
        NULL,                             //spi_isbad_block,    //IsBadBlock
        NULL,                             //MarkBadBlock
        nand_erase_block,      //EraseBlock
    };

其他函数应该为有些芯片的高级功能提供接口,比如,有些ecc的校验是硬件完成的,不需要软件计算。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值