RT-Thread论坛
直播中

甘满盛

8年用户 1360经验值
擅长:386660
私信 关注
[问答]

uffs文件系统挂载nand0设备后,所有块全变成坏块了,是什么原因导致的?


  • static rt_err_t _read_page(struct rt_mtd_nand_device *device,
  •                            rt_off_t page,
  •                            rt_uint8_t *data,
  •                            rt_uint32_t data_len,
  •                            rt_uint8_t *spare,
  •                            rt_uint32_t spare_len)
  • {

  •     int res = RT_EOK;
  •         rt_uint32_t i;
  •     int sr2 = 0;
  •     rt_uint8_t page_data[4], column_data[4];
  •     rt_uint16_t column_addr = 0;
  •     rt_uint8_t oob[PAGE_OOB_SIZE];
  •     struct rt_spi_device *spi_device = nand_bus_dev;

  •     RT_ASSERT(spi_device != RT_NULL);
  •     RT_ASSERT(device != NULL);
  •     RT_ASSERT(data_len <= device->page_size);
  •     RT_ASSERT(spare_len <= device->oob_size);

  •     page = page + (device->block_start) * (device->pages_per_block);
  •     if (page >= (device->block_end) * device->pages_per_block)
  •     {
  •         LOG_E("failed to read page, the page %d is out of bound.", page);
  •         return -RT_ERROR; //-RT_MTD_ENOMEM;
  •     }
  • //    rt_kprintf("_________read block %d, page %dn", page / (device->pages_per_block), page % (device->pages_per_block));

  •     res = spi_nand_status_read( READ_NAND_SR2_ADDR, &sr2); //0xBF
  •     if (res != RT_EOK)
  •     {
  •         return res;
  •     }

  •     //0x13 dummy[8bit] page_addr[16bit]
  •     page_data[0] = READ_PAGE_CMD;
  •     page_data[1] = DUMMY_CMD;
  •     page_data[2] = (page >> 8) & 0xff;
  •     page_data[3] = page & 0xff;
  •     rt_spi_send(spi_device, &page_data, 4);

  •     rt_hw_us_delay(500);

  •     if (sr2 & NAND_SR2_BUF_BIT_MASK) //BUF=1, read begin column_addr, end with length, one page
  •     {
  • //        if ((data != RT_NULL) && (data_len == PAGE_DATA_SIZE) && (data + PAGE_DATA_SIZE) == spare)
  • //        {
  • //            //0x03 cl_addr[16bit] dummy[8bit]
  • //            column_data[0] = READ_CMD;
  • //            column_data[1] = (column_addr>>8)&0x0f; //only CA[11:0] is effective
  • //            column_data[2] = column_addr&0xff;
  • //            column_data[3] = DUMMY_CMD;
  • //            LOG_I("begin to read page %d.",page);
  • //            res =  rt_spi_send_then_recv(spi_device,&column_data,4, data, (data_len+spare_len));
  • //        }
  • //        else
  •         {
  •             if (data != RT_NULL && data_len != 0)
  •             {
  •                 //0x03 cl_addr[16bit] dummy[8bit]
  •                 column_data[0] = READ_CMD;
  •                 column_data[1] = (column_addr >> 8) & 0x0f; //only CA[11:0] is effective
  •                 column_data[2] = column_addr & 0xff;
  •                 column_data[3] = DUMMY_CMD;
  •                 res = rt_spi_send_then_recv(spi_device, &column_data, 4, data, (data_len));

  •                 rt_hw_us_delay(500);
  •                 column_addr = PAGE_DATA_SIZE;
  •                 //0x03 cl_addr[16bit] dummy[8bit]
  •                 column_data[0] = READ_CMD;
  •                 column_data[1] = (column_addr >> 8) & 0x0f; //only CA[11:0] is effective
  •                 column_data[2] = column_addr & 0xff;
  •                 column_data[3] = DUMMY_CMD;
  • //                res =  rt_spi_send_then_recv(spi_device,&column_data,4, spare, (spare_len));
  •                 res = rt_spi_send_then_recv(spi_device, &column_data, 4, oob, (PAGE_OOB_SIZE));

  • //                LOG_E("------------read data,page:%d", page);
  •                 /* verify ECC */
  • #ifdef RT_USING_NFTL
  •                 if (nftl_ecc_verify256(data, PAGE_DATA_SIZE, oob) != RT_MTD_EOK)
  •                 {
  •                     res = -RT_MTD_EECC;
  •                     LOG_E("****************************ECC failed!, page:%d", page);
  •                 }
  •                 else
  •                 {
  • //                    LOG_E("!!!!!!!!!!! ECC ok!, page:%d", page);
  •                 }
  • #endif

  •             }
  •             if (spare != RT_NULL && spare_len != 0)
  •             {
  • //                LOG_E("------------read spare,page:%d", page);
  •                 column_addr = PAGE_DATA_SIZE;
  •                 //0x03 cl_addr[16bit] dummy[8bit]
  •                 column_data[0] = READ_CMD;
  •                 column_data[1] = (column_addr >> 8) & 0x0f; //only CA[11:0] is effective
  •                 column_data[2] = column_addr & 0xff;
  •                 column_data[3] = DUMMY_CMD;
  •   //              res =  rt_spi_send_then_recv(spi_device,&column_data,4, spare, (spare_len));
  •                 res = rt_spi_send_then_recv(spi_device, &column_data, 4, oob, (PAGE_OOB_SIZE));
  •                                 //rt_thread_mdelay(20);
  •                 if (spare != RT_NULL)
  •                 {
  •                     rt_memcpy(spare, oob, PAGE_OOB_SIZE);
  •                 }

  •             }
  •         }
  •     }
  •     else //BUF=0,read begin with the page, end with all nand
  •     {
  •         //0x03 dummy[24bit]
  •         column_data[0] = READ_CMD;
  •         column_data[1] = DUMMY_CMD;
  •         column_data[2] = DUMMY_CMD;
  •         column_data[3] = DUMMY_CMD;
  •         rt_kprintf("BUF bit=0,will read one page to end of the nand,TODO......n");
  •     }

  •     return RT_EOK;
  • }


nandflash驱动以搞好,然后使用dfs_mount(“nand0”, “/“, “uffs”, 0, 0),挂载nand0设备,直接报坏块,在未挂载之前,使用mtd_nand read nand0 1 1 命令读取的数据全是ff ff,挂载文件系统后全部报坏块,而且再次使用mtd_nand命令读取数据就全变成0x00了,求大神来解答。上面是nand_readpag代码,同时附上截图




回帖(2)

马沃源

2025-9-12 17:35:09
大概率是NAND驱动移植的有问题。             
举报

五斤麻辣油

2025-9-17 17:43:58

问题分析:UFFS挂载NAND后所有块显示坏块的原因


当UFFS文件系统挂载NAND设备后所有块都被识别为坏块,通常是由以下原因导致(结合提供的_read_page函数代码片段分析):




核心原因:坏块标记读取逻辑错误


在NAND Flash中,坏块标记(Bad Block Marker, BBM)通常存储在OOB(Out-Of-Band)区域的特定位置(如第0页的第0字节)。若读取逻辑错误,可能导致所有块被误判为坏块。


关键检查点:




  1. OOB偏移量错误  



    • 坏块标记位置需符合具体NAND芯片规格(常见位置:page0的oob偏移01)。  

    • 若驱动中使用的偏移量错误(如设置为无效位置),读取到的永远是无效数据(非0xFF),导致误判。




  2. 页地址计算错误  



    • _read_page函数中的page参数应为物理页号。  

    • 若传入的页号未按块对齐(例如未指向块的第一页),会读取到非标记页,误判坏块。




  3. 未跳过出厂坏块标记位置  



    • 出厂坏块标记通常在第1个或第2个页(不同厂商不同)。  

    • 若扫描逻辑未正确跳过这些位置,会导致读取错误。






_read_page 相关的具体问题


static rt_err_t _read_page(struct rt_mtd_nand_device *device,
                           rt_off_t page,            // 物理页号
                           rt_uint8_t *data,         // 主数据缓存
                           rt_uint32_t data_len,     // 主数据长度
                           rt_uint8_t *spare,        // OOB数据缓存(未在片段中显式出现)
                           rt_uint32_t spare_len)    // OOB数据长度

可能缺陷:




  1. OOB数据未正确传递

    坏块检测需读取OOB区域,但若上层调用时未传入spare缓存或spare_len=0,则无法读取标记。




  2. ECC校验干扰

    若在_read_page中启用ECC校验且OOB数据损坏(如未初始化的NAND),可能导致:



    • ECC纠错失败,返回错误代码  

    • 上层逻辑将ECC失败视为块损坏




  3. 读取时序/硬件错误  



    • 错误的NAND控制器时序配置导致读取数据全为0x00(非0xFF),被误判为坏块。

    • 物理连接问题(如信号干扰)。






快速定位问题:调试建议




  1. 检查OOB读取逻辑

    验证坏块检测代码中是否从正确位置读取标记:


    // 示例:检查块0的第1页的OOB位置0
    _read_page(device, block * pages_per_block, NULL, 0, oob_buf, oob_size);
    if (oob_buf[0] != 0xFF) { /* 标记坏块 */ }



  2. 打印原始OOB数据

    在挂载扫描时打印每个块的首页OOB内容:


    uint8_t oob[64];
    _read_page(device, page_addr, NULL, 0, oob, device->oob_size);
    printf("Block %d OOB: %02X %02X ...n", block_id, oob[0], oob[1]);


    • 若所有OOB非全0xFF → 检测逻辑或硬件问题

    • 若OOB全0xFF → 误判问题在软件逻辑




  3. 验证页地址计算

    确认传入_read_pagepage参数是按块的首页地址计算的:


    rt_off_t page_addr = block_id * device->pages_per_block; // 必须指向块的第一页



  4. 检查驱动配置

    确认rt_mtd_nand_device结构体已正确初始化:


    struct rt_mtd_nand_device nand_dev = {
      .block_size = 128 * 1024,  // 块大小
      .page_size  = 2048,        // 页大小
      .oob_size   = 64,          // OOB大小
      .pages_per_block = 64,     // 每块页数
    };





常见解决方案




  1. 修正坏块标记位置

    根据芯片手册调整OOB偏移量(如使用oob[0]改为oob[1])。




  2. 禁用初始坏块扫描的ECC

    在读取坏块标记时跳过ECC校验:


    // 驱动层添加标志位区分操作类型
    if (is_badblock_scan) {
       disable_ecc(device);
       _read_page(...);
       enable_ecc(device);
    }



  3. 初始化空NAND的OOB区域

    首次使用前,先擦除整个设备并写入全0xFF到OOB区域。




  4. 检查硬件连接与时序

    用示波器验证NAND的读写信号,调整控制器时序参数(如tR/tW)。





关键提示:在未正确理解NAND物理布局前,勿随意修改坏块表(BBT)逻辑,否则可能导致数据永久损坏。



通过逐步排查OOB读取流程和硬件交互,可精准定位所有块变坏块的根本原因。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分