前段时间有客户在官方社区反映i.mx rt1170下,使用官方sdk里flexspi驱动去擦写flash时不能很好地支持全局中断。 客户项目里用了两块nor flash,分别挂在不同的 flexspi上,一块flash用于存储xip代码(flexspi1),另一块flash用于存储项目资源数据(flexspi2),显然这样的设计原理上是没有问题的,那为什么使能了中断会出问题呢?今天就来分析下这个问题:
注: 客户测试的sdk版本为 2.12.1,对应的flexspi driver版本为2.3.6
一、为什么擦写flash时经常需要关全局中断?
在具体分析客户问题之前,我们先来聊聊嵌入式应用里应对nor flash的擦写,为何大部分情况下都是要关闭全局中断(这里假设执行代码空间与擦写操作空间在同一个 flash上,当然是在不同区域),这其实跟如下两个特性有关:
1.1 rww特性(read-while-write)
rww特性的意思是在flash执行擦写命令进入busy 状态期间(flash内部状态寄存器 wip位变状态1)还能否继续响应非操作区域的读访问。如果sr[wip] = 1 时还能够支持读访问,则该flash 支持rww,反之则不支持rww。
绝大部分flash都是不支持rww特性的,这就是为什么flash擦写操作代码本身是需要重定向到ram里去执行(尤其是回读sr[wip]状态的代码)。
对于支持rww特性的flash,一般是以block为单位,flash擦写操作代码放在blockx 里执行,则可以操作blockx以外的其它block 区域,且不需要做代码重定向。
现在你应该知道对于不支持rww的flash为什么擦写时需要关闭全局中断了,因为无法保证中断响应相关代码全都重定向到ram里了,所以干脆在flash擦写期间不响应任何中断。
1.2 sclk stop特性
sclk stop特性的意思是在flash执行写入命令接受主设备传输过来的page数据期间,如果总线上sclk停止(一般情况是flexspi这一端的txfifo为空或者触发空条件),则flash能否也暂停接受当前page数据直到sclk继续输出从而继续处理剩下的page数据。
绝大部分flash是不支持sclk stop特性的,因此在mcu端如果传输page数据,需要一次性连续传输完成,一旦中途被打断,则两次不连续的page数据传输可能无法得到想要的page写入结果。这也是为何flash写入期间我们需要关闭中断。
二、flexspi外设写操作设计
关于i.mx rt上的flexspi外设基本情况,以前有两篇旧文 《flexspi支持在flash xip原理》、《flexspi支持ahb方式写入flash》,大家先读一下有个初步了解。 这里想重点说一下flexspi关于ipg方式写操作的设计,下图为flexspi外设的模块框图,绿色线标出了 ipg 方式写入的通路,这里大家可以看出,其中 ip_tx_fifo 模块起了重要的数据缓冲作用,驱动里往 flexspi->tfdrx 寄存器写入的 page 数据会先被装载进 ip_tx_fifo 里,然后再传输出去。
不同i.mx rt型号中ip_tx_fifo大小不一样,目前有三种大小:128、256或1024 bytes。
对于quadspi/octalspi nor flash来说,page 大小一般是256 bytes;对于 hyperbus flash,page 大小一般是 512 bytes。所以在 i.mx rt10xx 上 ip_tx_fifo 是不足以缓冲整个 page 的,i.mx rt117x 上可以缓冲 quadspi/octalspi nor 类型的 page,i.mx rt118x/5xx/6xx 上则可以缓冲全部 nor flash 类型的 page。
对于 page 数据不能全部缓冲的情况,则需要一边传输一边缓冲。
在具体装载数据进 ip_tx_fifo 时,主要涉及如下三个 flexspi 寄存器,ip_tx_fifo 一次只能被填入watermark level大小的数据,想要把全部 page 数据填进 ip_tx_fifo,需要分多次装载。只要 flexspi->intr[iptxwe] 标志为 0, 即代表 ip_tx_fifo 剩余空间大于等于 watermark level,那么就可以继续装载。
flexspi->iptxfcr[txwmrk] -- 设置一次装载进 ip_tx_fifo 的数据长度(即 watermark level),8 bytes为单位
flexspi->tfdrx -- 按 watermark level 长度填入 ip_tx_fifo 装载数据
flexspi->intr[iptxwe] -- 触发 ip_tx_fifo 的一次装载
三、客户问题及flexspi driver写操作流程
前面铺垫了这么多,终于来到客户遇到的 flexspi 驱动对于中断不支持的问题了。因为客户使用了两片flash,所以不存在 rww 限制问题,那剩下的原因就跟 sclk stop 特性有关,即 ip_tx_fifo 并没有缓冲全部的 page,导致 page 传输过程被中断打断了,然后 ip_tx_fifo 因为缓冲数据全部发完而使 flexspi 模块进入了 sclk stop 状态。
我们直接打开fsl_flexspi.c驱动文件,找到跟写操作相关的 flexspi_transferblocking() 函数,在函数实现里可以发现,启动写传输时序的控制位 flexspi->ipcmd[trg] 是在 ip_tx_fifo 填充动作 flexspi_writeblocking() 函数之前被开启的,那这样的实现确实是不能够很好地支持中断的。
四、如何改进flexspi driver支持中断?
知道了原因所在,改起来也很简单。如果是quadspi/octalspi nor flash类型(page=256 bytes),在 i.mx rt117x 上,其 ip_tx_fifo 大小为 256 bytes,能够缓冲全部的 page 大小,则可以先调用 flexspi_writeblocking() 装载全部的 page 数据,然后再开启 flexspi->ipcmd[trg] 去触发写传输时序,这时候就不怕被中断打断了,如下代码所示。
当然下面代码只是一个 workaround 式的实现示例,不是一个完整的解决方案,毕竟 flexspi 驱动要适配全部 i.mx rt 型号以及全部类型的 nor flash,此外还适用 nand 型 flash(page 一般是 2kb),这时候需要根据情况拆分调用多次 flexspi_writeblocking() 函数(不管怎样要保证启动写传输时序前,把 ip_tx_fifo 先装满)。
status_t flexspi_transferblocking(flexspi_type *base, flexspi_transfer_t *xfer){ // 代码略去 /* start transfer. */ if ((xfer->cmdtype == kflexspi_write) || (xfer->cmdtype == kflexspi_config)) { result = flexspi_writeblocking(base, xfer->data, xfer->datasize); base->ipcmd |= flexspi_ipcmd_trg_mask; } else if (xfer->cmdtype == kflexspi_read) { base->ipcmd |= flexspi_ipcmd_trg_mask; result = flexspi_readblocking(base, xfer->data, xfer->datasize); } else { base->ipcmd |= flexspi_ipcmd_trg_mask; } // 代码略去}
基于区块链技术的去中心化应用程序BeeStore介绍
LT8330 8V 至 30V 输入、–24V 负输出转换器
苹果:开发者要遵守iOS14反追踪政策
京东方量产Micro OLED面板,迎头追赶三星和LG
深入地解析机器学习常用算法
探讨i.MX RT下FlexSPI driver实现Flash编程时对于中断支持问题
适用于移动应用的三种扬声器驱动器的介绍
“2022(十四届)传感器与MEMS产业化技术国际研讨会(暨成果展)”即将于12月19-21日召开
人工智能面临专家短缺难题,谷歌试图促进人工智能自我升级
GaN圈“扫地僧”誉鸿锦:身藏宝藏,初现锋芒
不锈钢螺旋板换热器防腐蚀处理方法的揭秘
推出高性能S32K39系列MCU,支持新一代电气化应用
微生物传感器的工作原理
华硕电神5000手机电力怪兽震撼来袭,5000毫安电量充斥着满满的暴力!
如何打破AI芯片垄断霸权
数据科学经典算法 KNN 已被嫌慢,ANN 比它快 380 倍
PLC维修入门与故障处理实例
4G与5G的性能特点及差异比较解析
动视暴雪和腾讯宣布建立长期战略合作伙伴关系
基于80C196的频率测量及在电压采样中的应用