缺失DQS信号的FlexSPI连接Flash有何不同?

一、flexspi的dqs信号作用文章中没有提及四线 qspi flash,因为一般的四线 qspi flash 芯片并没有 dqs 信号引脚。flexspi 模块的 dqs 信号当然可以用来连接 octal flash、hyper flash 上的 dqs 引脚,那么对于四线 qspi flash,这个 dqs 信号就没有作用了吗?其实不是的。
我们翻开 i.mxrt1170 的数据手册(data sheet)找到 flexspi parameters 小节里的如下内容,就很清楚了。flexspin_mcr0[rxclksrc] 位对应了三种 dqs 信号源设置:0x0 - dummy read strobe looped back internally 设置即完全不用 dqs 引脚(可作它用),对应最高 60mhz sdr 访问速度;0x1 - dummy read strobe looped back through the dqs pad 设置即从 dqs 引脚上回环,因此 dqs 引脚需要悬空,对应最高 133mhz sdr 访问速度;0x3 - read strobe from memory device dqs pad 设置即接到存储芯片 dqs 引脚上,对应最高 166mhz sdr 访问速度;
• dummy read strobe generated by flexspi controller and looped back internally (flexspin_mcr0[rxclksrc] = 0x0)• dummy read strobe generated by flexspi controller and looped back through the dqs pad (flexspin_mcr0[rxclksrc] = 0x1)• read strobe provided by memory device and input from dqs pad (flexspin_mcr0[rxclksrc] = 0x3)
二、哪些flexspi引脚组不支持dqs?目前恩智浦已量产的所有 i.mxrt 型号里(rt500/600/1010/1015/1020/1050/1060/1160/1170),大部分的 flexspi 引脚组合都是包含 dqs 信号设计的,只有如下两个例外。没有 dqs 信号的引脚组合连 flash 时,应配置 flexspin_mcr0[rxclksrc] 为 0x0 - looped back internally。
2.1 i.mxrt600 flexspi0 portb2.2 i.mxrt1160/1170 flexspi2 2nd porta三、使能没有dqs的flexspi连接的flash对于不含 dqs 信号的 flexspi 引脚组合,使用恩智浦相关工具操作连接在其上的 nor flash 是需要做一些改动的,我们以 i.mxrt1170-validation 板卡为例来介绍具体改动。
i.mxrt1170-validation 板卡是专供恩智浦内部使用的,分为 cpu1/2/3/4 四款,每款的硬件连接不同,其中 cpu2 板卡在 flexspi2 2nd porta 上连接了一颗镁光的 mt25ql128:
3.1 sdk中flexspi擦写flash例程改动我们现在打开 sdk 里的 flexspi 例程,这个例程是针对 mimxrt1170-evk 板卡写的,在 evk 上 nor flash 默认是连在 flexspi1 1st porta 上的,因此我们需要对例程做一些改动。
例程路径:\\sdk_2.x.x_mimxrt1170-evk\\boards\\evkmimxrt1170\\driver_examples\\flexspi\\nor\\polling_transfer\\cm7首当其冲的改动当然是 pin_mux.c 文件里的 board_initpins() 函数,需要将 flexspi1 1st pinmux 换成 flexspi2 2nd pinmux:
void board_initpins(void) { clock_enableclock(kclock_iomuxc); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_05_flexspi1_a_dqs, 1u); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_06_flexspi1_a_ss0_b, 1u; //iomuxc_setpinmux(iomuxc_gpio_sd_b2_07_flexspi1_a_sclk, 1u); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_08_flexspi1_a_data00, 1u); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_09_flexspi1_a_data01, 1u); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_10_flexspi1_a_data02, 1u); //iomuxc_setpinmux(iomuxc_gpio_sd_b2_11_flexspi1_a_data03, 1u); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_05_flexspi1_a_dqs, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_06_flexspi1_a_ss0_b, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_07_flexspi1_a_sclk, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_08_flexspi1_a_data00, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_09_flexspi1_a_data01, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_10_flexspi1_a_data02, 0x0au); //iomuxc_setpinconfig(iomuxc_gpio_sd_b2_11_flexspi1_a_data03, 0x0au); iomuxc_setpinmux(iomuxc_gpio_sd_b1_00_flexspi2_a_ss0_b, 1u; iomuxc_setpinmux(iomuxc_gpio_sd_b1_01_flexspi2_a_sclk, 1u); iomuxc_setpinmux(iomuxc_gpio_sd_b1_02_flexspi2_a_data00, 1u); iomuxc_setpinmux(iomuxc_gpio_sd_b1_03_flexspi2_a_data01, 1u); iomuxc_setpinmux(iomuxc_gpio_sd_b1_04_flexspi2_a_data02, 1u); iomuxc_setpinmux(iomuxc_gpio_sd_b1_05_flexspi2_a_data03, 1u); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_00_flexspi2_a_ss0_b, 0x0au); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_01_flexspi2_a_sclk, 0x0au); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_02_flexspi2_a_data00, 0x0au); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_03_flexspi2_a_data01, 0x0au); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_04_flexspi2_a_data02, 0x0au); iomuxc_setpinconfig(iomuxc_gpio_sd_b1_05_flexspi2_a_data03, 0x0au);}然后再改一下 app.h 文件里的宏定义,从 flexspi1 换到 flexspi2,并相应调整 flash 属性(evk 上是 is25wp128,validation 板上是 mt25ql128),以及更新 flexspi_clock_init() 函数:
//#define example_flexspi flexspi1//#define example_flexspi_amba_base flexspi1_amba_base//#define example_flexspi_clock kclock_flexspi1#define example_flexspi flexspi2#define example_flexspi_amba_base flexspi2_amba_base#define example_flexspi_clock kclock_flexspi2static inline void flexspi_clock_init(void){ // 在 board_bootclockrun() 函数里给 flexspi 设置的时钟源是 osc_rc_48m_div2 / 2 即 12mhz // 这里没有再次分频,因此 flexspi root clock 就是 12mhz //clock_setrootclockdiv(kclock_root_flexspi1, 2); //clock_setrootclockmux(kclock_root_flexspi1, 0); clock_setrootclockdiv(kclock_root_flexspi2, 2); clock_setrootclockmux(kclock_root_flexspi2, 0);}上面都是大家能意识到的改动,但其实最容易被忽略的改动是 flexspi_nor_flash_ops.c 文件里的 flexspi_nor_flash_init() 函数,config.rxsampleclock 设置必须要改成 kflexspi_readsampleclkloopbackinternally 才行。代码全部改完之后下载运行就可以正常擦写 flash 了。
void flexspi_nor_flash_init(flexspi_type *base){ // 省略部分代码 ... flexspi_clock_init(); flexspi_config_t config; flexspi_getdefaultconfig(&config); config.ahbconfig.enableahbprefetch = true; config.ahbconfig.enableahbbufferable = true; config.ahbconfig.enablereadaddressopt = true; config.ahbconfig.enableahbcachable = true; //config.rxsampleclock = kflexspi_readsampleclkloopbackfromdqspad; config.rxsampleclock = kflexspi_readsampleclkloopbackinternally; flexspi_init(base, &config); // 省略部分代码 ...}3.2 sdk中flashloader工程使用现在我们再来用一下 sdk 里的 flashloader 工程,这个应用程序可以与恩智浦专用命令行上位机 blhost.exe 进行交互,工程需要用调试器下载进主芯片内部 ram 运行
工程路径:\\sdk_2.x.x_mimxrt1170-evk\\boards\\evkmimxrt1170\\bootloader_examples\\flashloader\\cm7flashloader 运行起来之后,使用 blhost 工具按序执行下列命令,也一样能对 flash 进行擦写:
blhost -u -- get-property 1# 选中 flexspi2blhost -u -- fill-memory 0x20000000 4 0xcf900002blhost -u -- configure-memory 9 0x20000000# 配置 nor flash(forced internal dqs)blhost -u -- fill-memory 0x20000000 4 0xc1000053 # 其中bit[7:4]是关键设置!!!blhost -u -- fill-memory 0x20000004 4 0x00110000blhost -u -- configure-memory 9 0x20000000blhost -u -- get-property 25 9# 下载包含 ivt 头的 appblhost -u -- flash-erase-region 0x60000000 0x8000blhost -u -- fill-memory 0x20000000 4 0xf000000fblhost -u -- configure-memory 9 0x20000000blhost -u -- write-memory 0x60001000 ivt_app.bin上面命令序列里第二条 fill-memory 命令的参数 0xc1000053 是关键,从 flashloader 源代码里看它其实是在设置 serial_nor_config_option_t.option0.b.misc_mode 为 kserialnorenhancemode_internalloopback,这个设置对于四线 qspi flash 而言就是设 config->memconfig.readsampleclksrc 为 kflexspireadsampleclk_loopbackinternally:
enum{ kserialnorenhancemode_disabled = 0, kserialnorenhancemode_0_4_4_mode = 1, kserialnorenhancemode_0_8_8_mode = 2, kserialnorenhancemode_dataorderswapped = 3, kserialnorenhancemode_2ndpinmux = 4, kserialnorenhancemode_internalloopback = 5,};status_t parse_sfdp(uint32_t instance, flexspi_nor_config_t *config, jedec_info_table_t *tbl, serial_nor_config_option_t *option){ status_t status = kstatus_invalidargument; do { // 省略部分代码... uint8_t misc_mode = option- >option0.b.misc_mode; if (misc_mode == kserialnorenhancemode_disabled) { // 省略部分代码... }#if flexspi_enable_no_cmd_mode_support else if (misc_mode == kserialnorenhancemode_0_4_4_mode) { // 省略部分代码... }#endif // flexspi_enable_no_cmd_mode_support else if (misc_mode == kserialnorenhancemode_internalloopback) { config- >memconfig.readsampleclksrc = kflexspireadsampleclk_loopbackinternally; } else { // do nothing } // 省略部分代码... } while (0); return status;}3.3 下载工具mcubootutility配置flashloader 的使用对一般客户来说太复杂了,还是图形化工具 mcubootutility 更方便,打开这个工具,按如下配置(主要就是图中蓝框圈起来的 misc mode 设置),也可以正常擦写 flash。熟悉这个工具原理的朋友应该知道它底层依赖得就是 3.2 节里的 flashloader 与 blhost。
3.4 sdk例程里的fdcb启动头改动最后就是 sdk 里全部例程的 xip build 都需要一个 fdcb 头,这个头定义在 evkmimxrt1170_flexspi_nor_config.c 文件里,这里也要改一下 readsampleclksrc 和 serialclkfreq 配置才行。
const flexspi_nor_config_t qspiflash_config = { .memconfig = { .tag = flexspi_cfg_blk_tag, .version = flexspi_cfg_blk_version, //.readsampleclksrc = kflexspireadsampleclk_loopbackfromdqspad, .readsampleclksrc = kflexspireadsampleclk_loopbackinternally, .csholdtime = 3u, .cssetuptime = 3u, .controllermiscoption = 0x10, .devicetype = kflexspidevicetype_serialnor, .sflashpadtype = kserialflash_4pads, //.serialclkfreq = kflexspiserialclk_133mhz, .serialclkfreq = kflexspiserialclk_60mhz, .sflasha1size = 16u * 1024u * 1024u, .lookuptable = { // read luts flexspi_lut_seq(cmd_sdr, flexspi_1pad, 0xeb, raddr_sdr, flexspi_4pad, 0x18), flexspi_lut_seq(mode8_sdr, flexspi_4pad, 0x00, dummy_sdr, flexspi_4pad, 0x04), flexspi_lut_seq(read_sdr, flexspi_4pad, 0x04, 0, 0, 0), }, }, .pagesize = 256u, .sectorsize = 4u * 1024u, .ipcmdserialclkfreq = 0x1, .blocksize = 256u * 1024u, .isuniformblocksize = false,};

2023年世界无线电通信大会达成6GHz历史性协议!
一文详解功率器件封装结构热设计方案
运放精度看哪个参数
医院的非线性负载有哪些,会产生什么影响?
使用DAQ设备测量热电偶的过程
缺失DQS信号的FlexSPI连接Flash有何不同?
如何新建一个软件工程详细资料讲解
中国在推动5G车联网行业应用的政策力度
OmniVision推出基于OmniBSI™ 像素技术的2款最新2微米图像传感器
派美特携多款蓝牙耳机亮相CESA:猫耳萌萌哒,创意十足
维信诺将剥离PMOLED资产,专注发展AMOLED业务
艾迈斯欧司朗与Energous携手开发无线供电多光谱传感解决方案
图像处理硬件加速引擎是什么 如何提高CPU芯片性能
微信漫画网站源码小说漫画分销系统总站搭建开发
雷达感应模组在智能门锁中的应用
iOS10.3 Beta3开发者预览版固件下载地址一览
苹果已证实收购了VR广播公司NextVR
《高级别自动驾驶应用白皮书》发布,百度萝卜快跑无人化商业应用成亮点
Mac历史第四次重大变革:转用ARM芯片,只为做出更好产品
SDNLAB技术分享:Ceph在云英的实践