痞子衡嵌入式:导致串行NORFlash在i.MXRT下无法正常下载/启动的常见因素之WriteProtection

编程

  大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是导致串行NOR Flash在i.MXRT下无法正常下载/启动的常见因素之Write Protection。

  i.MXRT系列MCU发布已两年多了,基于i.MXRT的客户产品也越来越多,可以说是全面开花了。痞子衡作为i.MXRT产品线的系统应用工程师,早期的时候还可以尽情做参考设计,现在基本大量时间都被客户支持占据了。

  因为i.MXRT系列都没有内置Flash(RT1064, RT1024等SIP型号除外),因此为其搭配一块串行NOR Flash去启动是客户项目的头等大事,而串行NOR Flash厂商非常多,客户选择余地很大,因此我们不得不与客户一起同茫茫Flash型号打交道,痞子衡也常常调侃自己已沦为Flash测试工程师。

  痞子衡在支持客户解决串行NOR Flash下载启动问题过程中主要遇到几个常见因素,这几个因素可能会影响Flash在i.MXRT下无法正常使用,上两篇痞子衡分别讲了 《SFDP因素》 和 《QE bit因素》, 今天痞子衡重点跟大家聊聊Write Protection这个因素。

一、引入客户板子可以启动、无法再次下载问题

  痞子衡最近遇到一个智能电表厂商客户,他们项目板卡选用的是主控i.MXRT1051 + 华邦W25Q64JVSSIQ,应用程序是MBED bootloader + User App二级加载设计,其中MBED bootloader是由Arm Pelion物联网小组主导设计的,User App是这个电表厂商自己的功能代码。

  客户的问题是烧写了一个特定版本的MBED bootloader运行之后,板卡Flash无法再次做烧写了,但是板子是能够正常从Flash启动的。客户之后尝试使用了各种下载工具都不管用(J-Flash/IDE/NXP Tool等),其中下载工具包括痞子衡设计的一站式下载工具 MCUBootUtility ,于是问题就转到了痞子衡这里(好像有点躺枪的感觉)。工具后台报的错是擦除或者写入时会返回 kStatus_FlexSPINOR_CommandFailure,导致无法下载。

  既然问题和特定版本的MBED bootloader有关,那看起来就是这个bootloader引入的问题,但是痞子衡拿不到客户MBED bootloader源码,无法做白盒分析。鉴于痞子衡这么多年和Flash打交道的经验,痞子衡盲猜是bootloader使能了Flash的软件写保护功能(Software Write Protection)导致的问题,于是痞子衡让客户寄来了一块板卡,实测来证实痞子衡的猜想。

二、修改SDK FlexSPI例程来读取Status Register

  查看W25Q64JVSSIQ数据手册得知,软件写保护功能的配置集成在Flash器件内部非易失性Status Register中,这款Flash一共有3个8bit的Status Register(状态寄存器均支持易失性写入(即断电恢复)和非易失性写入(即断电保持),由前导的Write Enable命令类型0x06/0x50决定),并且每个Status Register都有不同的读写命令:

  现在我们简单修改了下SDK里的如下flexspi nor例程(选择ram build),增加上述三个Status Register读取功能的支持,从而实测读取Status Register来做验证。

SDK_2.9.1_EVKB-IMXRT1050oardsevkbimxrt1050driver_examplesflexspi

orpolling_transfer

  首先是在 app.h 和 flexspi_nor_polling_transfer.c 中将Status Register的读取命令加入到LUT表中。原来工程里已经有Status Register 1的读取支持,所以我们仅需增加Status Register 2/3的支持即可。因为这新增的两条命令,需要将CUSTOM_LUT_LENGTH由60改到64(i.MXRT1051上最大64,即支持16条LUT Sequence)。

const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {

// ...

/* 原有 Read status register 1 */

[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

/* 新增 Read status register 2 */

[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG2] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

/* 新增 Read status register 3 */

[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG3] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x15, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),

// ...

};

  然后在 flexspi_nor_flash_ops.c 中新增如下 flexspi_nor_get_status_register() 函数,这个函数直接仿照 flexspi_nor_get_vendor_id() 函数流程写即可,Flash端时序是一样的。

status_t flexspi_nor_get_status_register(FLEXSPI_Type *base, uint8_t seqIndex, uint8_t *regValue)

{

uint32_t readValue;

flexspi_transfer_t flashXfer;

flashXfer.deviceAddress = 0;

flashXfer.port = kFLEXSPI_PortA1;

flashXfer.cmdType = kFLEXSPI_Read;

flashXfer.SeqNumber = 1;

flashXfer.seqIndex = seqIndex;

flashXfer.data = &readValue;

flashXfer.dataSize = 1;

status_t status = FLEXSPI_TransferBlocking(base, &flashXfer);

*regValue = (uint8_t)readValue;

/* Do software reset. */

FLEXSPI_SoftwareReset(base);

return status;

}

  最后就是在 flexspi_nor_polling_transfer.c 中的 main() 函数里增加 flexspi_nor_get_status_register() 函数调用语句,将Status Register 1/2/3的值全部读取出来。

static uint8_t s_regValue1 = 0;

static uint8_t s_regValue2 = 0;

static uint8_t s_regValue3 = 0;

int main(void)

{

status_t status;

BOARD_ConfigMPU();

BOARD_InitPins();

BOARD_BootClockRUN();

BOARD_InitDebugConsole();

flexspi_nor_flash_init(EXAMPLE_FLEXSPI);

/* Get status register 1-3. */

status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG, &s_regValue1);

status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG2, &s_regValue2);

status = flexspi_nor_get_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_READSTATUSREG3, &s_regValue3);

// ...

}

三、W25Q64JVSSIQ的Write Protection特性

  将上一节修改后的 flexspi nor 例程下载进RAM调试运行,可以读出Status Register 1/2/3的值分别为0x40、0x42、0x60,看起来Status Register确实被MBED bootloader修改过。痞子衡标出了W25Q64JVSSIQ内部状态寄存器中所有与写保护相关的bit位如下,我们需要对照Flash数据手册具体查看读出来的值对应了什么样的写保护设置:

  首先Status Register1[SRP],Status Register2[SRL]以及外部WP#引脚共同决定Status Register设置条件,本例中SRL和SRP均为0,则WP#引脚控制不生效,Status Register可以直接被设置。

  Status Register中其他写保护相关的bit位解释如下,其中WPS是核心设置,它决定了写保护是用单独的Block lock命令来控制(见Flash命令集)还是直接由Status Register1/2中的CMP,TB,SEC,BPx位来决定。

Status Register3[WPS]:决定写保护策略是独立的Block锁定命令控制(WPS=1,默认设置)还是由Status Register1/2控制(WPS=0)

Status Register1[BPx]:指定Flash Memory保护区域块范围

Status Register1[SEC]:指定Flash Memory保护区域块单位是4KB Sector(SEC=1)还是64KB Block(SEC=0)

Status Register1[TB]:指定Flash Memory保护区域是从Top(TB=0)/Bottom(TB=1)开始

Status Register2[CMP]:决定由BPx,SEC,TB决定的Flash Memory保护区域是否生效(否的话,则区域外是受保护的)

  综合上面分析,最后我们发现MBED bootloader将全部的8MB Flash空间都保护起来了,所以各种下载工具都无法正常烧写这款Flash了。

四、修改SDK FlexSPI例程来写入Status Register

  要想重新使能Flash烧写,需要一个单独的嵌入式小工程将Status Register1/2/3值再改回到默认状态(WPS=0, CMP=0),可按照第2节里读SR功能修改步骤,代码如下。代码工程修改完成后借助调试器下载到RAM运行一次即可,需要注意应在芯片SDP模式下运行,运行结束后,立刻借助其他下载工具将Flash里旧固件更新掉,保证这个过程中不存在软复位而导致旧固件被再次运行的可能。(此处是将Flash里的MBED bootloader换掉,因为是它在使能Flash的写保护功能)

// flexspi_nor_flash_ops.c 文件中新增 flexspi_nor_set_status_register() 函数

status_t flexspi_nor_set_status_register(FLEXSPI_Type *base, uint32_t regIdx, uint8_t regValue)

{

flexspi_transfer_t flashXfer;

status_t status;

uint32_t writeValue = (uint32_t)regValue;

/* Write enable */

status = flexspi_nor_write_enable(base, 0);

if (status != kStatus_Success)

{

return status;

}

flashXfer.deviceAddress = 0;

flashXfer.port = kFLEXSPI_PortA1;

flashXfer.cmdType = kFLEXSPI_Write;

flashXfer.SeqNumber = 1;

flashXfer.seqIndex = regIdx;

flashXfer.data = &writeValue;

flashXfer.dataSize = 1;

status = FLEXSPI_TransferBlocking(base, &flashXfer);

if (status != kStatus_Success)

{

return status;

}

status = flexspi_nor_wait_bus_busy(base);

/* Do software reset. */

FLEXSPI_SoftwareReset(base);

return status;

}

// app.h 文件中

#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG 9

#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2 10

#define NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3 11

//#define NOR_CMD_LUT_SEQ_IDX_ENTERQPI 10

//#define NOR_CMD_LUT_SEQ_IDX_EXITQPI 11

// flexspi_nor_polling_transfer.c 文件中将Status Register的写入命令加入到LUT表中

const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {

// ...

/* 原有 Write status register 1 */

[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x01, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),

/* 新增 Write status register 2 */

[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),

/* 新增 Write status register 3 */

[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x11, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),

/*

// Enter QPI mode //

[4 * NOR_CMD_LUT_SEQ_IDX_ENTERQPI] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x35, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

// Exit QPI mode //

[4 * NOR_CMD_LUT_SEQ_IDX_EXITQPI] =

FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xF5, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),

*/

};

int main(void)

{

status_t status;

BOARD_ConfigMPU();

BOARD_InitPins();

BOARD_BootClockRUN();

BOARD_InitDebugConsole();

flexspi_nor_flash_init(EXAMPLE_FLEXSPI);

/* Set status register 1-3. */

status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG, 0x00);

status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG2, 0x02);

status = flexspi_nor_set_status_register(EXAMPLE_FLEXSPI, NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG3, 0x60);

// ...

}

五、写在最后

  这里仅以华邦Flash为例介绍Write Protection,其他厂商Flash对于这个Write Protection特性设计也许有所不同,需要查看数据手册具体分析。此外鉴于Flash这种种因素会导致在i.MXRT无法下载或正常启动,痞子衡之前计划做的全新上位机工具MCUTestSuite,会考虑将串行NOR Flash状态信息查询功能(SFDP/QE bit/Write Protection等)也放进去,敬请关注这个新项目:

  • MCUTestSuite工具项目:https://github.com/JayHeng/NXP-MCUTestSuite

  至此,导致串行NOR Flash在i.MXRT下无法正常下载/启动的常见因素之Write Protection痞子衡便介绍完毕了,掌声在哪里~~~

欢迎订阅

文章会同时发布到我的 云海天主页、CSDN主页、知乎主页、微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

以上是 痞子衡嵌入式:导致串行NORFlash在i.MXRT下无法正常下载/启动的常见因素之WriteProtection 的全部内容, 来源链接: utcz.com/z/519657.html

回到顶部