Segger J-Flash下烧写遇到特定区域内校验失败的问题

描述

最近在支持一个i.MX RT1170欧美客户,客户项目里选用了来自Micron的四线NOR Flash - MT25QL256ABA8E12-0AAT作为启动设备,一般读写倒是没有问题,但是在 Segger J-Flash下烧写遇到了特定区域内校验失败的问题。

从本人过往丰富的Flash支持经验来看,亚太区客户一般选用ISSI(芯成)/Winbond(华邦)/MXIC(旺宏)/GigaDevices(兆易创新) 的Flash比较多,个人对这些厂商Flash可以说是门清了。这个欧美客户选用的是不太熟的Micron(镁光)产品,借着这个问题,正好带大家一起稍微深入地了解下Micron Flash产品。

一、引出客户问题

首先是复现下客户的问题,找块MIMXRT1170-EVK开发板,将板载其他厂商Flash换成这颗MT25QL256ABA8E12-0AAT(因为是T-PBGA24封装,所以需要放到原来的 OctalFlash位置——U21),然后将SDK_2.11.1_MIMXRT1170-EVKoardsevkmimxrt1170driver_examplesflexspi orpolling_transfer例程稍作适配性修改,主要是将customLUT里的命令表按Micron数据手册命令表做调整(全用了四字节地址命令),然后跑了一下例程发现基本的Flash读写擦操作没有问题(默认操作的是0x14000处的Sector),这表明硬件修改没有问题。

 

const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
    /* Fast read quad mode - SDR */
    [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR,       kFLEXSPI_1PAD, 0xEC, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x20),
    [4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = 
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x0a, kFLEXSPI_Command_READ_SDR,  kFLEXSPI_4PAD, 0x04),

    /* Erase Sector */
    [4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR,       kFLEXSPI_1PAD, 0xDC, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20),

    /* Page Program - quad mode */
    [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] =
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR,       kFLEXSPI_1PAD, 0x34, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20),
    [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] =
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP,      kFLEXSPI_1PAD, 0x00),
};

 

接下来就是按客户操作流程来复现Segger J-Flash烧写校验失败问题,客户其实是尝试烧写全部32MB数据来查看J-Flash及其配套下载算法能否适用这颗Flash,这里就用《超级下载算法RT-UFL v1.0》,经过测试,确实复现了客户的问题。

经过反复测试,定位了问题是这颗Micron32MB的Flash前3/4 区域(0x0 - 0x17FFFFF)是没问题的,但是在后1/4区域(0x1800000 - 1FFFFFF)均会出现校验错误(J-Flash软件里看擦写操作是能进行的,但后面发现其实根本没有正常擦写)。

开发板

二、Micron Flash有什么不同?

在分析客户问题之前,我们先来简单认识一下这颗Micron NOR Flash,经过浏览Micron的官网以及这颗Flash的数据手册,发现它确实跟其他厂商的NOR Flash设计有点区别。

首先是Flash容量,其他厂商一般都是能够提供从512Kb到2Gb全范围的Flash产品,但是Micron串行NOR Flash最小容量就是128Mb,果然是国际Memory大厂,设计就是豪横。

但是从Flash作为XIP启动设备角度而言,128Mb其实挺多的,普通的嵌入式项目没有这么大的代码存储需求。

开发板

其次是NOR Flash里的高频问题 《QE bit 设计》,一般Flash的IO2/3引脚复用功能都是通过内部状态寄存器里的QE位来控制,QE关闭则IO2/3是RESET#/HOLD#/WP#功能:如果QE开启则IO2/3用于数据传输(这种情况下才可以用Quad I/O相关命令)。

然而Micron Flash根本就没有QE位控制,IO2/3功能主要靠当前命令类型来决定:如果是Single SPI或者Dual I/O SPI命令,则IO2/3是RESET#/HOLD#/WP#功能;如果是Quad I/O SPI命令,则IO2/3 用于传输数据。

其它设计上的区别就不再详细展开了,等用到具体功能查看数据手册再去了解对比。

三、找到问题原因

现在来分析客户问题,Flash的后1/4区域在J-Flash下校验错误,那我们先修改 polling_transfer例程去操作0x1800000之后的Sector,发现确实跑不过。

如果不是Flash介质问题,也不是读写擦命令问题,那只能有一种解释,那就是 Flash里这个区域被保护了,Flash里是有非易失寄存器可以设置软件保护的,但是默认应该是全部区域不保护,而第一小节里我们先跑了polling_transfer例程验证 Flash读写,那大概率这个例程里有修改Flash内部寄存器操作,经过排查定位到了flexspi_nor_enable_quad_mode() 函数。

 

#define FLASH_QUAD_ENABLE            0x40U

const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
    /* Enable Quad mode */
    [4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =
        FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),
};

int main(void)
{
    // 代码省略

    /* Enter quad mode. */
    status = flexspi_nor_enable_quad_mode(EXAMPLE_FLEXSPI);
    if (status != kStatus_Success)
    {
        return status;
    }

    // 代码省略

 

第二小节介绍里我们知道Micron Flash是没有QE位设计的,因此 flexspi_nor_enable_quad_mode() 函数在这里是多余的,这个函数是将0x40写入到了命令标号为0x01的Status Register(这个操作适用于ISSI Flash),我们在数据手册里找到这个寄存器定义,发现被置位的bit 6是块保护控制位BP[3:0]里的最高位,并且 BP[3:0]设置是非易失性的(断电不丢失)。

开发板

再进一步往下找BP[3:0]设置与Flash空间对应关系,发现4'b1000设置就是保护后1/4区域里的所有block,至今似乎真相大白了。

为了验证这个发现,我们需要将StatusRegister重设为0x00,然后再用J-Flash烧写一次,这时候校验失败问题消失了,一切恢复正常。

开发板

一点小体会

回顾这个故事,如果事先不用polling_transfer例程去操作一次Flash,或者即使跑了例程但事先意识到了Micron Flash没有QE设计而删除flexspi_nor_enable_quad_mode() 函数,也就无法复现客户问题了,这也是本次故事里最神奇的地方,我和客户犯了同样的失误,也许这就是缘分?  

      审核编辑:彭静
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分