查看: 1213|回复: 2

[分享] 探讨i.MX RT1170下FlexSPI driver实现Flash编程时对于中断支持问题

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3300

    主题

    6547

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32032
    最后登录
    2024-4-26
    发表于 2023-2-2 10:17:15 | 显示全部楼层 |阅读模式
    探讨i.MX RT1170下FlexSPI driver实现Flash编程时对于中断支持问题


    前段时间有客户在官方社区反映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。
    11.png
    绝大部分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 里,然后再传输出去。
    12.png
    不同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 数据不能全部缓冲的情况,则需要一边传输一边缓冲。
    13.png
    在具体装载数据进 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 的一次装载
    14.png
    三、客户问题及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() 函数之前被开启的,那这样的实现确实是不能够很好地支持中断的。
    15.png
    四、如何改进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 先装满)。
    1. status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer)
    2. {
    3.     // 代码略去

    4.     /* Start Transfer. */
    5.     if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
    6.     {
    7.         result = FLEXSPI_WriteBlocking(base, xfer->data, xfer->dataSize);
    8.         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
    9.     }
    10.     else if (xfer->cmdType == kFLEXSPI_Read)
    11.     {
    12.         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
    13.         result = FLEXSPI_ReadBlocking(base, xfer->data, xfer->dataSize);
    14.     }
    15.     else
    16.     {
    17.         base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
    18.     }

    19.     // 代码略去
    20. }
    复制代码






    签到签到
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    3 小时前
  • 签到天数: 1941 天

    [LV.Master]伴坛终老

    61

    主题

    1万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    17298
    最后登录
    2024-4-26
    发表于 2023-2-2 13:47:38 | 显示全部楼层
    学习学习
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-3-27 10:12
  • 签到天数: 100 天

    [LV.6]常住居民II

    3

    主题

    1031

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    1320
    最后登录
    2024-3-27
    发表于 2023-2-3 09:12:29 | 显示全部楼层
    学习学习
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-27 03:20 , Processed in 0.129581 second(s), 24 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表