一、整体初始化流程我们知道外部串行nor flash是接到i.mxrt的flexspi外设引脚上,有时串行nor flash启动也叫flexspi nor启动。关于flexspi nor启动流程,i.mxrt1050参考手册system boot章节有如下流图,蓝框之外的流程属于常规i.mxrt启动xip app流程,是个通用流程。蓝框之内才是具体flexspi初始化步骤,这个步骤概括得比较精炼。
为了让大家对flexspi nor设备启动初始化流程有个更具体的概念,痞子衡重新画了一张更详细的流程图,图中灰底框里描述得是flexspi初始化流程,痞子衡将其分解成了六步,我们有必要深入这六步初始化流程。
二、分解初始化流程2.1 复位flash芯片(可选)第一步是尝试复位flash芯片,这步是可选的,在fuse_0x6e0[7]里配置,默认是不使能的。复位flash目的是为了让flash处于一个确定的初始状态,方便i.mxrt bootrom去配置访问。为什么要强调flash的初始状态,因为很多时候i.mxrt未必是冷启动(上电启动),也有可能是软复位启动(比如调用nvic_systemreset),这时候外部flash已经被软复位前执行过的bootrom甚至用户app配置过,因此flash的状态可能不是上电初始状态(一般来说板级设计里flash的reset#引脚要么悬空,要么连接i.mxrt的por#引脚),这可能会影响软复位后bootrom去再次配置启动这块不定态的flash。
fuse 0x6e0[7] - flexspi_reset_pin_en
正常的flash都提供了reset#引脚来实现跟上电复位一样的功能,对于普通8-pin的qspi flash,这个reset#引脚往往是跟信号线io3复用的(仅在qe bit没使能情况下有效),而对于16-pin的qspi flash或者hyperflash,其reset#引脚都是独立的。
bootrom就是借助了flash的reset#引脚来实现的复位操作,实现代码比较简单,i.mxrt1050 bootrom直接指定了gpio1[9]当做复位信号线,板级设计里需要你将gpio1[9]连到flash的reset#引脚,然后bootrom就是简单地拉低gpio1[9]即可。reset#信号都是低电平有效,bootrom直接拉低这个信号持续250us,这个低电平持续时间对于复位来说是够够的,很多flash数据手册里其实仅要求几us即可。
备注:对于bootrom的flash复位功能来说,主要适用有独立reset#引脚的flash。#define reset_pad_idx kiomuxc_sw_mux_ctl_pad_gpio_ad_b0_09#define reset_pin_mux iomuxc_sw_mux_ctl_pad_mux_mode(5)#define reset_pin_gpio gpio1#define reset_pin_index 9if ((ocotp- >misc_conf1 & 0x80) > > 7){ // set pinmux as gpio iomuxc- >sw_mux_ctl_pad[reset_pad_idx] = reset_pin_mux; // set gpio to output mode reset_pin_gpio- >gdir |= (1ucfg3 & 0x100000) > > 20){ flashtype = 7;}else{ flashtype = (ocotp- >cfg4 & 0x700) > > 8;}
上图中最重要的fdcb赋值是config.memconfig.lookuptable,它是flexspi外设需要的核心配置,有了这个配置,cpu便可以直接从ahb总线读取flash的内容,因为flexspi会自动解析ahb总线读请求然后翻译成具体flexspi读时序,底层读时序需要的命令、地址字节数、dummy周期都在lookuptable里。bootrom预存了如下6大类flash的lookuptable:
// dedicated 3byte address read(0x03), 24bit addressstatic const uint32_t s_dedicated3bread[4] = { flexspi_lut_seq(cmd_sdr, flexspi_1pad, 0x03, raddr_sdr, flexspi_1pad, 0x18), flexspi_lut_seq(read_sdr, flexspi_1pad, 0x04, stop, flexspi_1pad, 0), 0, 0};// dedicated 4byte address read(0x13), 32 bit addressstatic const uint32_t s_dedicated4bread[4] = { flexspi_lut_seq(cmd_sdr, flexspi_1pad, 0x13, raddr_sdr, flexspi_1pad, 0x20), flexspi_lut_seq(read_sdr, flexspi_1pad, 0x04, stop, flexspi_1pad, 0), 0, 0};// hyperflash readstatic const uint32_t s_hyperflashread[4] = { flexspi_lut_seq(cmd_ddr, flexspi_8pad, 0xa0, raddr_ddr, flexspi_8pad, 0x18), flexspi_lut_seq(caddr_ddr, flexspi_8pad, 0x10, dummy_rwds_ddr, flexspi_8pad, 0x0c), flexspi_lut_seq(read_ddr, flexspi_8pad, 0x04, stop, flexspi_8pad, 0), 0};// mxic octal ddr readstatic const uint32_t s_mxicoctddrread[4] = { flexspi_lut_seq(cmd_ddr, flexspi_8pad, 0xee, cmd_ddr, flexspi_8pad, 0x11), flexspi_lut_seq(raddr_ddr, flexspi_8pad, 0x20, dummy_ddr, flexspi_8pad, 0xc), flexspi_lut_seq(read_ddr, flexspi_8pad, 0x04, stop, flexspi_8pad, 0), 0};// micron octal ddr readstatic const uint32_t s_micronoctddrread[4] = { flexspi_lut_seq(cmd_sdr, flexspi_8pad, 0xfd, raddr_ddr, flexspi_8pad, 0x20), flexspi_lut_seq(dummy_ddr, flexspi_8pad, 0x8, read_ddr, flexspi_8pad, 0x04), 0, 0};// adesto octal ddr readstatic const uint32_t s_adestooctddrread[4] = { flexspi_lut_seq(cmd_sdr, flexspi_8pad, 0x0b, raddr_ddr, flexspi_8pad, 0x20), flexspi_lut_seq(dummy_ddr, flexspi_8pad, 0x8, read_ddr, flexspi_8pad, 0x04), 0, 0};2.3 第一次flexspi初始化第三步就是利用上述配置完成的初始fdcb块对flexspi外设进行第一次初始化,就是下面代码,这个流程跟官方sdk里的flexspi_nor_flash_init()大同小异,这里不予具体展开。如果在这里初始化就返回失败(这里一般不会失败,因为仅仅是flexspi外设自身初始化,并不涉及操作外部flash芯片的动作),bootrom则直接退出flexspi nor设备启动,转入sdp下载。
#define flexspi_instance 0uint32_t instance = flexspi_instance;status_t status = flexspi_init(instance, (flexspi_mem_config_t *)(&config));if (status != kstatus_success){ return status;}flexspi_update_lut(instance, 0, &config.memconfig.lookuptable, 1);2.4 若干善后工作上述第一次flexspi初始化一般都会成功的,但这并不代表fuse里的flashtype等配置跟板子上flash型号是匹配的,也就是说初始fdcb配置块此时还没有被充分验证其是否适用板载flash型号。
flexspi第一次初始化结束后,为了保证后续能正常ahb访问,bootrom里做了一些善后工作,主要是两件事:
做一些访问前的延时:根绝fuse 0x450[3:2] - hold time来调用microseconds_delay()做延时,以使flexspi外设完全准备好。做一次无效ahb访问:类似这样的代码 volatile uint32_t dummy = *(uint32_t *)0x60000000;,无效ahb读可以使flash退出continuous read模式2.5 获取用户fdcb配置块善后工作结束之后,此时cpu应该可以通过ahb正常访问flash了,这个阶段我们只需要从flash的偏移0地址处读取用户fdcb,验证用户fdcb是否存在,这里才是对前面初始fdcb配置块以及第一次flexspi外设初始化的真正考验。
验证用户fdcb是否存在就是简单读取fdcb的前四个字节(tag),验证这个tag是否合法。如果第一次验证tag不成功(有可能是flexspi配置不正确,也有可能是用户fdcb不存在),会尝试做一次三字节地址切换到四字节地址的lut更新(仅适用qspi flash),然后做第二次tag读取验证,如果此时还是验证失败(大概率是不存在用户fdcb了),bootrom则直接退出flexspi nor设备启动,转入sdp下载。
#define flexspi_amba_base (0x60000000u)#define flash_base flexspi_amba_base// 使用三字节地址的lut对flash进行初次ahb访问flexspi_clear_cache(flexspi_instance);flexspi_nor_config_t *pconfig = (flexspi_nor_config_t *)flash_base;if (pconfig- >memconfig.tag != flexspi_cfg_blk_tag){ // 因为拿不到用户fdcb的tag,尝试切换使用四字节地址的lut if (flashtype == 0) { flexspi_update_lut(flexspi_instance, 0, s_basic4bread, 1); } flexspi_clear_cache(flexspi_instance); pconfig = (flexspi_nor_config_t *)flash_base;}// 对flash进行第二次ahb访问,再次确认能否拿到用户fdcb的tagif (pconfig- >memconfig.tag != flexspi_cfg_blk_tag){ return kstatus_fail;}上面代码里有flexspi_clear_cache()操作,这个其实就是利用flexspi0->mcr0[swreset]做一个外设级别的软复位,另外代码里还涉及到一个四字节地址qspi flash的lut表,即如下所示:
// basic read with 32bit addressstatic const uint32_t s_basic4bread[4] = { flexspi_lut_seq(cmd_sdr, flexspi_1pad, 0x03, raddr_sdr, flexspi_1pad, 0x20), flexspi_lut_seq(read_sdr, flexspi_1pad, 0x04, stop, flexspi_1pad, 0), 0, 0};2.6 第二次flexspi初始化到了这里,基本代表第一次flexspi初始化是正确且可用的,并且能够拿到有效的用户fdcb配置块。这时候就是利用用户fdcb配置块对flexspi外设做第二次初始化,初始化代码流程跟第一次初始化是一模一样的。
这个第二次初始化是非常有必要的,因为它反映了用户的真实需求,用户fdcb配置块里会准确描述板载flash的全面特性(访问速度,真实存储空间大小,特殊定制lut等等),这些信息必须由用户来提供。
需要注意的是,第二次flexspi初始化返回成功并不代表用户fdcb配置块一定就是正确的,还是那句话,这仅仅是对flexspi外设自身的初始化。后续常规app解析流程里才是对这个用户fdcb配置块的真正考验。
如何优化数据实现机器学习高数据吞吐量
ADC简介、原理及主要参数
诺基亚MeeGo操作系统仍有希望存续
苹果手机卸载软件到底会不会有残留iOS的沙盒机制到底是什么
线性温度传感器的使用常识
深入i.MXRT1050系列ROM中串行NOR Flash启动初始化流程
Profinet转CANopen协议转换网关基本应用
易制的家用脉冲治疗仪,Low frequency signal generator
上海 8月11日-12日《案例分析与EMC设计》公开课即将开始!
美国国家半导体温度传感器的广泛应用
诺基亚在IFA 2019展会上推出新款诺基亚6.2和诺基亚7.2
MMU包含两个模块是什么
纳米手机膜竟是“智商税”?
Cypress单芯片低功耗蓝牙BLE解决方案的特点分析
LG G6将在3月亮相,超强配置,或许打乱国产机排名!
中性点接地电阻柜的原理以及如何选择电阻
液位开关和液位传感器的区别及选用
现阶段纯电动汽车用户最大的痛点是什么
超全攻略 HUAWEI WATCH 2智能运动手表完美演绎超强实用感
研发遥控免疫疗法 可辨识和杀死癌细胞