前段時間有客戶在官方社區反映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上,當然是在不同區域),這其實跟如下兩個特性有關:
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; } // 代碼略去 }
審核編輯:湯梓紅
-
FlaSh
+關注
關注
10文章
1635瀏覽量
148082 -
編程
+關注
關注
88文章
3616瀏覽量
93760 -
中斷
+關注
關注
5文章
898瀏覽量
41514 -
driver
+關注
關注
0文章
526瀏覽量
66616 -
SDK
+關注
關注
3文章
1037瀏覽量
45977
原文標題:探討i.MX RT下FlexSPI driver實現Flash編程時對于中斷支持問題
文章出處:【微信號:NXP_SMART_HARDWARE,微信公眾號:恩智浦MCU加油站】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論