|
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是在FDCB里配置串行NOR Flash多个寄存器的注意事项。
关于使用 i.MXRT 启动头 FDCB 来设置 Flash 内部寄存器,痞子衡写过如下两篇文章,在进入本文之前,建议大家先阅读下这两篇文章,有个初步了解。
《在FDCB里设置Flash的Dummy Cycle》《在FDCB里切换Flash模式至QPI/OPI》我们知道 Flash 内部常常有多个状态/配置寄存器,这些寄存器有些是易失性的,有些是非易失性的。当芯片被指定从 Flash 启动的时候,我们如果希望 BootROM 能够根据不同应用需求来提前设置好这些 Flash 寄存器,那么在应用程序里就不用再额外配置了(涉及 Flash 工作状态变化的配置,如果是 XIP 程序去操作,需要考虑代码重定向问题)。
对于使用 FDCB 来配置 Flash 一个寄存器的操作,相信大家都很了解,在恩智浦 SDK 包里默认 FDCB 启动头里都有成功示例。最近痞子衡同事尝试使用 FDCB 去配置镁光 MT35X 的两个寄存器(地址为 0x000000 的寄存器切至 OPI DDR、地址为 0x000003 的寄存器设 Drive Strength)发现有一个寄存器设置没生效,这是怎么回事?今天我们来聊一聊:
Note: 本文适用于 i.MXRT500/600/1010/1020/1040/1050/1060/1160/1170一、FDCB提供的Flash寄存器配置能力我们先来看一下 FDCB 结构里跟 Flash 配置相关的成员,痞子衡整理如下,简单来说,就是有一条 deviceModeSeq 和三条 configCmdSeqs,所以最多能配置 Flash 里 4 个不同命令下对应的寄存器(有些 Flash 里一条配置命令能连续写入多个寄存器,这种情况下就能配置不止 4 个寄存器),这对于大部分应用场景都完全够用了。
Note 1: BootROM 执行这四个配置的顺序分别是 deviceModeSeq、configCmdSeqs[0]、configCmdSeqs[1]、configCmdSeqs[2],记住这个顺序。Note 2: deviceModeSeq 与 configCmdSeq 实现的配置功能几乎没有区别,两者能做的事情是一样的,可以互换。//!@brief FlexSPI Memory Configuration Block
typedef struct _FlexSPIConfig
{
// ...
//!
uint8_t deviceModeCfgEnable;
//!
uint8_t deviceModeType;
//!
uint16_t waitTimeCfgCommands;
//!
flexspi_lut_seq_t deviceModeSeq;
//!
uint32_t deviceModeArg;
//!
uint8_t configCmdEnable;
//!
uint8_t configModeType[3];
//!
flexspi_lut_seq_t configCmdSeqs[3];
//!
uint32_t configCmdArgs[3];
// ...
//!
uint16_t busyOffset;
//!
uint16_t busyBitPolarity;
//!
uint32_t lookupTable[64];
// ...
} flexspi_mem_config_t;
在 《在FDCB里设置Flash的Dummy Cycle》 一文最后,痞子衡已经分享了 BootROM 解析执行 configCmdSeq 的代码流程,在这个流程里我们能看到和 deviceModeType/configModeType[]、waitTimeCfgCommands 成员相关的逻辑代码,这里有必要进一步解释一下。
//!@brief Flash Configuration Command Type
enum
{
kDeviceConfigCmdType_Generic, //!
kDeviceConfigCmdType_QuadEnable, //!
kDeviceConfigCmdType_Spi2Xpi, //!
kDeviceConfigCmdType_Xpi2Spi, //!
kDeviceConfigCmdType_Spi2NoCmd, //!
kDeviceConfigCmdType_Reset, //!
};
当 deviceModeType/configModeType 成员被设置为 kDeviceConfigCmdType_Spi2Xpi 时;如果 FDCB 本身被获取时 BootROM 用得是 DPI/QPI/OPI 命令(根据 efuse 配置决定),那么此条 Flash 寄存器配置会被直接忽略;如果 BootROM 用得是普通一线 SPI 模式读取的 FDCB,那么这个 Flash 寄存器配置仍然生效。
kDeviceConfigCmdType_Spi2Xpi 等三个跟 Flash 命令模式切换相关的配置类型,顾名思义就是告诉 BootROM 这三种配置会导致 Flash 工作模式变化,而一旦 Flash 工作模式发生变化,用于判断配置是否完成的 READ_STATUS 命令也随之变得不可用(因为 SPI 模式下与 DPI/QPI/OPI 模式下的命令序列不同),这种情况下就需要借助 waitTimeCfgCommands 成员来实现软件延时以等待对 Flash 的配置真正生效(如果不等生效就直接进入后续流程,可能会导致启动问题)。
kDeviceConfigCmdType_Generic 配置类型,则是用于跟工作模式切换无关的 Flash 寄存器配置,这种情况下 BootROM 可以使用 READ_STATUS 命令来判断对 Flash 寄存器配置是否已经生效,那么就不需要 waitTimeCfgCommands 实现的延时等待(需要查 Flash 数据手册作相应设置,比较麻烦,而且手册里是给了典型值和最大值,取最大值会导致启动时间变长,典型值不能保证适用所有情况)。
二、配置Flash多个寄存器注意点Flash 配置寄存器的写入流程通常分三步:一、WRITE_ENABLE 使能写操作;二、具体的 CONFIG_REG 操作;三、READ_STATUS 或者软件延时确保配置已完成。这些命令序列全部存储在 FDCB 里的 lookupTable[64] 成员里。
关于 Flash 寄存器的配置操作,从寄存器属性上来看,分为易失性和非易失性两种,前者的操作一般是立即生效的,后者的操作不是立即生效(Flash 状态寄存器 WIP 位会反映进度)。从命令模式角度来看,分为非模式切换操作(比如设置 Dummy Cycle、Drive Strength)以及切换 SPI 与 DPI/QPI/OPI 模式操作两种,同样前者操作是立即生效,后者操作不是立即生效。
现在回到文章开头痞子衡同事遇到的问题,如果 deviceModeSeq 用于切换至 OPI DDR 模式,configCmdSeqs[0] 用于设 Drive Strength,请问哪一个操作没有生效?这里就不卖关子了,设 Drive Strength 没有生效,因为第一个配置是切换至 OPI DDR 模式,当 Flash 切换到该模式时,用于第二/三/四个配置的 WRITE_ENABLE 命令变得不可用了(还是因为 SPI 模式下与 DPI/QPI/OPI 模式下的命令序列不同),当然对应 Flash 寄存器设置就无效了。
那么如何避免这个问题?有一个一劳永逸的方法,那就是永远用 configCmdSeqs[2] 去做 SPI 与 DPI/QPI/OPI 模式切换操作,这样就不会影响前面三个配置。前面讲了,此时判断命令模式是否切换完成不能用 READ_STATUS 命令,那么就一定需要 waitTimeCfgCommands 来做软延时,如果延时时间不够,并且后续 BootROM 执行到验证 IVT 头时模式切换仍未完成,这会导致 IVT 启动头无法正确获取从而导致启动失败。
假设 waitTimeCfgCommands 延时设置对于命令模式切换已足够,这样问题就一定解决了吗?其实还不一定,如果此时已将 deviceModeSeq 用于设 Drive Strength,但是选择得是写入 Flash 非易失性存储器,这需要确保 waitTimeCfgCommands 延时对于写入非易失性寄存器也足够。翻看 MT35X 的数据手册可以发现,写入非易失性寄存器 cycle time 典型值是 0.2s,最大值是 1s。 |
|