1 SPI NOR
現在很多嵌入式系統使用了SPI NOR FLASH,而不選擇CFI NOR FLASH,這樣能夠節省更多的I/O口。而現在SPI NOR FLASH的讀取速度其實很快了,像最新的MXIC的OCTAL FLASH能夠達到400MB/s的讀取速率,而只需要12跟I/O線即可。
本文選擇一種具體的SPI NOR FLASH以及NXP i.MX系列SOC上的FlexSPI控制器來講解SPI NOR的一些概念以及軟件的編寫,這裏選擇MICRON的MT25系列的QuadSPI FLASH。
1.1 SPI 協議
最原始的SPI協議很簡單,只有四根線,其通信原理很簡單,它以主從方式工作,這種模式通常有一個主設備和一個或多個從設備,需要至少4根線,事實上3根也可以(單向傳輸時)。也是所有基於SPI的設備共有的,它們是SDI(數據輸入),SDO(數據輸出),SCK(時鐘),CS(片選)。
- SDO 主設備數據輸出,從設備數據輸入
- SDI 主設備數據輸入,從設備數據輸出
- SCLK 時鐘信號,由主設備產生
- SS 從設備使能信號,由主設備控制, 低電平選中
SPI有四種工作模式,各個工作模式的不同在於SCLK不同, 具體工作由CPOL,CPHA決定
CPOL: (Clock Polarity),時鐘極性
當CPOL爲0時,時鐘空閒時電平爲低;
當CPOL爲1時,時鐘空閒時電平爲高;
CPHA:(Clock Phase),時鐘相位
當CPHA爲0時,時鐘週期的上升沿採集數據,時鐘週期的下降沿輸出數據;
當CPHA爲1時,時鐘週期的下降沿採集數據,時鐘週期的上升沿輸出數據;
CPOL和CPHA,分別都可以是0或時1,對應的四種組合就是:
四種工作模式現如下:
1.2 SPI NOR FLASH
上面看到傳統的SPI協議只有四根I/O線,而SPI NOR FLASH的廠商爲了增加數據吞吐量,將SPI NOR FLASH的數據線進行擴展,因此產生了SPI FLASH,Dual SPI FLASH(兩根data線),Quad SPI FLAHS(4根data線), Octal SPI FLASH(8根data線)。在clock一定的情況下, 理論上線數越多速度越快。而對於SPI NOR FLASH來說,似乎不需要全雙工的操作,因爲讀寫一般不會同時進行。
由於現在QSPI FLASH比較流行,所以QSPI的一些操作都已經比較標準化了,許多能從SPI NOR中的SFDP中讀出,後面有一小節會介紹SPI NOR 的SFDP。而Octal FLASH在市場上時間比較短,並且價格昂貴,使用的系統還不是很多。所以Octal FLASH現在沒有一個統一的標準,不同廠家Octal FLASH的Octal I/O的讀寫有很大的差異。
下面我們看一些主流的一些SPI NOR FLASH的一些信息。
1.2.1 主流設備
主流生產SPI NOR FLASH的廠商有MICRON,MXIC, CYPRESS,SPANSION,ADESTO等。
MT25QL512AB
這是MICRON的一款QSPI FLASH,它支持Single I/O,Dual I/O和Quad I/O。不過一般來說對於QSPI FLASH來說,只會用Single或者Quad I/O,很少會用Dual I/O。
對於STR傳輸,也就是單時鐘邊沿採樣,最高採樣頻率能達到133MHz。對於DTR雙邊沿採樣來說,最高採樣頻率能達到66MHz。所以SDR和DTR的採樣數據的速度其實是一樣的。
下圖是MT25的I/O口描述
與傳統的SPI 接口相比,多了W#/DQ2和DQ3/HOLD#,這兩個I/O在Quad SPI情況下用作I/O口,在Dual和Single的情況下用作其他用處,這裏不做闡述。
MT35XU02GCBA
這是MICRON的一款Octal FLASH,它支持Single I/O和Octal I/O。對於STR傳輸,也就是單時鐘邊沿採樣,最高採樣頻率能達到166MHz。對於DTR雙邊沿採樣來說,最高採樣頻率能達到200MHz,實際採樣數據速率能到達400MB/s。所以Octal FLASH相比於QSPI FLASH性能提升是很大,但同時Octal FLASH相比於QSPI FLASH會貴很多。對於太部分嵌入式系統來說,成本比性能更重要,所以最主流的還是QSPI FLASH。
下圖是MT35的I/O口描述
C是時鐘信號,S#是片選,DQ[7:0]是數據線,DQS是讀數據採樣時鐘,W#寫保護信號。
DQS
因爲Octal FLASH DTR 200MH的情況下,由於CLK的傳輸的時候有延遲,單純使用SPI HOST傳過來的時鐘信號會導致採樣不準確,所以FLASH提供了一根DQS信號要提供讀數據採樣時鐘給HOST。而寫數據就不會有這種問題,所以寫數據沒有DQS。
S26KL512S
這是CYPRESS的一款HyperFLASH。 HyperFLASH也是一種8根I/O的FLASH,但它的操作跟其他廠家的Octal FLASH又很不一樣。這裏貼上一篇當時學習HyperFLASH的小記,比較詳細介紹了HyperFLASH的接口以及時序等。
HyperBus Nor Flash小記
1.2.2 SPI NOR 主要操作時序
簡單起見,這裏以MT25爲例來講解QSPI FLASH的一些主要的命令的時序:讀,寫,擦除,寫使能,讀寄存器等。
原因有2:QSPI FLASH現在使用的最多,QSPI相對於Octal FLASH來說使用起來簡單一點。這裏只討論Extended SPI,Dual SPI和Qual SPI就不討論了,這三種模式的差異僅僅體現在命令的傳輸上。Extended SPI命令傳輸使用DQ0,而Dual SPI使用兩根線來傳輸命令, Quad SPI使用四根線來傳輸命令。
讀命令13h
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
4-BYTE READ | 13h | 1-1-1 | 4 | 0 | 1 to ∞ |
這個讀命令是最基本的SPI 模式,命令,地址和數據都採用一根DQ線來傳輸。地址使用4個byte。下來貼出改命令的時序圖。
這個時序很簡單,在0-7的時鐘週期內,SPI HOST發出1個byte的命令13h。緊接着發出32位的地址,地址先發高位。最後FLASH以一個byte爲單位送出數據,同樣的數據先發高位。
讀命令ECh
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
4-BYTE QUAD INPUT/OUTPUT FAST READ | ECh | 1-4-4 | 4 | 10 | 1 to ∞ |
ECh是STR的Quad I/O讀命令,在Extended SPI模式下, 命令階段HOST採用一個I/O口DQ0來發送8bit的ECh。
緊接着在8-16個時鐘週期內HOST發出32位的地址,同樣高位數據先發,比如在第八個Cycle時候,DQ3發送addr[31],DQ2發送addr[30],DQ1發送addr[29], DQ0發送addr[28]。
ECh需要dummy 的clock cycle,這段時間內FLASH內的控制器需要做一些操作將數據讀出,並且送到SPI總線上。從MT25的RM中看到這裏ECh的Dummy Cycle需要10個Clock Cycle。
最後Flash就會將數據送出,送出的數據格式與地址的格式一樣,高位先發。因爲STR模式,所以可以看到在數據採樣階段,一個Clock Cycle只有採樣一個bit的數據。
讀命令EEh
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
4-BYTE DTR QUAD INPUT/OUTPUT FAST READ | EEh | 1-4-4 | 4 | 8 | 1 to ∞ |
這裏應該是EEh,估計是MT25的RM上寫錯了。這上面的EDh跟EEh的時序是一樣的。EEh是DTR模式下的QUAD I/O,它基本跟ECh的時序是一樣的。與ECh不同的點在於EEh的地址階段和數據階段都是雙邊沿採樣,所以在Address和Data階段中,一個Clock Cycle會採到兩個bit。從上圖中可以看出來
讀FLASH ID 9Eh
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
READ ID | 9Eh | 1-0-1 | 0 | 0 | 1 to 20 |
9Eh時序非常簡單,HOST送出8bit的命令,然後FLASH會依次送出8bit的Manufaturer ID,16bit的Device ID,以及不定長的UID。下圖是MT25的Device ID數據結構
讀Status Register 05h
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
READ STATUS REGISTER | 05h | 1-0-1 | 0 | 0 | 1 to ∞ |
這個圖的時序是讀register的操作,就是除了status register還有其他的register。所有的讀register時序都是一樣的,HOST在DQ0發出8bit的命令,然後FLASH給出register的值。這裏status register一共是八位,一般用來查詢讀操作是否完成。
32KB SUBSECTOR擦除命令52h
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
32KB SUBSECTOR ERASE | 05h | 1-0-1 | 0 | 0 | 1 to ∞ |
我們知道對NOR FLASH來說,只能從1寫到0,所以在對某一個word或者byte進行寫操作的時候,需要對NOR FLASH進行擦除。但一般SPI NOR FLASH都沒有字節擦除的命令,最小都是基於SUBSECTOR的擦除。比如52h就是32KB SUBSECTOR的擦除命令。擦除之後整個32KB的SUBSECTOR會被置爲全1。
時序很簡單,HOST先發出8bit的命令,然後發出32bit的地址就可以了。
寫命令 12h
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
4-BYTE PAGE PROGRAM | 12h | 1-1-1 | 0 | 0 | 1 to 256 |
寫命令一次只能寫一個PAGE,也就是256個byte。這裏只貼出了Single的寫命令,其他的Quad和Dual的寫命令的時序都查不到,類比於讀命令。有興趣的可以查FLASH的RM。
時序比較簡單,基本跟讀命令13h是一樣的,只是在Data階段,數據是由HOST發出,而不是FLASH發出。並且Single的SPI模式下,HOST發出的數據在DQ0上傳輸。
寫使能 06h
不管是在擦除還是寫數據之前,都需要進行寫使能操作,才能操作SPI NOR FLASH。
Command | Code | Command-Addess-Data(Extended SPI) | Address Bytes | Dummy Clock Cycles(Extended SPI) | Data Bytes |
---|---|---|---|---|---|
WRITE ENABLE | 06h | 1-0-0 | 0 | 0 | 0 |
這種類型的命令只有Command階段,也就是HOST發出8bit的命令就行。
1.2.3 JEDEC SFDP
隨着串行Flash市場不斷的擴張,串行Flash的指令、功能和特性也日趨增多,而且各個廠商在串行Flash器件上的功能和特性也無法完全一致。例如,在扇區擦除功能上,支持4kB、32kB、64kB的擦除操作雖然分別有相應的指令,但是不同廠商的器件還是會存在一些指令和功能的差異。爲了準確地完成系統的兼容性測試或者是考慮到容量的升級,開發和設計人員需要詳細閱讀每一份串行Flash的產品規範,瞭解引腳的分佈和定義是否一致,操作所需要用到的功能指令是否完全兼容,從而對底層設備驅動軟件做相應的增補和修改,甚至改動到硬件,這無疑給項目的設計、維護和更新帶來一些不便。因此,串行Flash器件迫切需要一個統一規範的功能參數表,可以讓開發和設計人員明確地讀取到每一個所使用串行Flash的功能和參數特性。JEDEC的新規範JESD216 SFDP就是在這樣的一個市場環境下孕育而生的。摘自http://www.21ic.com/app/rf/201308/189076.htm
簡而言之,SFDP就是存儲在SPI NOR FLASH 內部的一個數據結構,通過這個數據結構能夠得到一些SPI NOR FLASH的信息,比如說是否支持Quad I/O傳輸,Quad I/O的命令是什麼,諸如此類,這樣的話。在驅動初始化的時候先讀出SFDP,然後根據SFDP解析出SPI NOR FLASH的信息去初始化HOST控制器。而不需要爲每一個FLASH建立一堆配置。可惜的是現在SFDP僅支持QSPI FLASH。對於OCTAL FLASH,沒辦法讀出相應的信息,在驅動程序中,如果要兼容不同廠家的OCTAL FLASH,還要去建立各種各樣的配置。
SPI NOR JEDEC標準
分析一下MT25的SFDP長什麼樣,從中能夠得到什麼信息。
上圖是SFDP主要的header。
- 前4個byte存的是SFDP簽名,這個是SFDP標準固定。
- 04h和05h分別存放了SFDP的主版本號和次版本號。
- 06h記錄了一共有多少個參數表,MT25只有一個parameter table。parameter table裏面記錄的就是QSPI的一些信息。
- 08h-0Fh記錄了第一個paramter table的信息。如果有多個parameter table的話,在第一個parameter table後面會有多個這個的數據結構。
下面幾可以看下MT25X的第一個parameter table長什麼樣
從上圖中可以看到,從MT25的第一個parameter table中可以讀出許多MT25X NOR FLASH的關鍵信息,比如FLASH的大小,是否支持1-4-4(Quad I/O),1-4-4傳輸的命令和dummy cycle,SUBSECTOR擦除命令, Program的命令等等。通過讀這張表驅動程序就能很容易的適配兼容JEDEC標準的SPI NOR FLASH。
1.3 i.MX FlexSPI控制器
NXP i.MX系列的SOC帶了一個叫FlexSPI的控制器,它支持兩個channel,最多能連接4片QSPI FLASH。每一個Channel支持Single/Dual/Quad/Octal傳輸模式。該控制器的詳細介紹可以參看NXP上i.MX RT1020的RM中的FlexSPI章節。這裏只介紹一些最關鍵的情況。
i.MX RT1020 Processor Reference Manual
FlexSPI具有以下特性:
- 可配置的命令序列(LUT table)來支持不同廠家的設備
- SPI NOR Flash或者類似於SPI NOR Flash的設備
- SPI NAND Flash
- HyperBus設備(HyperFlash/HyperRAM)
- Flash訪問模式
- Single/Dual/Quad/Octal
- SDR/DDR
- 採樣頻率支持(只要是讀時序的DQS)
- Internal dummy read strobe loopbacked internally
- Internal dummy read strobe loopbacked from pad
- SCK clock output loopbacked from pad
- Flash provided read strobe
- 使用AHB Bus完成Memory mapped 讀寫訪問
- 使用AHB RX Buffer來降低讀數據的延遲。AHB RX Buffer總大小:256 * 64 bits
- 支持16個AHB master。
- 8個可配置的AHB RX Buffer。
- 使用AHB TX BUffer來降低寫數據的延遲,AHB TX Buffer大小: 8 * 64 bits、
- 使用IP Bus來對Flash進行讀寫訪問。
1.3.1 外部I/O
下圖是FlexSPI與SPI NOR FLASH之間的連接。
1.3.2 時鐘
Clock Name | Description | Comment |
---|---|---|
serial clock root(ipg_clk_sfck) | Root clock for Serial Domain | - |
ahb clock(HCLK) | AHB Bus clock | - |
ipg clock(ipg_clock) | IPS Bus Clock | - |
SCK | Output clock on SCK pin | Half clock frequency of serial clock root in DDR mode, and same frequency as serial root in SDR mode. Clock output toggles during the whole flash access sequence. |
SCK2 | Output clock on SCK2 pin | 90 degree phase shifted from SCK in DDR mode. No clock output in SDR mode |
DQS_OUT | Dummy Read Strobe output | Same frequency as SCK. Clock output toggles during READ/LEARN instructions |
DQS_IN | Sample clock for RX data | Same frequency as SCK. Sample clock comes from loopbacked dummy read strobe, loopbacked SCK or Flash provided read strobe |
1.3.3 LUT Table
FlexSPI 並不直接通過寄存器來操作SPI Bus上的數據傳輸,而是提供了一組叫LUT Table的接口。也就是用戶需要先將操作SPI Slave設備的命令根據LUT Table的規則寫入到LUT Table,然後通過寄存器告訴FlexSPI某一個命令的LUT Sequence,然後FlexSPI 會去處理SPI Bus上的事。
先看一下LUT Table的數據結構,它是FlexSPI內部的一段未初始化內存。目前的FlexSPI一共16個Sequence。每一個Sequence包含8個instruction,每個instruction佔用兩個byte。Instruction的格式如最下圖所示,0-7位是操作數operand,8-9位是instruction的pad(1PAD, 2PAD, 4PAD, 8PAD),10-15位是操作碼opcode。
下表是LUT Sequence的Instrcution指令
在1.3.4中會列出一些常見的SPI NOR FLASH的LUT Sequence。
1.3.4 初始化
- 使能時鐘(AHB clock/IP Bus clock/Serial root clock),需要在SOC層的代碼完成。
- MCR0[MDIS]設爲0x1(使控制器處於停止模式)。
- 設置MCR0, MCR1, MCR2寄存器(不要去改變MCR0[MDIS])。
- 設置AHB bus控制寄存器(AHBCR),如果要使用AHB command來讀數據,那麼還要需要設置AHB RX Buffer控制寄存器(AHBRXBUFxCR)
- 設置Flash控制寄存器(FLSHxCR0, FLSHxCR1, FLSHxCR2)。
- 設置DLL控制寄存器(DLLCR),這個寄存器主要使用設置讀採樣頻率的。
- MCR0[MDIS]設置爲0(打開FlexSPI)。
- 配置LUT Table
- 軟件復位FlexSPI(設置MCR0[SWRESET]爲0x1)
1.3.5 SPI NOR Flash應用
這裏提供了一些常見的LUT Command Sequence,結合SPI NOR 主要操作時序小節
寫使能06h
Instruction No. | Instruction opcode[5:0] | Instruction num_pads[1:0] | Instruction operand[7:0] | Comment |
---|---|---|---|---|
0 | CMD_SDR | 0x0(Single) | 0x06 | command name: WREN |
1-7 | STOP(0x00) | 0 | 0 |
寫命令 12h
Instruction No. | Instruction opcode[5:0] | Instruction num_pads[1:0] | Instruction operand[7:0] | Comment |
---|---|---|---|---|
0 | CMD_SDR | 0x0(Single) | 0x12 | command name: 4-Byte address mode |
1 | ADDR_SDR | 0x0(Single) | 0x20 | Address bit number, 32 for 4-Byte address mode |
2 | WRITE_SDR | 0x0(Single) | Any non-zero value | This operand value could be used as default programming data size if IPCR0.IDATSZ is zero. This value is ignored for AHB command |
3-7 | STOP(0x00) | 0 | 0 |
讀Status Register 05h
Instruction No. | Instruction opcode[5:0] | Instruction num_pads[1:0] | Instruction operand[7:0] | Comment |
---|---|---|---|---|
0 | CMD_SDR | 0x0(Single) | 0x05 | command name:RDSR1 |
1 | READ_SDR | 0x0(Single) | 0x1 | 1 Byte for Status register1 |
2-7 | STOP(0x0) | 0x0 | 0x00 |
讀命令EEh
Instruction No. | Instruction opcode[5:0] | Instruction num_pads[1:0] | Instruction operand[7:0] | Comment |
---|---|---|---|---|
0 | CMD_SDR | 0x0(Single) | 0x0EE | command name:4QPIOR_DDR |
1 | ADDR_DDR | 0x2(Quad) | 0x20 | Address bit number, 32 for 4-Byte address mode |
2 | MODE8_DDR | 0x2(Quad) | Any value other than 0xAx | Exit continous read mode or keep in non-continous read mode. |
3 | DUMMY_DDR | 0x2(Quad) | 0x08 | Dummy cycle is 8 as CR2V[3:0]=0x8. |
4 | READ_DDR | 0x2(Quad) | Any non-zero value | This operand value could be used as default reading data size if IPCR0.IDATSZ is zero. This value is ignored for AHB command |
5-7 | STOP(0x0) | 0 | 0x00 |
1.4 SPI NOR 驅動程序實例
下面是一個簡單的基於FlexSPI控制器的驅動程序。整個驅動就包含5個文件。
- imx_flexspi.c封裝了FlexSPI控制器的寄存器操作
- imx_flexspi.h定義了FlexSPI的寄存器以及控制器相關的一些宏定義。
- imx_flexspi_port.c實現一些系統級的代碼,如時鐘使能,管腳分配等,用於不同平臺的移植。
- spi_nor.h封裝了spi nor的操作。
- imx_flexspi_nor.c實現了spi_nor.h中的接口。
spi_nor.h
#ifndef SPI_NOR_H
#define SPI_NOR_H
#include <stdint.h>
typedef struct spi_nor_cmd_set_tag {
uint8_t reset_enable;
uint8_t reset_memory;
uint8_t read_id;
uint8_t read_sfdp;
uint8_t read;
uint8_t read_dummy_cycles;
uint8_t read_cmd_mode;
uint8_t read_addr_mode;
uint8_t read_data_mode;
uint8_t write_enable;
uint8_t write_disable;
uint8_t read_status_reg;
uint8_t read_flag_status_reg;
uint8_t read_nvconfig_reg;
uint8_t read_vconfig_reg;
uint8_t read_evconfig_reg;
uint8_t read_eadd_reg;
uint8_t read_gp_read_reg;
uint8_t program;
uint8_t program_dummy_cycles;
uint8_t program_cmd_mode;
uint8_t program_addr_mode;
uint8_t program_data_mode;
uint8_t write_status_reg;
uint8_t write_nvconfig_reg;
uint8_t write_vconfig_reg;
uint8_t write_evconfig_reg;
uint8_t write_eaddr_reg;
uint8_t clear_flag_status_reg;
uint8_t erase_bulk;
uint8_t erase_32KB_subsector;
uint8_t erase_4KB_subsector;
uint8_t erase_sector;
}spi_nor_cmd_set_t;
typedef struct spi_nor_tag {
void *host;
spi_nor_cmd_set_t cmd_set;
uint32_t (*read_id)(struct spi_nor_tag *spi_nor, uint8_t *id_buf, uint32_t buf_size);
uint32_t (*read_sfdp)(struct spi_nor_tag *spi_nor, uint8_t *sfdp_buf);
uint32_t (*read)(struct spi_nor_tag *spi_nor, uint8_t *dst, uint8_t *src, uint32_t size);
uint32_t (*write)(struct spi_nor_tag *spi_nor, uint8_t *dst, uint8_t *src, uint32_t size);
uint32_t (*write_enable)(struct spi_nor_tag *spi_nor);
uint32_t (*erase_sector)(struct spi_nor_tag *spi_nor, uint32_t addr);
uint32_t (*erase_bulk)(struct spi_nor_tag *spi_nor);
uint32_t (*read_status_reg)(struct spi_nor_tag *spi_nor, uint8_t *status_reg);
} spi_nor_t;
extern uint32_t init_spi_nor(spi_nor_t *spi_nor, uint32_t instance);
#endif /* SPI_NOR_H */
代碼很簡單
- spi_nor_t定義了SPI NOR Flash的常用操作,讀寫擦除等
- 同時它包含一個host指針指向具體的控制器對象
- 還包含一個cmd_set對象,在初始化spi_nor_t結構時,初始化該對象,然後後面具體的操作比如讀操作就可以根據不同命令產生不同的時序。
imx_flexspi.h
#ifndef IMX_FLEXSPI_H
#define IMX_FLEXSPI_H
#include <stdint.h>
#define FLEXSPI_BASE 0x30BB0000U
#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
typedef struct {
volatile uint32_t mcr0; /**< Module Control Register 0, offset: 0x0 */
volatile uint32_t mcr1; /**< Module Control Register 1, offset: 0x4 */
volatile uint32_t mcr2; /**< Module Control Register 2, offset: 0x8 */
volatile uint32_t ahbcr; /**< AHB Bus Control Register, offset: 0xC */
volatile uint32_t inten; /**< Interrupt Enable Register, offset: 0x10 */
volatile uint32_t intr; /**< Interrupt Register, offset: 0x14 */
volatile uint32_t lutkey; /**< LUT Key Register, offset: 0x18 */
volatile uint32_t lutcr; /**< LUT Control Register, offset: 0x1C */
volatile uint32_t ahbrxbufcr0[8]; /**< AHB RX Buffer 0 Control Register 0..
AHB RX Buffer 3 Control Register 0, array offset: 0x20, array step: 0x4 */
uint8_t reserved0[32];
volatile uint32_t flashcr0[4]; /**< Flash A1 Control Register 0..
Flash B2 Control Register 0, array offset: 0x60, array step: 0x4 */
volatile uint32_t flashcr1[4]; /**< Flash A1 Control Register 1..
Flash B2 Control Register 1, array offset: 0x70, array step: 0x4 */
volatile uint32_t flashcr2[4]; /**< Flash A1 Control Register 2..
Flash B2 Control Register 2, array offset: 0x80, array step: 0x4 */
uint8_t reserved1[8];
volatile uint32_t flashcr5; /**< Flash Control Register 5, offset: 0x98 */
uint8_t reserved2[4];
volatile uint32_t ipcr0; /**< IP Control Register 0, offset: 0xA0 */
volatile uint32_t ipcr1; /**< IP Control Register 1, offset: 0xA4 */
uint8_t reserved3[8];
volatile uint32_t ipcmd; /**< IP Command Register, offset: 0xB0 */
volatile uint32_t dlpr; /**< Data Learn Pattern Register, offset: 0xB4 */
volatile uint32_t iprxcr; /**< IP RX FIFO Control Register, offset: 0xB8 */
volatile uint32_t iptxcr; /**< IP TX FIFO Control Register, offset: 0xBC */
volatile uint32_t dllcr[2]; /**< DLL Control Register 0, array offset: 0xC0, array step: 0x4 */
uint8_t reserved4[24];
volatile uint32_t sts0; /**< Status Register 0, offset: 0xE0 */
volatile uint32_t sts1; /**< Status Register 1, offset: 0xE4 */
volatile uint32_t sts2; /**< Status Register 2, offset: 0xE8 */
volatile uint32_t ahbspndsts; /**< AHB Suspend Status Register, offset: 0xEC */
volatile uint32_t iprxsts; /**< IP RX FIFO Status Register, offset: 0xF0 */
volatile uint32_t iptxsts; /**< IP TX FIFO Status Register, offset: 0xF4 */
uint8_t reserved5[8];
volatile uint32_t rfdr[32]; /**< IP RX FIFO Data Register 0..
IP RX FIFO Data Register 31, array offset: 0x100, array step: 0x4 */
volatile uint32_t tfdr[32]; /**< IP TX FIFO Data Register 0..
IP TX FIFO Data Register 31, array offset: 0x180, array step: 0x4 */
volatile uint32_t lut[64]; /**< LUT 0..LUT 63, array offset: 0x200, array step: 0x4 */
} flexspi_t;
/*! @name MCR0 - Module Control Register 0 */
#define FLEXSPI_MCR0_SWRESET_MASK (0x1U)
#define FLEXSPI_MCR0_SWRESET_SHIFT (0U)
#define FLEXSPI_MCR0_SWRESET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_SWRESET_SHIFT)) & FLEXSPI_MCR0_SWRESET_MASK)
#define FLEXSPI_MCR0_MDIS_MASK (0x2U)
#define FLEXSPI_MCR0_MDIS_SHIFT (1U)
#define FLEXSPI_MCR0_MDIS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_MDIS_SHIFT)) & FLEXSPI_MCR0_MDIS_MASK)
#define FLEXSPI_MCR0_RXCLKSRC_MASK (0x30U)
#define FLEXSPI_MCR0_RXCLKSRC_SHIFT (4U)
#define FLEXSPI_MCR0_RXCLKSRC(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_RXCLKSRC_SHIFT)) & FLEXSPI_MCR0_RXCLKSRC_MASK)
#define FLEXSPI_MCR0_ARDFEN_MASK (0x40U)
#define FLEXSPI_MCR0_ARDFEN_SHIFT (6U)
#define FLEXSPI_MCR0_ARDFEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_ARDFEN_SHIFT)) & FLEXSPI_MCR0_ARDFEN_MASK)
#define FLEXSPI_MCR0_ATDFEN_MASK (0x80U)
#define FLEXSPI_MCR0_ATDFEN_SHIFT (7U)
#define FLEXSPI_MCR0_ATDFEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_ATDFEN_SHIFT)) & FLEXSPI_MCR0_ATDFEN_MASK)
#define FLEXSPI_MCR0_HSEN_MASK (0x800U)
#define FLEXSPI_MCR0_HSEN_SHIFT (11U)
#define FLEXSPI_MCR0_HSEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_HSEN_SHIFT)) & FLEXSPI_MCR0_HSEN_MASK)
#define FLEXSPI_MCR0_DOZEEN_MASK (0x1000U)
#define FLEXSPI_MCR0_DOZEEN_SHIFT (12U)
#define FLEXSPI_MCR0_DOZEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_DOZEEN_SHIFT)) & FLEXSPI_MCR0_DOZEEN_MASK)
#define FLEXSPI_MCR0_COMBINATIONEN_MASK (0x2000U)
#define FLEXSPI_MCR0_COMBINATIONEN_SHIFT (13U)
#define FLEXSPI_MCR0_COMBINATIONEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_COMBINATIONEN_SHIFT)) & FLEXSPI_MCR0_COMBINATIONEN_MASK)
#define FLEXSPI_MCR0_SCKFREERUNEN_MASK (0x4000U)
#define FLEXSPI_MCR0_SCKFREERUNEN_SHIFT (14U)
#define FLEXSPI_MCR0_SCKFREERUNEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_SCKFREERUNEN_SHIFT)) & FLEXSPI_MCR0_SCKFREERUNEN_MASK)
#define FLEXSPI_MCR0_LEARNEN_MASK (0x8000U)
#define FLEXSPI_MCR0_LEARNEN_SHIFT (15U)
#define FLEXSPI_MCR0_LEARNEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_LEARNEN_SHIFT)) & FLEXSPI_MCR0_LEARNEN_MASK)
#define FLEXSPI_MCR0_IPGRANTWAIT_MASK (0xFF0000U)
#define FLEXSPI_MCR0_IPGRANTWAIT_SHIFT (16U)
#define FLEXSPI_MCR0_IPGRANTWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_IPGRANTWAIT_SHIFT)) & FLEXSPI_MCR0_IPGRANTWAIT_MASK)
#define FLEXSPI_MCR0_AHBGRANTWAIT_MASK (0xFF000000U)
#define FLEXSPI_MCR0_AHBGRANTWAIT_SHIFT (24U)
#define FLEXSPI_MCR0_AHBGRANTWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_AHBGRANTWAIT_SHIFT)) & FLEXSPI_MCR0_AHBGRANTWAIT_MASK)
/*! @name MCR1 - Module Control Register 1 */
#define FLEXSPI_MCR1_AHBBUSWAIT_MASK (0xFFFFU)
#define FLEXSPI_MCR1_AHBBUSWAIT_SHIFT (0U)
#define FLEXSPI_MCR1_AHBBUSWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR1_AHBBUSWAIT_SHIFT)) & FLEXSPI_MCR1_AHBBUSWAIT_MASK)
#define FLEXSPI_MCR1_SEQWAIT_MASK (0xFFFF0000U)
#define FLEXSPI_MCR1_SEQWAIT_SHIFT (16U)
#define FLEXSPI_MCR1_SEQWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR1_SEQWAIT_SHIFT)) & FLEXSPI_MCR1_SEQWAIT_MASK)
/*! @name MCR2 - Module Control Register 2 */
#define FLEXSPI_MCR2_CLRAHBBUFOPT_MASK (0x800U)
#define FLEXSPI_MCR2_CLRAHBBUFOPT_SHIFT (11U)
#define FLEXSPI_MCR2_CLRAHBBUFOPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_CLRAHBBUFOPT_SHIFT)) & FLEXSPI_MCR2_CLRAHBBUFOPT_MASK)
#define FLEXSPI_MCR2_CLRLEARNPHASE_MASK (0x4000U)
#define FLEXSPI_MCR2_CLRLEARNPHASE_SHIFT (14U)
#define FLEXSPI_MCR2_CLRLEARNPHASE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_CLRLEARNPHASE_SHIFT)) & FLEXSPI_MCR2_CLRLEARNPHASE_MASK)
#define FLEXSPI_MCR2_SAMEDEVICEEN_MASK (0x8000U)
#define FLEXSPI_MCR2_SAMEDEVICEEN_SHIFT (15U)
#define FLEXSPI_MCR2_SAMEDEVICEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_SAMEDEVICEEN_SHIFT)) & FLEXSPI_MCR2_SAMEDEVICEEN_MASK)
#define FLEXSPI_MCR2_SCKBDIFFOPT_MASK (0x80000U)
#define FLEXSPI_MCR2_SCKBDIFFOPT_SHIFT (19U)
#define FLEXSPI_MCR2_SCKBDIFFOPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_SCKBDIFFOPT_SHIFT)) & FLEXSPI_MCR2_SCKBDIFFOPT_MASK)
#define FLEXSPI_MCR2_RESUMEWAIT_MASK (0xFF000000U)
#define FLEXSPI_MCR2_RESUMEWAIT_SHIFT (24U)
#define FLEXSPI_MCR2_RESUMEWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_RESUMEWAIT_SHIFT)) & FLEXSPI_MCR2_RESUMEWAIT_MASK)
/*! @name AHBCR - AHB Bus Control Register */
#define FLEXSPI_AHBCR_APAREN_MASK (0x1U)
#define FLEXSPI_AHBCR_APAREN_SHIFT (0U)
#define FLEXSPI_AHBCR_APAREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_APAREN_SHIFT)) & FLEXSPI_AHBCR_APAREN_MASK)
#define FLEXSPI_AHBCR_CACHABLEEN_MASK (0x8U)
#define FLEXSPI_AHBCR_CACHABLEEN_SHIFT (3U)
#define FLEXSPI_AHBCR_CACHABLEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_CACHABLEEN_SHIFT)) & FLEXSPI_AHBCR_CACHABLEEN_MASK)
#define FLEXSPI_AHBCR_BUFFERABLEEN_MASK (0x10U)
#define FLEXSPI_AHBCR_BUFFERABLEEN_SHIFT (4U)
#define FLEXSPI_AHBCR_BUFFERABLEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_BUFFERABLEEN_SHIFT)) & FLEXSPI_AHBCR_BUFFERABLEEN_MASK)
#define FLEXSPI_AHBCR_PREFETCHEN_MASK (0x20U)
#define FLEXSPI_AHBCR_PREFETCHEN_SHIFT (5U)
#define FLEXSPI_AHBCR_PREFETCHEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_PREFETCHEN_SHIFT)) & FLEXSPI_AHBCR_PREFETCHEN_MASK)
#define FLEXSPI_AHBCR_READADDROPT_MASK (0x40U)
#define FLEXSPI_AHBCR_READADDROPT_SHIFT (6U)
#define FLEXSPI_AHBCR_READADDROPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_READADDROPT_SHIFT)) & FLEXSPI_AHBCR_READADDROPT_MASK)
/*! @name INTEN - Interrupt Enable Register */
#define FLEXSPI_INTEN_IPCMDDONEEN_MASK (0x1U)
#define FLEXSPI_INTEN_IPCMDDONEEN_SHIFT (0U)
#define FLEXSPI_INTEN_IPCMDDONEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDDONEEN_SHIFT)) & FLEXSPI_INTEN_IPCMDDONEEN_MASK)
#define FLEXSPI_INTEN_IPCMDGEEN_MASK (0x2U)
#define FLEXSPI_INTEN_IPCMDGEEN_SHIFT (1U)
#define FLEXSPI_INTEN_IPCMDGEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDGEEN_SHIFT)) & FLEXSPI_INTEN_IPCMDGEEN_MASK)
#define FLEXSPI_INTEN_AHBCMDGEEN_MASK (0x4U)
#define FLEXSPI_INTEN_AHBCMDGEEN_SHIFT (2U)
#define FLEXSPI_INTEN_AHBCMDGEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBCMDGEEN_SHIFT)) & FLEXSPI_INTEN_AHBCMDGEEN_MASK)
#define FLEXSPI_INTEN_IPCMDERREN_MASK (0x8U)
#define FLEXSPI_INTEN_IPCMDERREN_SHIFT (3U)
#define FLEXSPI_INTEN_IPCMDERREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDERREN_SHIFT)) & FLEXSPI_INTEN_IPCMDERREN_MASK)
#define FLEXSPI_INTEN_AHBCMDERREN_MASK (0x10U)
#define FLEXSPI_INTEN_AHBCMDERREN_SHIFT (4U)
#define FLEXSPI_INTEN_AHBCMDERREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBCMDERREN_SHIFT)) & FLEXSPI_INTEN_AHBCMDERREN_MASK)
#define FLEXSPI_INTEN_IPRXWAEN_MASK (0x20U)
#define FLEXSPI_INTEN_IPRXWAEN_SHIFT (5U)
#define FLEXSPI_INTEN_IPRXWAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPRXWAEN_SHIFT)) & FLEXSPI_INTEN_IPRXWAEN_MASK)
#define FLEXSPI_INTEN_IPTXWEEN_MASK (0x40U)
#define FLEXSPI_INTEN_IPTXWEEN_SHIFT (6U)
#define FLEXSPI_INTEN_IPTXWEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPTXWEEN_SHIFT)) & FLEXSPI_INTEN_IPTXWEEN_MASK)
#define FLEXSPI_INTEN_DATALEARNFAILEN_MASK (0x80U)
#define FLEXSPI_INTEN_DATALEARNFAILEN_SHIFT (7U)
#define FLEXSPI_INTEN_DATALEARNFAILEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_DATALEARNFAILEN_SHIFT)) & FLEXSPI_INTEN_DATALEARNFAILEN_MASK)
#define FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK (0x100U)
#define FLEXSPI_INTEN_SCKSTOPBYRDEN_SHIFT (8U)
#define FLEXSPI_INTEN_SCKSTOPBYRDEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SCKSTOPBYRDEN_SHIFT)) & FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK)
#define FLEXSPI_INTEN_SCKSTOPBYWREN_MASK (0x200U)
#define FLEXSPI_INTEN_SCKSTOPBYWREN_SHIFT (9U)
#define FLEXSPI_INTEN_SCKSTOPBYWREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SCKSTOPBYWREN_SHIFT)) & FLEXSPI_INTEN_SCKSTOPBYWREN_MASK)
#define FLEXSPI_INTEN_AHBBUSTIMEOUTEN_MASK (0x400U)
#define FLEXSPI_INTEN_AHBBUSTIMEOUTEN_SHIFT (10U)
#define FLEXSPI_INTEN_AHBBUSTIMEOUTEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBBUSTIMEOUTEN_SHIFT)) & FLEXSPI_INTEN_AHBBUSTIMEOUTEN_MASK)
#define FLEXSPI_INTEN_SEQTIMEOUTEN_MASK (0x800U)
#define FLEXSPI_INTEN_SEQTIMEOUTEN_SHIFT (11U)
#define FLEXSPI_INTEN_SEQTIMEOUTEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SEQTIMEOUTEN_SHIFT)) & FLEXSPI_INTEN_SEQTIMEOUTEN_MASK)
/*! @name INTR - Interrupt Register */
#define FLEXSPI_INTR_IPCMDDONE_MASK (0x1U)
#define FLEXSPI_INTR_IPCMDDONE_SHIFT (0U)
#define FLEXSPI_INTR_IPCMDDONE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDDONE_SHIFT)) & FLEXSPI_INTR_IPCMDDONE_MASK)
#define FLEXSPI_INTR_IPCMDGE_MASK (0x2U)
#define FLEXSPI_INTR_IPCMDGE_SHIFT (1U)
#define FLEXSPI_INTR_IPCMDGE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDGE_SHIFT)) & FLEXSPI_INTR_IPCMDGE_MASK)
#define FLEXSPI_INTR_AHBCMDGE_MASK (0x4U)
#define FLEXSPI_INTR_AHBCMDGE_SHIFT (2U)
#define FLEXSPI_INTR_AHBCMDGE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBCMDGE_SHIFT)) & FLEXSPI_INTR_AHBCMDGE_MASK)
#define FLEXSPI_INTR_IPCMDERR_MASK (0x8U)
#define FLEXSPI_INTR_IPCMDERR_SHIFT (3U)
#define FLEXSPI_INTR_IPCMDERR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDERR_SHIFT)) & FLEXSPI_INTR_IPCMDERR_MASK)
#define FLEXSPI_INTR_AHBCMDERR_MASK (0x10U)
#define FLEXSPI_INTR_AHBCMDERR_SHIFT (4U)
#define FLEXSPI_INTR_AHBCMDERR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBCMDERR_SHIFT)) & FLEXSPI_INTR_AHBCMDERR_MASK)
#define FLEXSPI_INTR_IPRXWA_MASK (0x20U)
#define FLEXSPI_INTR_IPRXWA_SHIFT (5U)
#define FLEXSPI_INTR_IPRXWA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPRXWA_SHIFT)) & FLEXSPI_INTR_IPRXWA_MASK)
#define FLEXSPI_INTR_IPTXWE_MASK (0x40U)
#define FLEXSPI_INTR_IPTXWE_SHIFT (6U)
#define FLEXSPI_INTR_IPTXWE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPTXWE_SHIFT)) & FLEXSPI_INTR_IPTXWE_MASK)
#define FLEXSPI_INTR_DATALEARNFAIL_MASK (0x80U)
#define FLEXSPI_INTR_DATALEARNFAIL_SHIFT (7U)
#define FLEXSPI_INTR_DATALEARNFAIL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_DATALEARNFAIL_SHIFT)) & FLEXSPI_INTR_DATALEARNFAIL_MASK)
#define FLEXSPI_INTR_SCKSTOPBYRD_MASK (0x100U)
#define FLEXSPI_INTR_SCKSTOPBYRD_SHIFT (8U)
#define FLEXSPI_INTR_SCKSTOPBYRD(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SCKSTOPBYRD_SHIFT)) & FLEXSPI_INTR_SCKSTOPBYRD_MASK)
#define FLEXSPI_INTR_SCKSTOPBYWR_MASK (0x200U)
#define FLEXSPI_INTR_SCKSTOPBYWR_SHIFT (9U)
#define FLEXSPI_INTR_SCKSTOPBYWR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SCKSTOPBYWR_SHIFT)) & FLEXSPI_INTR_SCKSTOPBYWR_MASK)
#define FLEXSPI_INTR_AHBBUSTIMEOUT_MASK (0x400U)
#define FLEXSPI_INTR_AHBBUSTIMEOUT_SHIFT (10U)
#define FLEXSPI_INTR_AHBBUSTIMEOUT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBBUSTIMEOUT_SHIFT)) & FLEXSPI_INTR_AHBBUSTIMEOUT_MASK)
#define FLEXSPI_INTR_SEQTIMEOUT_MASK (0x800U)
#define FLEXSPI_INTR_SEQTIMEOUT_SHIFT (11U)
#define FLEXSPI_INTR_SEQTIMEOUT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SEQTIMEOUT_SHIFT)) & FLEXSPI_INTR_SEQTIMEOUT_MASK)
/*! @name LUTKEY - LUT Key Register */
#define FLEXSPI_LUTKEY_KEY_MASK (0xFFFFFFFFU)
#define FLEXSPI_LUTKEY_KEY_SHIFT (0U)
#define FLEXSPI_LUTKEY_KEY(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTKEY_KEY_SHIFT)) & FLEXSPI_LUTKEY_KEY_MASK)
/*! @name LUTCR - LUT Control Register */
#define FLEXSPI_LUTCR_LOCK_MASK (0x1U)
#define FLEXSPI_LUTCR_LOCK_SHIFT (0U)
#define FLEXSPI_LUTCR_LOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTCR_LOCK_SHIFT)) & FLEXSPI_LUTCR_LOCK_MASK)
#define FLEXSPI_LUTCR_UNLOCK_MASK (0x2U)
#define FLEXSPI_LUTCR_UNLOCK_SHIFT (1U)
#define FLEXSPI_LUTCR_UNLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTCR_UNLOCK_SHIFT)) & FLEXSPI_LUTCR_UNLOCK_MASK)
/*! @name AHBRXBUFCR0 - AHB RX Buffer 0 Control Register 0..AHB RX Buffer 3 Control Register 0 */
#define FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK (0xFFU)
#define FLEXSPI_AHBRXBUFCR0_BUFSZ_SHIFT (0U)
#define FLEXSPI_AHBRXBUFCR0_BUFSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_BUFSZ_SHIFT)) & FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK)
#define FLEXSPI_AHBRXBUFCR0_MSTRID_MASK (0xF0000U)
#define FLEXSPI_AHBRXBUFCR0_MSTRID_SHIFT (16U)
#define FLEXSPI_AHBRXBUFCR0_MSTRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_MSTRID_SHIFT)) & FLEXSPI_AHBRXBUFCR0_MSTRID_MASK)
#define FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK (0x3000000U)
#define FLEXSPI_AHBRXBUFCR0_PRIORITY_SHIFT (24U)
#define FLEXSPI_AHBRXBUFCR0_PRIORITY(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_PRIORITY_SHIFT)) & FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK)
/* The count of FLEXSPI_AHBRXBUFCR0 */
#define FLEXSPI_AHBRXBUFCR0_COUNT (8U)
/*! @name FLSHCR0 - Flash A1 Control Register 0..Flash B2 Control Register 0 */
#define FLEXSPI_FLSHCR0_FLSHSZ_MASK (0x7FFFFFU)
#define FLEXSPI_FLSHCR0_FLSHSZ_SHIFT (0U)
#define FLEXSPI_FLSHCR0_FLSHSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR0_FLSHSZ_SHIFT)) & FLEXSPI_FLSHCR0_FLSHSZ_MASK)
/* The count of FLEXSPI_FLSHCR0 */
#define FLEXSPI_FLSHCR0_COUNT (4U)
/*! @name FLSHCR1 - Flash A1 Control Register 1..Flash B2 Control Register 1 */
#define FLEXSPI_FLSHCR1_TCSS_MASK (0x1FU)
#define FLEXSPI_FLSHCR1_TCSS_SHIFT (0U)
#define FLEXSPI_FLSHCR1_TCSS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_TCSS_SHIFT)) & FLEXSPI_FLSHCR1_TCSS_MASK)
#define FLEXSPI_FLSHCR1_TCSH_MASK (0x3E0U)
#define FLEXSPI_FLSHCR1_TCSH_SHIFT (5U)
#define FLEXSPI_FLSHCR1_TCSH(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_TCSH_SHIFT)) & FLEXSPI_FLSHCR1_TCSH_MASK)
#define FLEXSPI_FLSHCR1_WA_MASK (0x400U)
#define FLEXSPI_FLSHCR1_WA_SHIFT (10U)
#define FLEXSPI_FLSHCR1_WA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_WA_SHIFT)) & FLEXSPI_FLSHCR1_WA_MASK)
#define FLEXSPI_FLSHCR1_CAS_MASK (0x7800U)
#define FLEXSPI_FLSHCR1_CAS_SHIFT (11U)
#define FLEXSPI_FLSHCR1_CAS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CAS_SHIFT)) & FLEXSPI_FLSHCR1_CAS_MASK)
#define FLEXSPI_FLSHCR1_CSINTERVALUNIT_MASK (0x8000U)
#define FLEXSPI_FLSHCR1_CSINTERVALUNIT_SHIFT (15U)
#define FLEXSPI_FLSHCR1_CSINTERVALUNIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CSINTERVALUNIT_SHIFT)) & FLEXSPI_FLSHCR1_CSINTERVALUNIT_MASK)
#define FLEXSPI_FLSHCR1_CSINTERVAL_MASK (0xFFFF0000U)
#define FLEXSPI_FLSHCR1_CSINTERVAL_SHIFT (16U)
#define FLEXSPI_FLSHCR1_CSINTERVAL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CSINTERVAL_SHIFT)) & FLEXSPI_FLSHCR1_CSINTERVAL_MASK)
/* The count of FLEXSPI_FLSHCR1 */
#define FLEXSPI_FLSHCR1_COUNT (4U)
/*! @name FLSHCR2 - Flash A1 Control Register 2..Flash B2 Control Register 2 */
#define FLEXSPI_FLSHCR2_ARDSEQID_MASK (0xFU)
#define FLEXSPI_FLSHCR2_ARDSEQID_SHIFT (0U)
#define FLEXSPI_FLSHCR2_ARDSEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_ARDSEQID_SHIFT)) & FLEXSPI_FLSHCR2_ARDSEQID_MASK)
#define FLEXSPI_FLSHCR2_ARDSEQNUM_MASK (0xE0U)
#define FLEXSPI_FLSHCR2_ARDSEQNUM_SHIFT (5U)
#define FLEXSPI_FLSHCR2_ARDSEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_ARDSEQNUM_SHIFT)) & FLEXSPI_FLSHCR2_ARDSEQNUM_MASK)
#define FLEXSPI_FLSHCR2_AWRSEQID_MASK (0xF00U)
#define FLEXSPI_FLSHCR2_AWRSEQID_SHIFT (8U)
#define FLEXSPI_FLSHCR2_AWRSEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRSEQID_SHIFT)) & FLEXSPI_FLSHCR2_AWRSEQID_MASK)
#define FLEXSPI_FLSHCR2_AWRSEQNUM_MASK (0xE000U)
#define FLEXSPI_FLSHCR2_AWRSEQNUM_SHIFT (13U)
#define FLEXSPI_FLSHCR2_AWRSEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRSEQNUM_SHIFT)) & FLEXSPI_FLSHCR2_AWRSEQNUM_MASK)
#define FLEXSPI_FLSHCR2_AWRWAIT_MASK (0xFFF0000U)
#define FLEXSPI_FLSHCR2_AWRWAIT_SHIFT (16U)
#define FLEXSPI_FLSHCR2_AWRWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRWAIT_SHIFT)) & FLEXSPI_FLSHCR2_AWRWAIT_MASK)
#define FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK (0x70000000U)
#define FLEXSPI_FLSHCR2_AWRWAITUNIT_SHIFT (28U)
#define FLEXSPI_FLSHCR2_AWRWAITUNIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRWAITUNIT_SHIFT)) & FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK)
#define FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK (0x80000000U)
#define FLEXSPI_FLSHCR2_CLRINSTRPTR_SHIFT (31U)
#define FLEXSPI_FLSHCR2_CLRINSTRPTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_CLRINSTRPTR_SHIFT)) & FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK)
/* The count of FLEXSPI_FLSHCR2 */
#define FLEXSPI_FLSHCR2_COUNT (4U)
/*! @name IPCR0 - IP Control Register 0 */
#define FLEXSPI_IPCR0_SFAR_MASK (0xFFFFFFFFU)
#define FLEXSPI_IPCR0_SFAR_SHIFT (0U)
#define FLEXSPI_IPCR0_SFAR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR0_SFAR_SHIFT)) & FLEXSPI_IPCR0_SFAR_MASK)
/*! @name IPCR1 - IP Control Register 1 */
#define FLEXSPI_IPCR1_IDATSZ_MASK (0xFFFFU)
#define FLEXSPI_IPCR1_IDATSZ_SHIFT (0U)
#define FLEXSPI_IPCR1_IDATSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_IDATSZ_SHIFT)) & FLEXSPI_IPCR1_IDATSZ_MASK)
#define FLEXSPI_IPCR1_ISEQID_MASK (0xF0000U)
#define FLEXSPI_IPCR1_ISEQID_SHIFT (16U)
#define FLEXSPI_IPCR1_ISEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_ISEQID_SHIFT)) & FLEXSPI_IPCR1_ISEQID_MASK)
#define FLEXSPI_IPCR1_ISEQNUM_MASK (0x7000000U)
#define FLEXSPI_IPCR1_ISEQNUM_SHIFT (24U)
#define FLEXSPI_IPCR1_ISEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_ISEQNUM_SHIFT)) & FLEXSPI_IPCR1_ISEQNUM_MASK)
#define FLEXSPI_IPCR1_IPAREN_MASK (0x80000000U)
#define FLEXSPI_IPCR1_IPAREN_SHIFT (31U)
#define FLEXSPI_IPCR1_IPAREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_IPAREN_SHIFT)) & FLEXSPI_IPCR1_IPAREN_MASK)
/*! @name IPCMD - IP Command Register */
#define FLEXSPI_IPCMD_TRG_MASK (0x1U)
#define FLEXSPI_IPCMD_TRG_SHIFT (0U)
#define FLEXSPI_IPCMD_TRG(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCMD_TRG_SHIFT)) & FLEXSPI_IPCMD_TRG_MASK)
/*! @name DLPR - Data Learn Pattern Register */
#define FLEXSPI_DLPR_DLP_MASK (0xFFFFFFFFU)
#define FLEXSPI_DLPR_DLP_SHIFT (0U)
#define FLEXSPI_DLPR_DLP(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLPR_DLP_SHIFT)) & FLEXSPI_DLPR_DLP_MASK)
/*! @name IPRXFCR - IP RX FIFO Control Register */
#define FLEXSPI_IPRXFCR_CLRIPRXF_MASK (0x1U)
#define FLEXSPI_IPRXFCR_CLRIPRXF_SHIFT (0U)
#define FLEXSPI_IPRXFCR_CLRIPRXF(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_CLRIPRXF_SHIFT)) & FLEXSPI_IPRXFCR_CLRIPRXF_MASK)
#define FLEXSPI_IPRXFCR_RXDMAEN_MASK (0x2U)
#define FLEXSPI_IPRXFCR_RXDMAEN_SHIFT (1U)
#define FLEXSPI_IPRXFCR_RXDMAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_RXDMAEN_SHIFT)) & FLEXSPI_IPRXFCR_RXDMAEN_MASK)
#define FLEXSPI_IPRXFCR_RXWMRK_MASK (0x3CU)
#define FLEXSPI_IPRXFCR_RXWMRK_SHIFT (2U)
#define FLEXSPI_IPRXFCR_RXWMRK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_RXWMRK_SHIFT)) & FLEXSPI_IPRXFCR_RXWMRK_MASK)
/*! @name IPTXFCR - IP TX FIFO Control Register */
#define FLEXSPI_IPTXFCR_CLRIPTXF_MASK (0x1U)
#define FLEXSPI_IPTXFCR_CLRIPTXF_SHIFT (0U)
#define FLEXSPI_IPTXFCR_CLRIPTXF(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_CLRIPTXF_SHIFT)) & FLEXSPI_IPTXFCR_CLRIPTXF_MASK)
#define FLEXSPI_IPTXFCR_TXDMAEN_MASK (0x2U)
#define FLEXSPI_IPTXFCR_TXDMAEN_SHIFT (1U)
#define FLEXSPI_IPTXFCR_TXDMAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_TXDMAEN_SHIFT)) & FLEXSPI_IPTXFCR_TXDMAEN_MASK)
#define FLEXSPI_IPTXFCR_TXWMRK_MASK (0x3CU)
#define FLEXSPI_IPTXFCR_TXWMRK_SHIFT (2U)
#define FLEXSPI_IPTXFCR_TXWMRK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_TXWMRK_SHIFT)) & FLEXSPI_IPTXFCR_TXWMRK_MASK)
/*! @name DLLCR - DLL Control Register 0 */
#define FLEXSPI_DLLCR_DLLEN_MASK (0x1U)
#define FLEXSPI_DLLCR_DLLEN_SHIFT (0U)
#define FLEXSPI_DLLCR_DLLEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_DLLEN_SHIFT)) & FLEXSPI_DLLCR_DLLEN_MASK)
#define FLEXSPI_DLLCR_DLLRESET_MASK (0x2U)
#define FLEXSPI_DLLCR_DLLRESET_SHIFT (1U)
#define FLEXSPI_DLLCR_DLLRESET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_DLLRESET_SHIFT)) & FLEXSPI_DLLCR_DLLRESET_MASK)
#define FLEXSPI_DLLCR_SLVDLYTARGET_MASK (0x78U)
#define FLEXSPI_DLLCR_SLVDLYTARGET_SHIFT (3U)
#define FLEXSPI_DLLCR_SLVDLYTARGET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_SLVDLYTARGET_SHIFT)) & FLEXSPI_DLLCR_SLVDLYTARGET_MASK)
#define FLEXSPI_DLLCR_OVRDEN_MASK (0x100U)
#define FLEXSPI_DLLCR_OVRDEN_SHIFT (8U)
#define FLEXSPI_DLLCR_OVRDEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_OVRDEN_SHIFT)) & FLEXSPI_DLLCR_OVRDEN_MASK)
#define FLEXSPI_DLLCR_OVRDVAL_MASK (0x7E00U)
#define FLEXSPI_DLLCR_OVRDVAL_SHIFT (9U)
#define FLEXSPI_DLLCR_OVRDVAL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_OVRDVAL_SHIFT)) & FLEXSPI_DLLCR_OVRDVAL_MASK)
/* The count of FLEXSPI_DLLCR */
#define FLEXSPI_DLLCR_COUNT (2U)
/*! @name STS0 - Status Register 0 */
#define FLEXSPI_STS0_SEQIDLE_MASK (0x1U)
#define FLEXSPI_STS0_SEQIDLE_SHIFT (0U)
#define FLEXSPI_STS0_SEQIDLE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_SEQIDLE_SHIFT)) & FLEXSPI_STS0_SEQIDLE_MASK)
#define FLEXSPI_STS0_ARBIDLE_MASK (0x2U)
#define FLEXSPI_STS0_ARBIDLE_SHIFT (1U)
#define FLEXSPI_STS0_ARBIDLE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_ARBIDLE_SHIFT)) & FLEXSPI_STS0_ARBIDLE_MASK)
#define FLEXSPI_STS0_ARBCMDSRC_MASK (0xCU)
#define FLEXSPI_STS0_ARBCMDSRC_SHIFT (2U)
#define FLEXSPI_STS0_ARBCMDSRC(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_ARBCMDSRC_SHIFT)) & FLEXSPI_STS0_ARBCMDSRC_MASK)
#define FLEXSPI_STS0_DATALEARNPHASEA_MASK (0xF0U)
#define FLEXSPI_STS0_DATALEARNPHASEA_SHIFT (4U)
#define FLEXSPI_STS0_DATALEARNPHASEA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_DATALEARNPHASEA_SHIFT)) & FLEXSPI_STS0_DATALEARNPHASEA_MASK)
#define FLEXSPI_STS0_DATALEARNPHASEB_MASK (0xF00U)
#define FLEXSPI_STS0_DATALEARNPHASEB_SHIFT (8U)
#define FLEXSPI_STS0_DATALEARNPHASEB(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_DATALEARNPHASEB_SHIFT)) & FLEXSPI_STS0_DATALEARNPHASEB_MASK)
/*! @name STS1 - Status Register 1 */
#define FLEXSPI_STS1_AHBCMDERRID_MASK (0xFU)
#define FLEXSPI_STS1_AHBCMDERRID_SHIFT (0U)
#define FLEXSPI_STS1_AHBCMDERRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_AHBCMDERRID_SHIFT)) & FLEXSPI_STS1_AHBCMDERRID_MASK)
#define FLEXSPI_STS1_AHBCMDERRCODE_MASK (0xF00U)
#define FLEXSPI_STS1_AHBCMDERRCODE_SHIFT (8U)
#define FLEXSPI_STS1_AHBCMDERRCODE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_AHBCMDERRCODE_SHIFT)) & FLEXSPI_STS1_AHBCMDERRCODE_MASK)
#define FLEXSPI_STS1_IPCMDERRID_MASK (0xF0000U)
#define FLEXSPI_STS1_IPCMDERRID_SHIFT (16U)
#define FLEXSPI_STS1_IPCMDERRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_IPCMDERRID_SHIFT)) & FLEXSPI_STS1_IPCMDERRID_MASK)
#define FLEXSPI_STS1_IPCMDERRCODE_MASK (0xF000000U)
#define FLEXSPI_STS1_IPCMDERRCODE_SHIFT (24U)
#define FLEXSPI_STS1_IPCMDERRCODE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_IPCMDERRCODE_SHIFT)) & FLEXSPI_STS1_IPCMDERRCODE_MASK)
/*! @name STS2 - Status Register 2 */
#define FLEXSPI_STS2_ASLVLOCK_MASK (0x1U)
#define FLEXSPI_STS2_ASLVLOCK_SHIFT (0U)
#define FLEXSPI_STS2_ASLVLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_ASLVLOCK_SHIFT)) & FLEXSPI_STS2_ASLVLOCK_MASK)
#define FLEXSPI_STS2_AREFLOCK_MASK (0x2U)
#define FLEXSPI_STS2_AREFLOCK_SHIFT (1U)
#define FLEXSPI_STS2_AREFLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_AREFLOCK_SHIFT)) & FLEXSPI_STS2_AREFLOCK_MASK)
#define FLEXSPI_STS2_ASLVSEL_MASK (0xFCU)
#define FLEXSPI_STS2_ASLVSEL_SHIFT (2U)
#define FLEXSPI_STS2_ASLVSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_ASLVSEL_SHIFT)) & FLEXSPI_STS2_ASLVSEL_MASK)
#define FLEXSPI_STS2_AREFSEL_MASK (0x3F00U)
#define FLEXSPI_STS2_AREFSEL_SHIFT (8U)
#define FLEXSPI_STS2_AREFSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_AREFSEL_SHIFT)) & FLEXSPI_STS2_AREFSEL_MASK)
#define FLEXSPI_STS2_BSLVLOCK_MASK (0x10000U)
#define FLEXSPI_STS2_BSLVLOCK_SHIFT (16U)
#define FLEXSPI_STS2_BSLVLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BSLVLOCK_SHIFT)) & FLEXSPI_STS2_BSLVLOCK_MASK)
#define FLEXSPI_STS2_BREFLOCK_MASK (0x20000U)
#define FLEXSPI_STS2_BREFLOCK_SHIFT (17U)
#define FLEXSPI_STS2_BREFLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BREFLOCK_SHIFT)) & FLEXSPI_STS2_BREFLOCK_MASK)
#define FLEXSPI_STS2_BSLVSEL_MASK (0xFC0000U)
#define FLEXSPI_STS2_BSLVSEL_SHIFT (18U)
#define FLEXSPI_STS2_BSLVSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BSLVSEL_SHIFT)) & FLEXSPI_STS2_BSLVSEL_MASK)
#define FLEXSPI_STS2_BREFSEL_MASK (0x3F000000U)
#define FLEXSPI_STS2_BREFSEL_SHIFT (24U)
#define FLEXSPI_STS2_BREFSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BREFSEL_SHIFT)) & FLEXSPI_STS2_BREFSEL_MASK)
/*! @name AHBSPNDSTS - AHB Suspend Status Register */
#define FLEXSPI_AHBSPNDSTS_ACTIVE_MASK (0x1U)
#define FLEXSPI_AHBSPNDSTS_ACTIVE_SHIFT (0U)
#define FLEXSPI_AHBSPNDSTS_ACTIVE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_ACTIVE_SHIFT)) & FLEXSPI_AHBSPNDSTS_ACTIVE_MASK)
#define FLEXSPI_AHBSPNDSTS_BUFID_MASK (0xEU)
#define FLEXSPI_AHBSPNDSTS_BUFID_SHIFT (1U)
#define FLEXSPI_AHBSPNDSTS_BUFID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_BUFID_SHIFT)) & FLEXSPI_AHBSPNDSTS_BUFID_MASK)
#define FLEXSPI_AHBSPNDSTS_DATLFT_MASK (0xFFFF0000U)
#define FLEXSPI_AHBSPNDSTS_DATLFT_SHIFT (16U)
#define FLEXSPI_AHBSPNDSTS_DATLFT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_DATLFT_SHIFT)) & FLEXSPI_AHBSPNDSTS_DATLFT_MASK)
/*! @name IPRXFSTS - IP RX FIFO Status Register */
#define FLEXSPI_IPRXFSTS_FILL_MASK (0xFFU)
#define FLEXSPI_IPRXFSTS_FILL_SHIFT (0U)
#define FLEXSPI_IPRXFSTS_FILL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFSTS_FILL_SHIFT)) & FLEXSPI_IPRXFSTS_FILL_MASK)
#define FLEXSPI_IPRXFSTS_RDCNTR_MASK (0xFFFF0000U)
#define FLEXSPI_IPRXFSTS_RDCNTR_SHIFT (16U)
#define FLEXSPI_IPRXFSTS_RDCNTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFSTS_RDCNTR_SHIFT)) & FLEXSPI_IPRXFSTS_RDCNTR_MASK)
/*! @name IPTXFSTS - IP TX FIFO Status Register */
#define FLEXSPI_IPTXFSTS_FILL_MASK (0xFFU)
#define FLEXSPI_IPTXFSTS_FILL_SHIFT (0U)
#define FLEXSPI_IPTXFSTS_FILL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFSTS_FILL_SHIFT)) & FLEXSPI_IPTXFSTS_FILL_MASK)
#define FLEXSPI_IPTXFSTS_WRCNTR_MASK (0xFFFF0000U)
#define FLEXSPI_IPTXFSTS_WRCNTR_SHIFT (16U)
#define FLEXSPI_IPTXFSTS_WRCNTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFSTS_WRCNTR_SHIFT)) & FLEXSPI_IPTXFSTS_WRCNTR_MASK)
/*! @name RFDR - IP RX FIFO Data Register 0..IP RX FIFO Data Register 31 */
#define FLEXSPI_RFDR_RXDATA_MASK (0xFFFFFFFFU)
#define FLEXSPI_RFDR_RXDATA_SHIFT (0U)
#define FLEXSPI_RFDR_RXDATA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_RFDR_RXDATA_SHIFT)) & FLEXSPI_RFDR_RXDATA_MASK)
/* The count of FLEXSPI_RFDR */
#define FLEXSPI_RFDR_COUNT (32U)
/*! @name TFDR - IP TX FIFO Data Register 0..IP TX FIFO Data Register 31 */
#define FLEXSPI_TFDR_TXDATA_MASK (0xFFFFFFFFU)
#define FLEXSPI_TFDR_TXDATA_SHIFT (0U)
#define FLEXSPI_TFDR_TXDATA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_TFDR_TXDATA_SHIFT)) & FLEXSPI_TFDR_TXDATA_MASK)
/* The count of FLEXSPI_TFDR */
#define FLEXSPI_TFDR_COUNT (32U)
/*! @name LUT - LUT 0..LUT 63 */
#define FLEXSPI_LUT_OPERAND0_MASK (0xFFU)
#define FLEXSPI_LUT_OPERAND0_SHIFT (0U)
#define FLEXSPI_LUT_OPERAND0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPERAND0_SHIFT)) & FLEXSPI_LUT_OPERAND0_MASK)
#define FLEXSPI_LUT_NUM_PADS0_MASK (0x300U)
#define FLEXSPI_LUT_NUM_PADS0_SHIFT (8U)
#define FLEXSPI_LUT_NUM_PADS0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS0_SHIFT)) & FLEXSPI_LUT_NUM_PADS0_MASK)
#define FLEXSPI_LUT_OPCODE0_MASK (0xFC00U)
#define FLEXSPI_LUT_OPCODE0_SHIFT (10U)
#define FLEXSPI_LUT_OPCODE0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPCODE0_SHIFT)) & FLEXSPI_LUT_OPCODE0_MASK)
#define FLEXSPI_LUT_OPERAND1_MASK (0xFF0000U)
#define FLEXSPI_LUT_OPERAND1_SHIFT (16U)
#define FLEXSPI_LUT_OPERAND1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPERAND1_SHIFT)) & FLEXSPI_LUT_OPERAND1_MASK)
#define FLEXSPI_LUT_NUM_PADS1_MASK (0x3000000U)
#define FLEXSPI_LUT_NUM_PADS1_SHIFT (24U)
#define FLEXSPI_LUT_NUM_PADS1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS1_SHIFT)) & FLEXSPI_LUT_NUM_PADS1_MASK)
#define FLEXSPI_LUT_OPCODE1_MASK (0xFC000000U)
#define FLEXSPI_LUT_OPCODE1_SHIFT (26U)
#define FLEXSPI_LUT_OPCODE1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPCODE1_SHIFT)) & FLEXSPI_LUT_OPCODE1_MASK)
/* The count of FLEXSPI_LUT */
#define FLEXSPI_LUT_COUNT (64U)
#define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0ul)
#define CMD_INDEX_READ 0
#define CMD_INDEX_READSTATUS 1
#define CMD_INDEX_WRITEENABLE 2
#define CMD_INDEX_WRITE 4
#define CMD_LUT_SEQ_IDX_READ 0
#define CMD_LUT_SEQ_IDX_READSTATUS 1
#define CMD_LUT_SEQ_IDX_WRITEENABLE 3
#define CMD_LUT_SEQ_IDX_WRITE 9
#define NOR_CMD_LUT_SEQ_IDX_READ CMD_LUT_SEQ_IDX_READ
#define NOR_CMD_LUT_SEQ_IDX_READSTATUS CMD_LUT_SEQ_IDX_READSTATUS
#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI 2
#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE CMD_LUT_SEQ_IDX_WRITEENABLE
#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_XPI 4
#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5
#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 8
#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM CMD_LUT_SEQ_IDX_WRITE
#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11
#define NOR_CMD_LUT_SEQ_IDX_READ_ID 12
#define NOR_CMD_LUT_SEQ_IDX_READ_SFDP 13
#define NOR_CMD_LUT_SEQ_IDX_RESTORE_NOCMD 14
#define NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD 15
#define CMD_SDR 0x01
#define CMD_DDR 0x21
#define RADDR_SDR 0x02
#define RADDR_DDR 0x22
#define CADDR_SDR 0x03
#define CADDR_DDR 0x23
#define MODE1_SDR 0x04
#define MODE1_DDR 0x24
#define MODE2_SDR 0x05
#define MODE2_DDR 0x25
#define MODE4_SDR 0x06
#define MODE4_DDR 0x26
#define MODE8_SDR 0x07
#define MODE8_DDR 0x27
#define WRITE_SDR 0x08
#define WRITE_DDR 0x28
#define READ_SDR 0x09
#define READ_DDR 0x29
#define LEARN_SDR 0x0A
#define LEARN_DDR 0x2A
#define DATSZ_SDR 0x0B
#define DATSZ_DDR 0x2B
#define DUMMY_SDR 0x0C
#define DUMMY_DDR 0x2C
#define DUMMY_RWDS_SDR 0x0D
#define DUMMY_RWDS_DDR 0x2D
#define JMP_ON_CS 0x1F
#define STOP 0
#define FLEXSPI_1PAD 0
#define FLEXSPI_2PAD 1
#define FLEXSPI_4PAD 2
#define FLEXSPI_8PAD 3
typedef enum {
FLEXSPI_CMD_WRITE,
FLEXSPI_CMD_READ,
FLEXSPI_CMD_OPER,
} flexspi_ip_cmd_op_e;
typedef struct flexspi_ip_cmd_tag{
uint8_t *dst;
uint8_t *src;
uint32_t size;
flexspi_ip_cmd_op_e op;
uint8_t seq_id;
uint8_t seq_size;
uint8_t is_parallel;
} flexspi_ip_cmd_t;
typedef struct flexspi_instance_tag {
flexspi_t *flexspi_reg;
uint32_t instance;
} flexspi_instance_t;
extern uint32_t imx_flexspi_ip_command(flexspi_t *flexspi_reg, flexspi_ip_cmd_t *flexspi_ip_cmd_p);
extern uint32_t imx_flexspi_init(flexspi_instance_t *flexspi_instance);
extern void imx_flexspi_update_lut(flexspi_t *flexspi_reg, uint32_t seq_idx, uint32_t seq[]);
extern void imx_flexspi_swreset(flexspi_t *flexspi_reg);
extern flexspi_instance_t g_flexspi_instance_arr[2];
/* System level port interface */
extern void imx_flexspi_clock_gate_disable(uint32_t instance);
extern void imx_flexspi_clock_config(uint32_t instance);
extern void imx_flexspi_clock_gate_enable(uint32_t instance);
extern void imx_flexspi_iomux_config(uint32_t instance);
#endif /* IMX_FLEXSPI_H */
- flexspi_t定義了FlexSPI 的寄存器映射,寄存器的定義可以去看上面發的i.MX RT1020參考手冊。
- 以及下面一堆宏定義都是定義了寄存器的一些操作,也需要根據手冊來看具體的實現。
- flexspi_ip_cmd_op_e定義了命令的類型,讀命令(如讀數據, 讀寄存器),寫命令(如寫數據,寫寄存器),操作命令(如擦除, 寫使能)。
- flexspi_ip_cmd_t用來操作FlexSPI的IP命令控制,這個具體實現再後面的imx_flexspi.c中看到。
- flexspi_instance_t定義了具體使用哪個FlexSPI控制器。一個SOC上可能有多個FlexSPI控制器,這個結構就可以區分使用哪個控制器。
- 接下來就是定義了一些imx_flexspi.c對外暴露的接口,其實用到的就三個,一個是初始化,一個是發送命令的接口,還有一個就是更新LUT Table的接口。
imx_flexspi.c
這個文件封裝了對FlexSPI底層的寄存器操作,其中的函數需要對照着RM來一步一步看。
uint32_t imx_flexspi_init(flexspi_instance_t *flexspi_instance)
FlexSPI的初始化函數,其步驟就是根據1.3.4 初始化來寫的。
- 首先是imx_flexspi_clock_gate_disable,imx_flexspi_clock_config, imx_flexspi_clock_gate_enable,imx_flexspi_iomux_config來初始化時鐘和I/O。
- imx_flexspi_config_ahb配置AHB相關的寄存器。
- imx_flexspi_config_flash_controller配置Flash相關的寄存器。
- imx_flexspi_init_lut配置默認的LUT Table。
- imx_flexspi_swreset軟件復位FlexSPI。
uint32_t imx_flexspi_init(flexspi_instance_t *flexspi_instance)
{
uint32_t mcr0 = 0;
flexspi_t *flexspi_reg = flexspi_instance->flexspi_reg;
uint32_t instance = flexspi_instance->instance;
/* Enable controller clocks in System level.*/
imx_flexspi_clock_gate_disable(instance);
imx_flexspi_clock_config(instance);
imx_flexspi_clock_gate_enable(instance);
imx_flexspi_iomux_config(instance);
/* Set MCR0[MDIS] to 0x1(Make sure controller is configured in module stop mode)*/
flexspi_reg->mcr0 &= ~FLEXSPI_MCR0_MDIS_MASK;
imx_flexspi_swreset(flexspi_reg);
flexspi_reg->mcr0 |= FLEXSPI_MCR0_MDIS_MASK;
/* Configure module control registers: MCR0, MCR1, MCR2
* Don't change MCR0[MDIS]
* */
mcr0 = flexspi_reg->mcr0 & (uint32_t) ~(FLEXSPI_MCR0_RXCLKSRC_MASK
| FLEXSPI_MCR0_IPGRANTWAIT_MASK | FLEXSPI_MCR0_AHBGRANTWAIT_MASK
| FLEXSPI_MCR0_COMBINATIONEN_MASK | FLEXSPI_MCR0_ATDFEN_MASK | FLEXSPI_MCR0_ARDFEN_MASK);
mcr0 |= FLEXSPI_MCR0_IPGRANTWAIT_MASK;
mcr0 |= FLEXSPI_MCR0_AHBGRANTWAIT_MASK;
mcr0 |= FLEXSPI_MCR0_RXCLKSRC(0);
flexspi_reg->mcr0 = mcr0;
flexspi_reg->mcr1 = FLEXSPI_MCR1_SEQWAIT(0xFFFF) | FLEXSPI_MCR1_AHBBUSWAIT(0xFFFF);
flexspi_reg->mcr2 &= ~FLEXSPI_MCR2_SAMEDEVICEEN_MASK;
/* Configure AHB bus control register and AHB RX Buffer control registers */
imx_flexspi_config_ahb(flexspi_reg);
/* Configure Flash control registers(FLSHxCR0, FLASHxCR1, FLASHxCR2) */
imx_flexspi_config_flash_controller(flexspi_reg);
/* Configure DLL control regiseter(DLLxCR) according to sample clock source */
flexspi_reg->dllcr[0] = 0x100UL;
/* Set MCR0[MDIS] to 0x0(Exit module stop mode) */
flexspi_reg->mcr0 &= ~FLEXSPI_MCR0_MDIS_MASK;
/* Configure LUT as needed(For AHB command or IP command) */
imx_flexspi_init_lut(flexspi_reg);
imx_flexspi_swreset(flexspi_reg);
return 0;
}
static void imx_flexspi_config_ahb(flexspi_t *flexspi_reg)
static void imx_flexspi_config_ahb(flexspi_t *flexspi_reg)
{
uint32_t temp;
uint32_t i;
temp = flexspi_reg->ahbcr & (~FLEXSPI_AHBCR_APAREN_MASK);
temp |= FLEXSPI_AHBCR_READADDROPT_MASK;
flexspi_reg->ahbcr = temp;
flexspi_reg->ahbcr |= FLEXSPI_AHBCR_PREFETCHEN_MASK;
for (i = 0; i < FLEXSPI_AHBRXBUFCR0_COUNT - 1; i++) {
flexspi_reg->ahbrxbufcr0[i] &=
~(FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK | FLEXSPI_AHBRXBUFCR0_MSTRID_MASK |
FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK);
}
}
要理解這個函數,需要看下AHBCR和AHBRXBUFCRx的寄存器定義。
主要是設置APAREN和PREFETCHEN這兩位,讓FlexSPI工作在Indiviadual模式下,並且使能讀預取。
緊接着就是設置AHBRXBUFCRx寄存器。在FlexSPI上一共有8個AHBRXBUF。AHB Rx Buffer總共的大小一共2KB。每一個buffer的大小就是通過AHBRXBUFCRx控制的。如果buffer0-buffer6的BUFSZ都設爲0,那麼默認所有的AHB Master都會使用buffer7。在這裏我們就是這樣設置了,將buffer0-buffer6都設置爲0。所以buffer7獨佔了2KB的大小。
imx_flexspi_config_flash_controller
static void imx_flexspi_config_flash_controller(flexspi_t *flexspi_reg)
{
uint32_t temp = 0;
flexspi_reg->flashcr0[0] = 64 * 1024;
temp = FLEXSPI_FLSHCR1_TCSS(0x3) | FLEXSPI_FLSHCR1_TCSH(0x3) |
FLEXSPI_FLSHCR1_CAS(0);
flexspi_reg->flashcr1[0] = temp;
}
這個函數主要是配置FLSHCR0, FLSHCR1, FLSHCR2這三個寄存器。
FLSHCR0的定義如下圖,主要定義了Flash的大小。本文用的Flash是MT25X 64MB的型號,因此這裏就把該寄存器設置爲64 * 1024 KB。
FLASHCR1
這個寄存器主要設置TCSH和TCSS兩位.。Column Address Size這個bit主要是用於HyperFlash的,對於MT25的QSPI,這裏設置爲0。
FLASHCR2主要配置AHB讀和寫的LUT sequence。由於這裏默認的寄存器是0,而我們要設置的讀序列恰好是第0條,所以這裏就不設置了。
imx_flexspi_init_lut
static void imx_flexspi_init_lut(flexspi_t *flexspi_reg)
{
imx_flexspi_wait_until_ip_idle(flexspi_reg);
imx_flexspi_unlock_lut(flexspi_reg);
flexspi_reg->lut[0] = 0x08180403;
flexspi_reg->lut[1] = 0x2480;
flexspi_reg->lut[2] = 0x0;
flexspi_reg->lut[3] = 0x0;
flexspi_reg->lut[4] = 0x24040405;
flexspi_reg->lut[5] = 0x0;
flexspi_reg->lut[6] = 0x0;
flexspi_reg->lut[7] = 0x0;
flexspi_reg->lut[8] = 0x0;
flexspi_reg->lut[9] = 0x0;
flexspi_reg->lut[10] = 0x0;
flexspi_reg->lut[11] = 0x0;
flexspi_reg->lut[12] = 0x0406;
flexspi_reg->lut[13] = 0x0;
flexspi_reg->lut[14] = 0x0;
flexspi_reg->lut[15] = 0x0;
flexspi_reg->lut[16] = 0x20020401;
flexspi_reg->lut[17] = 0x0;
flexspi_reg->lut[18] = 0x0;
flexspi_reg->lut[19] = 0x0;
flexspi_reg->lut[20] = 0x082004dc;
flexspi_reg->lut[21] = 0x0;
flexspi_reg->lut[22] = 0x0;
flexspi_reg->lut[23] = 0x0;
flexspi_reg->lut[24] = 0x04c7;
flexspi_reg->lut[25] = 0x0;
flexspi_reg->lut[26] = 0x0;
flexspi_reg->lut[27] = 0x0;
flexspi_reg->lut[28] = 0x0;
flexspi_reg->lut[29] = 0x0;
flexspi_reg->lut[30] = 0x0;
flexspi_reg->lut[31] = 0x0;
flexspi_reg->lut[32] = 0x0;
flexspi_reg->lut[33] = 0x0;
flexspi_reg->lut[34] = 0x0;
flexspi_reg->lut[35] = 0x0;
flexspi_reg->lut[36] = 0x08200412;
flexspi_reg->lut[37] = 0x2080;
flexspi_reg->lut[38] = 0x0;
flexspi_reg->lut[39] = 0x0;
flexspi_reg->lut[40] = 0x0;
flexspi_reg->lut[41] = 0x0;
flexspi_reg->lut[42] = 0x0;
flexspi_reg->lut[43] = 0x0;
flexspi_reg->lut[44] = 0x0460;
flexspi_reg->lut[45] = 0x0;
flexspi_reg->lut[46] = 0x0;
flexspi_reg->lut[47] = 0x0;
flexspi_reg->lut[48] = 0x0;
flexspi_reg->lut[49] = 0x0;
flexspi_reg->lut[50] = 0x0;
flexspi_reg->lut[51] = 0x0;
flexspi_reg->lut[52] = 0x0;
flexspi_reg->lut[53] = 0x0;
flexspi_reg->lut[54] = 0x0;
flexspi_reg->lut[55] = 0x0;
flexspi_reg->lut[56] = 0x0;
flexspi_reg->lut[57] = 0x0;
flexspi_reg->lut[58] = 0x0;
flexspi_reg->lut[59] = 0x0;
flexspi_reg->lut[60] = 0x0;
flexspi_reg->lut[61] = 0x0;
flexspi_reg->lut[62] = 0x0;
flexspi_reg->lut[63] = 0x0;
imx_flexspi_lock_lut(flexspi_reg);
}
這個函數用來初始化LUT Table, 這裏默認放了一些LUT Sequence。第一條是讀命令,第二條讀status寄存器,第四條是寫使能等等。在寫LUT Sequence之前必須unlock LUT Table,寫完之後需要lock LUT Table。
.
imx_flexspi_swreset
最後就是軟件復位一把,就是往MCR0的SWRESET位寫1即可。復位完成後硬件會自動把這位清零。
void imx_flexspi_swreset(flexspi_t *flexspi_reg)
{
flexspi_reg->mcr0 |= FLEXSPI_MCR0_SWRESET_MASK;
while (flexspi_reg->mcr0 & FLEXSPI_MCR0_SWRESET_MASK);
}
imx_flexspi_ip_command
這個函數根據命令類型進行分發。讀操作分發到do_flexspi_ip_cmd_read,寫操作分發到do_flexspi_ip_cmd_write,操作類命令分發給do_flexspi_ip_cmd_op。
uint32_t imx_flexspi_ip_command(flexspi_t *flexspi_reg, flexspi_ip_cmd_t *flexspi_ip_cmd_p)
{
imx_flexspi_clear_ip_rxfifo(flexspi_reg);
imx_flexspi_clear_ip_txfifo(flexspi_reg);
switch (flexspi_ip_cmd_p->op) {
case FLEXSPI_CMD_READ:
do_flexspi_ip_cmd_read(flexspi_ip_cmd_p);
break;
case FLEXSPI_CMD_WRITE:
do_flexspi_ip_cmd_write(flexspi_ip_cmd_p);
break;
case FLEXSPI_CMD_OPER:
do_flexspi_ip_cmd_op(flexspi_ip_cmd_p);
default:
break;
}
imx_flexspi_wait_until_ip_idle(flexspi_reg);
if (flexspi_reg->intr & FLEXSPI_INTR_IPCMDERR_MASK) {
switch ((flexspi_reg->sts1 & FLEXSPI_STS1_IPCMDERRCODE_MASK)
>> FLEXSPI_STS1_IPCMDERRCODE_SHIFT) {
default:
return 1;
case 7 :
return 2;
}
}
return 0;
}
static void do_flexspi_ip_cmd_write(flexspi_ip_cmd_t *flexspi_ip_cmd_p)
{
uint32_t i = 0;
uint32_t remain_size = flexspi_ip_cmd_p->size;
uint32_t *buf_ptr = (uint32_t *)flexspi_ip_cmd_p->src;
uint32_t temp = 0;
flexspi_t *flexspi_reg = (flexspi_t *)FLEXSPI_BASE;
flexspi_reg->ipcr0 = (uint32_t)flexspi_ip_cmd_p->dst;
temp |= FLEXSPI_IPCR1_IDATSZ(flexspi_ip_cmd_p->size);
temp |= FLEXSPI_IPCR1_ISEQID(flexspi_ip_cmd_p->seq_id)
| FLEXSPI_IPCR1_ISEQNUM(flexspi_ip_cmd_p->seq_size - 1)
| FLEXSPI_IPCR1_IPAREN(flexspi_ip_cmd_p->is_parallel);
flexspi_reg->ipcr1 = temp;
flexspi_reg->ipcmd |= FLEXSPI_IPCMD_TRG_MASK;
while (remain_size > 0) {
if (flexspi_reg->intr & FLEXSPI_INTR_IPTXWE_MASK) {
if (remain_size >= 8) {
flexspi_reg->tfdr[0] = *buf_ptr++;
flexspi_reg->tfdr[1] = *buf_ptr++;
remain_size -= 8;
} else {
}
flexspi_reg->intr |= FLEXSPI_INTR_IPTXWE_MASK;
}
if ((flexspi_reg->intr & FLEXSPI_INTR_IPCMDERR_MASK) != 0U) {
break;
}
}
}
static void do_flexspi_ip_cmd_op(flexspi_ip_cmd_t *flexspi_ip_cmd_p)
{
flexspi_t *flexspi_reg = (flexspi_t *)FLEXSPI_BASE;
uint32_t temp = 0;
flexspi_reg->ipcr0 = (uint32_t)flexspi_ip_cmd_p->dst;
temp |= FLEXSPI_IPCR1_IDATSZ(flexspi_ip_cmd_p->size);
temp |= FLEXSPI_IPCR1_ISEQID(flexspi_ip_cmd_p->seq_id)
| FLEXSPI_IPCR1_ISEQNUM(flexspi_ip_cmd_p->seq_size - 1) |
FLEXSPI_IPCR1_IPAREN(flexspi_ip_cmd_p->is_parallel);
flexspi_reg->ipcr1 = temp;
flexspi_reg->ipcmd |= FLEXSPI_IPCMD_TRG_MASK;
}
static void do_flexspi_ip_cmd_read(flexspi_ip_cmd_t *flexspi_ip_cmd_p)
{
uint32_t i = 0;
uint32_t remain_size = flexspi_ip_cmd_p->size;
uint32_t *buf_ptr = (uint32_t *)flexspi_ip_cmd_p->dst;
uint32_t temp = 0;
uint32_t buffer[2] = {0};
uint8_t *src;
uint8_t *dst;
flexspi_t *flexspi_reg = (flexspi_t *)FLEXSPI_BASE;
flexspi_reg->ipcr0 = (uint32_t)flexspi_ip_cmd_p->src;
temp |= FLEXSPI_IPCR1_IDATSZ(flexspi_ip_cmd_p->size);
temp |= FLEXSPI_IPCR1_ISEQID(flexspi_ip_cmd_p->seq_id)
| FLEXSPI_IPCR1_ISEQNUM(flexspi_ip_cmd_p->seq_size - 1)
| FLEXSPI_IPCR1_IPAREN(flexspi_ip_cmd_p->is_parallel);
flexspi_reg->ipcr1 = temp;
flexspi_reg->ipcmd |= FLEXSPI_IPCMD_TRG_MASK;
while (remain_size > 0) {
if (remain_size >= 8) {
// Make sure the RX FIFO contains valid data before read
if (flexspi_reg->intr & FLEXSPI_INTR_IPRXWA_MASK) {
*buf_ptr++ = flexspi_reg->rfdr[0];
*buf_ptr++ = flexspi_reg->rfdr[1];
remain_size -= 8;
flexspi_reg->intr |= FLEXSPI_INTR_IPRXWA_MASK;
}
} else {
if (flexspi_reg->iprxsts & FLEXSPI_IPRXFSTS_FILL_MASK) {
buffer[0] = flexspi_reg->rfdr[0];
buffer[1] = flexspi_reg->rfdr[1];
src = (uint8_t *)buffer;
dst = (uint8_t *)buf_ptr;
for (i = 0; i < remain_size; i++) {
*dst++ = *src++;
}
remain_size = 0;
flexspi_reg->intr |= FLEXSPI_INTR_IPRXWA_MASK;
}
}
if ((flexspi_reg->intr & FLEXSPI_INTR_IPCMDERR_MASK) != 0U) {
break;
}
}
}
imx_flexspi_nor.c
init_spi_nor
該函數用於初始化spi_nor_t結構體,主要就是將各個操作的函數指針賦值給spi_nor_t裏的成員。並且調用初始化函數初始化FlexSPI控制器。
uint32_t init_spi_nor(spi_nor_t *spi_nor, uint32_t instance)
{
flexspi_t *flexspi_reg;
flexspi_instance_t *flexspi_instance;
spi_nor->read = flexspi_nor_read_by_ip;
spi_nor->write = flexspi_nor_program_by_ip;
spi_nor->write_enable = flexspi_nor_write_enable;
spi_nor->erase_bulk = flexspi_nor_erase_bulk;
spi_nor->erase_sector = flexspi_nor_erase_sector;
spi_nor->read_id = flexspi_nor_read_id;
spi_nor->read_sfdp = 0;
spi_nor->host = (void *)&g_flexspi_instance_arr[instance];
flexspi_instance = (flexspi_instance_t *)spi_nor->host;
flexspi_reg = flexspi_instance->flexspi_reg;
imx_flexspi_init(flexspi_instance);
mt25x_cmd_set(spi_nor);
return 0;
}
mt25x_cmd_set
這個函數主要根據MT25的參考手冊把相應的命令填到spi_nor的cmd_set成員中。
static void mt25x_cmd_set(spi_nor_t *spi_nor)
{
spi_nor->cmd_set.reset_enable = 0x66;
spi_nor->cmd_set.reset_memory = 0x99;
spi_nor->cmd_set.read_id = 0x9E;
spi_nor->cmd_set.read_sfdp = 0x5A;
spi_nor->cmd_set.read = 0x03;
spi_nor->cmd_set.read_dummy_cycles = 0x0;
spi_nor->cmd_set.read_cmd_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.read_addr_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.read_data_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.write_enable = 0x06;
spi_nor->cmd_set.write_disable = 0x04;
spi_nor->cmd_set.read_status_reg = 0x05;
spi_nor->cmd_set.read_flag_status_reg = 0x70;
spi_nor->cmd_set.read_nvconfig_reg = 0xB5;
spi_nor->cmd_set.read_vconfig_reg = 0x85;
spi_nor->cmd_set.read_evconfig_reg = 0x65;
spi_nor->cmd_set.read_eadd_reg = 0xc8;
spi_nor->cmd_set.read_gp_read_reg = 0x96;
spi_nor->cmd_set.program = 0x12;
spi_nor->cmd_set.program_dummy_cycles = 0x0;
spi_nor->cmd_set.program_cmd_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.program_addr_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.program_data_mode = FLEXSPI_1PAD;
spi_nor->cmd_set.write_status_reg = 0x01;
spi_nor->cmd_set.write_nvconfig_reg = 0xB1;
spi_nor->cmd_set.write_vconfig_reg = 0x81;
spi_nor->cmd_set.write_evconfig_reg = 0x61;
spi_nor->cmd_set.write_eaddr_reg = 0xC5;
spi_nor->cmd_set.clear_flag_status_reg = 0x50;
spi_nor->cmd_set.erase_bulk = 0xC7;
spi_nor->cmd_set.erase_32KB_subsector = 0x52;
spi_nor->cmd_set.erase_4KB_subsector = 0x20;
spi_nor->cmd_set.erase_sector = 0xD8;
uint32_t seq[4] = {0};
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
seq[0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, spi_nor->cmd_set.read_id,
READ_SDR, FLEXSPI_1PAD, 0x04);
imx_flexspi_update_lut(flexspi_reg, NOR_CMD_LUT_SEQ_IDX_READ_ID, seq);
}
flexspi_nor_read_status_reg
static uint32_t flexspi_nor_read_status_reg(spi_nor_t *spi_nor, uint8_t *status_reg)
{
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = 0;
flexspi_ip_cmd.dst = status_reg;
flexspi_ip_cmd.size = 1;
flexspi_ip_cmd.op = FLEXSPI_CMD_READ;
flexspi_ip_cmd.seq_id = 1;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
return imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
}
flexspi_nor_program_by_ip
static uint32_t flexspi_nor_program_by_ip(spi_nor_t *spi_nor,
uint8_t *dst, uint8_t *src, uint32_t size)
{
uint32_t ret = 0;
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
ret = flexspi_nor_write_enable(spi_nor);
if (ret != 0) {
goto cleanup;
}
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = src;
flexspi_ip_cmd.dst = dst;
flexspi_ip_cmd.size = size;
flexspi_ip_cmd.op = FLEXSPI_CMD_WRITE;
flexspi_ip_cmd.seq_id = 9;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
ret = imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
if (ret != 0) {
goto cleanup;
}
ret = flexspi_nor_wait_busy_bit(spi_nor);
cleanup:
return ret;
}
flexspi_nor_read_by_ip
static uint32_t flexspi_nor_read_by_ip(spi_nor_t *spi_nor, uint8_t *dst,
uint8_t *src, uint32_t size)
{
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd.src = src;
flexspi_ip_cmd.dst = dst;
flexspi_ip_cmd.size = size;
flexspi_ip_cmd.op = FLEXSPI_CMD_READ;
flexspi_ip_cmd.seq_id = CMD_INDEX_READ;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
return imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
}
flexspi_nor_wait_busy_bit
static uint32_t flexspi_nor_wait_busy_bit(spi_nor_t *spi_nor)
{
uint8_t status_reg;
uint32_t ret = 0;
uint32_t is_busy = 0;
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = 0;
flexspi_ip_cmd.dst = &status_reg;
flexspi_ip_cmd.size = sizeof(status_reg);
flexspi_ip_cmd.op = FLEXSPI_CMD_READ;
flexspi_ip_cmd.seq_id = 1;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
do {
ret = imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
is_busy = status_reg & 0x01;
if (ret != 0) {
goto cleanup;
}
} while (is_busy);
cleanup:
return ret;
}
```.
<div class="se-preview-section-delimiter"></div>
##### flexspi_nor_erase_bulk
<div class="se-preview-section-delimiter"></div>
```c
static uint32_t flexspi_nor_erase_bulk(spi_nor_t *spi_nor)
{
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = 0;
flexspi_ip_cmd.dst = 0;
flexspi_ip_cmd.size = 0;
flexspi_ip_cmd.op = FLEXSPI_CMD_OPER;
flexspi_ip_cmd.seq_id = 6;
flexspi_ip_cmd.is_parallel = 0;
return imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
}
flexspi_nor_write_enable
static uint32_t flexspi_nor_write_enable(spi_nor_t *spi_nor)
{
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = 0;
flexspi_ip_cmd.dst = 0;
flexspi_ip_cmd.size = 0;
flexspi_ip_cmd.op = FLEXSPI_CMD_OPER;
flexspi_ip_cmd.seq_id = 3;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
return imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
}
flexspi_nor_erase_sector
static uint32_t flexspi_nor_erase_sector(spi_nor_t *spi_nor, uint32_t addr)
{
flexspi_instance_t *flexspi_instance_p = (flexspi_instance_t *)spi_nor->host;
flexspi_t *flexspi_reg = flexspi_instance_p->flexspi_reg;
flexspi_ip_cmd_t flexspi_ip_cmd;
flexspi_ip_cmd.src = 0;
flexspi_ip_cmd.dst = (uint8_t *)((uint64_t)addr);
flexspi_ip_cmd.size = 0;
flexspi_ip_cmd.op = FLEXSPI_CMD_OPER;
flexspi_ip_cmd.seq_id = 5;
flexspi_ip_cmd.seq_size = 1;
flexspi_ip_cmd.is_parallel = 0;
return imx_flexspi_ip_command(flexspi_reg, &flexspi_ip_cmd);
}