本篇是开发笔记第四篇,咱们就重点聊聊如何让超级下载算法适用不同厂商生产的不同属性串行NOR Flash。
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是超级下载算法开发笔记(4)之轮询Flash配置参数。
文接上篇 《超级下载算法(RT-UFL)开发笔记(3) - 统一FlexSPI驱动访问》,现在超级下载算法中已经集成了BootROM版本的统一FlexSPI驱动,原则上BootROM能支持启动的所有串行NOR Flash型号,超级下载算法都可以对其进行擦写操作。BootROM虽然可以支持很多种不同的Flash,但其需要依赖用户提供一个名为FDCB的配置结构体放置在Flash固定偏移处,BootROM先配置FlexSPI为1bit SDR低速模式去访问Flash获取到FDCB,然后从FDCB中得到当前Flash的全部属性再去重新初始化FlexSPI外设。然而超级下载算法没法从用户处获取到Flash的信息,只能自力更生,使用轮询的方法去不断尝试,直到试出合适的配置参数。
本篇是开发笔记第四篇,咱们就重点聊聊如何让超级下载算法适用不同厂商生产的不同属性串行NOR Flash。
前言里讲了BootROM对Flash的支持是靠不同的FDCB结构体配置值来实现的,这个FDCB一共512bytes,原型及各byte定义在i.MXRT1xxx参考手册System Boot章节里 Serial NOR configuration block (512 bytes) 一小节有详细介绍。这个FDCB主要是用于配置FlexSPI外设的,咱们超级下载算法的 flexspi_nor_flash_init() 函数的一个主要参数 flexspi_nor_config_t 其实就是FDCB。
status_t flexspi_nor_flash_init(uint32_t instance, flexspi_nor_config_t *config);
关于这个FDCB具体如何赋值,恩智浦官网有一些应用笔记,这些应用笔记介绍了一些典型的Flash型号应该匹配什么样的FDCB值,从这些应用笔记里我们可以大概了解FDCB用法。
上面的应用笔记里列举了一些BootROM支持的Flash型号,这些型号仅仅是恩智浦工程师验证过的型号,而客户在实际项目中用到的Flash型号远远不止这些。从Flash型号本身角度来看,不同厂商的不同型号是独特且唯一的,但从FDCB角度而言,很多同类型Flash型号其实是一样的配置值。
那么我们现在是不是直接在超级下载算法中穷举不同的FDCB值去轮询呢?要知道FDCB有512bytes,这是个不小的结构体,轮询一遍太费时且低效了。我们需要进一步提炼FDCB,将其精简一下,只轮询那些跟Flash类型紧密相关的参数。这个工作其实也不需要我们做了,恩智浦ROM研发小组已经做好了,那便是8bytes的config option配置结构体,这个配置结构体也是超级下载算法的 flexspi_nor_get_config() 函数的一个主要参数 serial_nor_config_option_t。
status_t flexspi_nor_get_config(uint32_t instance, flexspi_nor_config_t *config, serial_nor_config_option_t *option);
其实这个神奇的8bytes的config option配置结构体不止一次地出现过痞子衡之前的文章里:《导致串行NOR Flash在i.MXRT下无法正常下载/启动的常见因素之SFDP》、《导致串行NOR Flash在i.MXRT下无法正常下载/启动的常见因素之QE bit》、《FlexSPI NOR启动时间(RT1170)》、《MCUBootUtility v2.3发布,这次不再放过任何一款Flash》,它非常精炼地概括了市面上主要的串行NOR Flash特性(都要符合JESD216规范),只要你提供config option,经过 flexspi_nor_get_config() 函数执行后便可以自动生成相对应的完整FDCB。
在i.MXRTxxx参考手册Non-Secure Boot ROM章节里你可以找到如下典型Flash型号对应的参考config option值:
直接利用512bytes的FDCB去轮询太难,但利用8bytes的config option去轮询就简单多了。我们顺着上文中提及的ufl_target_desc_t结构体,在其中新增几个成员(FlexSPI外设编号/基址/映射地址,config option),其中轮询主要跟config option有关。
typedef struct _target_desc { uint32_t imxrtChipId; uint32_t flexspiInstance; // 新增 uint32_t flexspiBaseAddr; // 新增 uint32_t flashBaseAddr; // 新增 serial_nor_config_option_t configOption; // 新增 flexspi_nor_flash_driver_t flashDriver; flexspi_bsp_driver_t flexspiBsp; } ufl_target_desc_t;
然后我们定义一个config option型的数组 s_flashConfigOpt[],里面存放一些经典的config option值。当前痞子衡的设计是仅轮询这些经典的config option值,并没有穷举config option,这也是从超级下载算法的执行效率角度考虑,这些经典的config option值足以覆盖80%以上的Flash型号了(后期如果要提高Flash覆盖率,会考虑转到穷举法的)。
static const serial_nor_config_option_t s_flashConfigOpt[] = { // For Normal Quad, eg. IS25LP064A, GD25LB256E {.option0.U = 0xc0000001, .option1.U = 0x00000000}, // For Normal Octal, eg. MX25UM51345G {.option0.U = 0xc0403001, .option1.U = 0x00000000}, {.option0.U = 0xc1503051, .option1.U = 0x20000014}, // For Normal HyperBus, eg. S26KS512S, IS26KS512S {.option0.U = (0xc0233000 + kSerialNorCfgOption_MaxFreq), .option1.U = 0x00000000}, // For Normal Octal, eg. MX25UM51245G {.option0.U = 0xc0403031, .option1.U = 0x00000000}, // For Normal Octal, eg. MT35X {.option0.U = 0xc0603001, .option1.U = 0x00000000}, // For Normal Octal, eg. ATXP032 {.option0.U = 0xc0803001, .option1.U = 0x00000000}, // For Normal 1-bit SDR {.option0.U = FLASH_CONFIG_OPT_1BIT_SDR, .option1.U = 0x00000000}, };
关于具体轮询操作,源码在 RT-UFL 项目中的ufl_auto_probe_flash.c 文件里,痞子衡就不再贴出了,只讲一下几个要点:
- 要点 1: 对于一些SIP版本的i.MXRT型号,没有必要再轮询了,直接给预设的config option值即可。
- 要点 2: config option参数轮询成功的判断标准是,执行初始化->擦->写操作均正常(或许还要加入回读校验)。
- 要点 3: 当前config option参数轮询失败进到下一个option值前需要对FlexSPI外设进行复位(有条件的话还要对Flash进行复位)。
- 要点 4: 不同Flash型号支持的最大速度不同,轮询时总是先从最低速开始,慢慢增速到最大支持的速度(当前是100MHz,后期会调整)。
- 要点 5: 为了照顾没有SFDP表的Flash(或不符合JESD216规范),轮询过程里增加了一个1bit SDR属性的FDCB表作为最后一个保底轮询。
至此,超级下载算法开发笔记(4)之轮询Flash配置参数痞子衡便介绍完毕了,掌声在哪里~~~