5.33 XSPI 使用说明

本章说明 N32H49x 标准外设库中 XSPI 驱动的文件组成与 34 个公开函数,以及 XSPI_DUALQUAD、XSPI_QUAD、XSPI_QUAD_DMA 3 个示例。XSPI 支持标准、双线、四线、八线 SPI 通信与内存映射(XIP)访问外扩 Flash,间接模式的 FIFO 收发、中断与 DMA 请配合用户手册的“多线串行外设接口(xSPI)”章节阅读。

5.33.1 相关文件

相对路径 作用
firmware/n32h49x_std_periph_driver/inc/n32h49x_xspi.h 定义帧格式、传输模式、FIFO 阈值、中断与 DMA 选择等宏与 XSPI_InitType 结构,声明 34 个公开函数
firmware/n32h49x_std_periph_driver/src/n32h49x_xspi.c 实现上述 34 个函数:复位与初始化、传输类型与等待周期、FIFO 阈值与数据量、数据收发与状态标志、中断与 DMA 配置
projects/n32h49x_EVAL/examples/XSPI/ XSPI 示例根目录,含 XSPI_DUALQUAD、XSPI_QUAD、XSPI_QUAD_DMA 3 个示例
projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD/ 该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt
projects/n32h49x_EVAL/bsp/ 该示例引用的公共板级文件:串口日志函数

5.33.2 API 参考

搜索 API共 34 个函数

以下 34 个公开函数按 n32h49x_xspi.h 的声明顺序分为 7 组;每个条目给出功能摘要与 n32h49x_xspi.c 中该函数正上方的注释原文。

复位与初始化

XSPI_DeInit、XSPI_Init、XSPI_StructInit、XSPI_Cmd、XSPI_XIP_Cmd

传输类型与等待周期

XSPI_SetTransType、XSPI_SetWaitCycles

FIFO 阈值与数据量

XSPI_SetRXFIFOLevel、XSPI_SetTXFIFOLevel、XSPI_SetTXFIFOStartLevel、XSPI_GetRXFIFOLevel、XSPI_GetTXFIFOLevel、XSPI_ReadRxFifoNum、XSPI_ReadTxFifoNum

数据收发与状态标志

XSPI_GetDataPointer、XSPI_SendData、XSPI_ReceiveData、XSPI_GetFlagStatus、XSPI_GetBusyStatus、XSPI_GetTxDataBusyStatus、XSPI_GetTxDataEmptyStatus、XSPI_GetRxHaveDataStatus、XSPI_GetRxDataFullStatus、XSPI_GetDataConflictErrorStatus

中断

XSPI_GetINTStatus、XSPI_ClearITBit、XSPI_ConfigInt

DMA

XSPI_ConfigDMATxLevel、XSPI_ConfigDMARxLevel、XSPI_EnableDMA

FIFO 数据搬运

XSPI_ClrFifo、XSPI_GetFifoData、XSPI_SendAndGetWords、XSPI_SendWordAndGetWords

void XSPI_DeInit(void)将 XSPI 外设寄存器恢复为默认复位值。
源码注释
name    XSPI_DeInit.
fun     Deinitializes the XSPI peripheral registers to its default reset values.
return  none
void XSPI_Init(XSPI_InitType* XSPI_InitStruct)合并 XSPI 参数结构体缓冲区中的配置,并写入相关寄存器。
源码注释
name    XSPIInitConfig.
fun     Merge configuration from the buffer of XSPI para struct, then write it into related registers.
param   XSPI_InitStruct :
          - FRF
          - SPIFRF
          - TMOD
          - SCPOL
          - SCPH
          - DFS
          - SSTE
          - SEN
          - CLKDIV
          - WAITCYCLES
          - INST_L
          - ADDRL
          - NDF
          - TXFT
          - RXFT
          - ENHANCED_WAITCYCLES
          - ENHANCED_CLKSTREN
          - ENHANCED_ADDR_L
          - ENHANCED_INST_L
          - ENHANCED_TRANSTYPE
          - ENHANCED_WRSPIDDREN;
          - ENHANCED_WRINDDREN;
          - XIP_FRF
          - XIP_TRANSTYPE
          - XIP_ADDRL
          - XIP_INST_L
          - XIP_WAITCYCLES
          - XIPDFSHC
          - XIPINSTEN
          - XIPCTEN
          - XIPINSTEN
          - XIPMBL
          - XIP_WRINDDREN
          - XIP_DDREN
          - XIPDFSHC
          - XIPMDBITS
          - ITOC
          - WTOC
          - XTOUT
          - CFS
          - MWMOD
          - MCDIR
          - MHSEN
          - TXFN
          - RXFN
          - SDCN
          - SES
          - TXDE
return  none

使用提示: 源码注释的 name 字段写作 XSPIInitConfig.,与函数名 XSPI_Init 不一致,按函数名调用即可。

void XSPI_StructInit(XSPI_InitType* XSPI_InitStruct)把 XSPI_InitStruct 的每个成员填充为默认值。
源码注释
name    XSPI_StructInit.
fun     Fills each XSPI_InitStruct member with its default value.
param   XSPI_InitStruct :
          - FRF
          - SPIFRF
          - TMOD
          - SCPOL
          - SCPH
          - DFS
          - SSTE
          - SEN
          - CLKDIV
          - WAITCYCLES
          - INST_L
          - ADDRL
          - NDF
          - TXFT
          - RXFT
          - ENHANCED_WAITCYCLES
          - ENHANCED_CLKSTREN
          - ENHANCED_ADDR_L
          - ENHANCED_INST_L
          - ENHANCED_TRANSTYPE
          - ENHANCED_WRSPIDDREN;
          - ENHANCED_WRINDDREN;
          - XIP_FRF
          - XIP_TRANSTYPE
          - XIP_ADDRL
          - XIP_INST_L
          - XIP_WAITCYCLES
          - XIPDFSHC
          - XIPINSTEN
          - XIPCTEN
          - XIPINSTEN
          - XIPMBL
          - XIP_WRINDDREN
          - XIP_DDREN
          - XIPDFSHC
          - XIPMDBITS
          - ITOC
          - WTOC
          - XTOUT
          - CFS
          - MWMOD
          - MCDIR
          - MHSEN
          - TXFN
          - RXFN
          - SDCN
          - SES
          - TXDE
return  none
void XSPI_Cmd(FunctionalState cmd)控制 XSPI 功能开关。
源码注释
name    XSPI_Cmd.
fun     Control XSPI function switch.
param   cmd
          - ENABLE
          - DISABLE
return  none
void XSPI_XIP_Cmd(FunctionalState cmd)控制 XSPI XIP 功能开关。
源码注释
name    XSPI_XIP_Cmd.
fun     Control XSPI XIP function switch.
param   cmd
          - ENABLE
          - DISABLE
return  none
void XSPI_SetTransType(uint32_t TransType)设置地址与指令的发送格式(1/2/4/8 线模式)。
源码注释
name    XSPI_SetTransType.
fun     Set the format of address and instruction sending (1/2/4/8 wire mode)
param   TransType
          - XSPI_ENH_CTRL0_TRANSTYPE_STANDARD
          - XSPI_ENH_CTRL0_TRANSTYPE_ADDRESS_BY_FRF
          - XSPI_ENH_CTRL0_TRANSTYPE_ALL_BY_FRF
return  none
void XSPI_SetWaitCycles(uint32_t WAITCYCLES)设置需要等待的空指令周期数。
源码注释
name    XSPI_SetWaitCycles.
fun     Set the number of empty instruction cycles to wait
param   WAITCYCLES:
          - XSPI_ENH_CTRL0_WAIT_1CYCLES
          - ...
          - XSPI_ENH_CTRL0_WAIT_31CYCLES
return  none
void XSPI_SetRXFIFOLevel(uint32_t fifo_len)设置接收 FIFO 传输阈值,即触发接收满中断的阈值。
源码注释
name    XSPI_SetRXFIFOLevel.
fun     Set Rx fifo transmission threshold, trigger full interrupt threshold
param   fifo_len:
          - 0x0-0xF
return  none
void XSPI_SetTXFIFOLevel(uint32_t fifo_len)设置发送 FIFO 传输阈值,并触发相应中断阈值。
源码注释
name    XSPI_SetTXFIFOLevel.
fun     Set the Tx fifo transmission threshold and trigger the interrupt threshold
param   fifo_len:
          - 0x0-0xF
return  none
void XSPI_SetTXFIFOStartLevel(uint32_t fifo_len)设置发送 FIFO 启动传输阈值。
源码注释
name    XSPI_SetTXFIFOStartLevel.
fun     Set Tx fifo start transmission threshold
param   fifo_len:
          - 0x0-0xF
return  none
uint8_t XSPI_GetRXFIFOLevel(void)获取接收 FIFO 中的数据量。
源码注释
name    XSPI_GetRXFIFOLevel.
fun     Get the amount of data in the Rx fifo
return  Amount of data in Rx fifo.
uint8_t XSPI_GetTXFIFOLevel(void)获取发送 FIFO 中的数据量。
源码注释
name    XSPI_GetTXFIFOLevel.
fun     Get the amount of data in the Tx fifo
return  Amount of data in Tx fifo.
uint32_t XSPI_GetDataPointer(void)获取 XSPI DAT0 寄存器的指针。
源码注释
name    XSPIGetDataPointer.
fun     Get Pointer of XSPI DAT0 register.
return  The pointer of XSPI DAT0 register.

使用提示: 源码注释的 name 字段写作 XSPIGetDataPointer.,与函数名 XSPI_GetDataPointer 不一致,按函数名调用即可。

uint32_t XSPI_ReadRxFifoNum(void)读取 XSPI RXFN 寄存器的值,该值表示接收 FIFO 中的数据个数。
源码注释
name    XSPI_ReadRxFifoNum.
fun     Read value from XSPI RXFN register which shows the number of the data from receive fifo.
return  The number of the data from receive fifo.
uint32_t XSPI_ReadTxFifoNum(void)读取 XSPI TXFN 寄存器的值,该值表示发送 FIFO 中的数据个数。
源码注释
name    XSPI_ReadTxFifoNum.
fun     Read value from XSPI TXFN register which shows the number of the data from tx fifo.
return  The number of the data from tx fifo.
void XSPI_SendData(uint32_t SendData)直接向 XSPI DAT0 寄存器写入一个数据以发送。
源码注释
name    XSPI_SendData.
fun     Write one data direct to XSPI DAT0 register to send.
param   SendData:
          - data to be send
return  none
uint32_t XSPI_ReceiveData(void)从 XSPI DAT0 寄存器读取一个数据。
源码注释
name    XSPI_ReceiveData.
fun     Read one data from XSPI DAT0 register.
return  The value of XSPI DAT0 register.
FlagStatus XSPI_GetFlagStatus(uint32_t XSPI_FLAG)检查指定的 XSPI 标志是否置位。
源码注释
name    XSPI_GetFlagStatus.
fun     Checks whether the specified XSPI flag is set or not.
param   XSPI_FLAG:
          - XSPI_STS_BUSY
          - XSPI_STS_TXFNF
          - XSPI_STS_TXFE
          - XSPI_STS_RXFNE
          - XSPI_STS_RXFF
          - XSPI_STS_TXE
          - XSPI_STS_DCERR
return  The new state of XSPI_FLAG (SET or RESET).
uint16_t XSPI_GetINTStatus(uint16_t FLAG)检查指定的 XSPI 中断是否发生。
源码注释
name    XSPI_GetINTStatus.
fun     Checks whether the specified XSPI interrupt has occurred or not.
param   FLAG:
          - XSPI_ISTS_TXFEIS
          - XSPI_ISTS_TXFOIS
          - XSPI_ISTS_RXFUIS
          - XSPI_ISTS_RXFOIS
          - XSPI_ISTS_RXFFIS
          - XSPI_ISTS_MMCIS
          - XSPI_ISTS_XRXOIS
          - XSPI_ISTS_TXUIS
return  The new state of XSPI_IT (SET or RESET).
void XSPI_ClearITBit(uint16_t XSPI_IT)检查指定的 XSPI 中断是否发生。
源码注释
name    XSPI_ClearITBit.
fun     Checks whether the specified XSPI interrupt has occurred or not.
param   XSPI_IT:
          - XSPI_IT_TXUIM
          - XSPI_IT_XRXOIM
          - XSPI_IT_MMCIM
          - XSPI_IT_RXFFIM
          - XSPI_IT_RXFOIM
          - XSPI_IT_RXFUIM
          - XSPI_IT_TXFOIM
          - XSPI_IT_TXFEIM
return  none.
void XSPI_ConfigInt(uint16_t XSPI_IT, FunctionalState Cmd)使能或禁止指定的 XSPI 中断。
源码注释
name    XSPI_ConfigInt.
fun     Enables or disables the specified XSPI interrupts.
param   XSPI_IT:
          - XSPI_IT_TXUIM
          - XSPI_IT_XRXOIM
          - XSPI_IT_MMCIM
          - XSPI_IT_RXFFIM
          - XSPI_IT_RXFOIM
          - XSPI_IT_RXFUIM
          - XSPI_IT_TXFOIM
          - XSPI_IT_TXFEIM
param   Cmd:
          - ENABLE
          - DISABLE
return  none.
void XSPI_ConfigDMATxLevel(uint32_t TxDataLevel)配置 XSPI DMA 发送阈值。
源码注释
name    XSPI_ConfigDMATxLevel.
fun     Configuration of XSPI DMA Tx Level.
param   TxDataLevel(transmit data):
          - 0~0x1F
return  none.
void XSPI_ConfigDMARxLevel(uint32_t RxDataLevel)配置 XSPI DMA 接收阈值。
源码注释
name    XSPI_ConfigDMARxLevel.
fun     Configuration of XSPI DMA Rx Level.
param   RxDataLevel(receive data):
          - 0~0x1F
return  none.
void XSPI_EnableDMA(uint32_t XSPI_DMAReq, FunctionalState Cmd)使能或禁止 XSPI 的 DMA 接口。
源码注释
name    XSPI_EnableDMA
fun     Enables or disables the XSPI's DMA interface.
param   XSPI_DMAReq (The input parameters must be the following values):
          - XSPI_DMAREQ_TX    XSPI DMA transmit request
          - XSPI_DMAREQ_RX    XSPI DMA receive request
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
note  Configured when xSPI_EN.XSPIEN disabled
FlagStatus XSPI_GetBusyStatus(void)获取 XSPI 状态,判断是否忙。
源码注释
name    XSPI_GetBusyStatus.
fun     Get XSPI status,busy or not.
return  SET:XSPI busy;
        RESET:XSPI idle.
FlagStatus XSPI_GetTxDataBusyStatus(void)检查发送 FIFO 是否已满。
源码注释
name    XSPI_GetTxDataBusyStatus.
fun     Check transmit fifo full or not.
return  SET: Transmit fifo full;
        RESET: Transmit fifo not full.
FlagStatus XSPI_GetTxDataEmptyStatus(void)检查发送 FIFO 是否为空。
源码注释
name    XSPI_GetTxDataEmptyStatus.
fun     Check transmit fifo empty or not.
return  SET: Transmit fifo empty;
        RESET: Transmit fifo not empty.
FlagStatus XSPI_GetRxHaveDataStatus(void)检查接收 FIFO 是否有数据。
源码注释
name    XSPI_GetRxHaveDataStatus.
fun     Check receive fifo have data or not.
return  SET:Receive fifo have data;
        RESET:Receive fifo empty.
FlagStatus XSPI_GetRxDataFullStatus(void)检查接收 FIFO 是否已满。
源码注释
name    XSPI_GetRxDataFullStatus.
fun     Check receive fifo full or not.
return  SET: Receive fifo full;
        RESET: Receive fifo not full.
FlagStatus XSPI_GetDataConflictErrorStatus(void)检查是否发生数据冲突错误。
源码注释
name    XSPI_GetDataConflictErrorStatus.
fun     Check data conflict error or not.
return  SET: Data conflict error;
        RESET: No data conflict error.
void XSPI_ClrFifo(void)读取 DAT0 寄存器以清空 FIFO。
源码注释
name    ClrFifo.
fun     Read DAT0 register to clear fifo.
return  none.

使用提示: 源码注释的 name 字段写作 ClrFifo.,与函数名 XSPI_ClrFifo 不一致,按函数名调用即可。

uint32_t XSPI_GetFifoData(uint32_t* pData, uint32_t Len)从 FIFO 中获取数据。
源码注释
name    GetFifoData
fun     Get data from fifo.
param   pData pointer to buffer of getting fifo data.
param   Len length of getting fifo data.
return  XSPI_SUCCESS or XSPI_NULL.

使用提示: 源码注释的 name 字段写作 GetFifoData,与函数名 XSPI_GetFifoData 不一致,按函数名调用即可。

void XSPI_SendAndGetWords(uint32_t* pSrcData, uint32_t* pDstData, uint32_t cnt)从源数据缓冲区发送数据,并把返回的数据取回目标数据缓冲区。
源码注释
name    XSPISendAndGetWords.
fun     Send words out from source data buffer and get returned datas into destination data buffer.
param   pSrcData:
          - pSrcData pointer to buffer of sending datas.
param   pDstData:
          - pDstData pointer to buffer of getting returned datas.
param   cnt:
          - cnt number of sending datas.
return  none.

使用提示: 源码注释的 name 字段写作 XSPISendAndGetWords.,与函数名 XSPI_SendAndGetWords 不一致,按函数名调用即可。

uint32_t XSPI_SendWordAndGetWords(uint32_t WrData, uint32_t* pRdData, uint8_t LastRd)发送一个数据,并把返回的数据取回目标数据缓冲区。
源码注释
name    XSPISendWordAndGetWords.
fun     Send one word data and get returned words into destination data buffer.
param   WrData:
          - WrData one word to be sent.
param   pRdData:
          - pRdData pointer to buffer of getting returned datas.
param   LastRd:
          - 1:go on to get returned datas.
          - 0:end to get returned datas.
return  none.

使用提示: 源码注释的 name 字段写作 XSPISendWordAndGetWords.,与函数名 XSPI_SendWordAndGetWords 不一致,按函数名调用即可。

5.33.3 Demo 示例说明

本节说明 XSPI 的 3 个示例:XSPI_DUALQUAD 用两片外置 Flash 的片选切换组合成八线数据通路,XSPI_QUAD 用四线模式读写单片外置 Flash,XSPI_QUAD_DMA 在四线模式基础上用 DMA 搬运数据。

5.33.3.1 XSPI_DUALQUAD 双片选八线读写外置 Flash

工程目录: projects/n32h49x_EVAL/examples/XSPI/XSPI_DUALQUAD/

初始化日志、时钟与 GPIO→用标准模式配置 XSPI 并逐片使能四线→分别擦除两片 Flash 并读回校验→切换片选后用八线格式写入数据→用八线格式读回并比较得出结论

项目 源码解读
功能 用两片外置 Quad Flash 通过片选切换组合为八线数据通路;
先以标准模式逐片擦除并读回校验,再切到八线格式写入并读回比较。
源码组成 src/main.c:main、Delay;
src/xspi_cfg.c:RCC_Configuration、GPIO_Configuration、XSPI_Configuration;
src/spi_flash.c:XSPI_FlashREG_WR、XSPI_FlashSendData、XSPI_FlashWrite、XSPI_FlashRead;
inc/main.h:长度与地址宏;
readme.txt、MDK-ARM/、EWARM/:说明与工程文件。
关键配置 时钟:RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE) 与 GPIO、AFIO 时钟;
帧格式:寄存器阶段用 STANDRD_SPI_FORMAT,数据阶段用 OCTAL_SPI_FORMAT;
片选:由 AFIO_Config_XSPI_DualQuadMode 选择第一片或第二片 Flash;
数据:DFS_32_BIT 与 CTRL1_NDF_63、CTRL1_NDF_255 控制帧长与数量。
程序与数据路径 main 先配好时钟与引脚,再进入标准模式;
循环内逐片选择 Flash,写使能、置 QE、擦除 32KB 扇区并读回校验全 0xFF;
填充 XSPI_Wbuffer 后切到八线格式写入数据并读回;
main 比较 XSPI_Rbuffer 与 XSPI_Wbuffer 并打印结论。
主要 API XSPI_DeInit、XSPI_Cmd、XSPI_SendData、XSPI_ReceiveData、XSPI_GetFlagStatus
验证方法 串口打印 Spi_flash write and read demo end - dual quad mode 表示流程正常结束;
比较循环未打印 FALSH WR fail 表示写入与读回一致。
使用提示 双片选通过 AFIO 切换,移植时按目标板两片 Flash 的片选引脚调整;
寄存器读写阶段与数据阶段使用不同帧格式,切换时需重新调用 XSPI_Configuration;
运行需插好全功能板上的跳线帽。
核心代码解读与移植

示例把两片外置 Quad Flash 通过片选切换组合成八线数据通路,先逐片擦除校验,再写入并读回比较。

数据路径: RCC_Configuration 与 GPIO_Configuration 配置时钟与引脚 → XSPI_Configuration 进入标准模式 → AFIO_Config_XSPI_DualQuadMode 选择第一片或第二片 Flash → 写使能、置 QE、擦除并读回校验 → 切到八线格式写入并读回 XSPI_Wbuffer → 比较 XSPI_Rbuffer 与 XSPI_Wbuffer

1. 初始化 XSPI 并选择片选。 main 先配置标准模式,再用 AFIO_Config_XSPI_DualQuadMode 在两片 Flash 之间切换片选。

src/main.csrc/main.c · main
    /* XSPI Configuration */
    XSPI_Configuration(STANDRD_SPI_FORMAT,TX_AND_RX,DFS_08_BIT,CTRL1_NDF_255,50);

    for(flash_cnt = 0; flash_cnt < 2; flash_cnt++) // Erase flash 1 and flash 2 respectively
    {
        if(flash_cnt == 1)// enable flash 2 and clear buffer
        {
            AFIO_Config_XSPI_DualQuadMode(AFIO_XSPI_DUAL_QUAD_ENABLE);
        }
        else
        {
            AFIO_Config_XSPI_DualQuadMode(AFIO_XSPI_DUAL_QUAD_DISABLE);
        }

XSPI_Configuration 直接写 CTRL0、CTRL1、BAUD 等寄存器完成配置;两片 Flash 由 AFIO 的片选选择切换,每次循环只操作被选中的一片。

2. 置 QE 使能四线模式。 在标准模式下写使能并置位状态寄存器 2 的 QE 位,使 Flash 支持四线传输。

src/main.csrc/main.c · main
        do/*set QE*/
        {
            bufw[0] = SPIFLASH_Write_Reg1;
            bufw[1] = 0x00;
            bufw[2] = SPIFLASH_REG2CMD_SETQE;
            XSPI_FlashREG_WR(bufw,bufr,3,TYPE_REG_WRITE);
            bufw[0] = SPIFLASH_Read_Reg2;
            XSPI_FlashREG_WR(bufw,bufr,NULL,TYPE_REG_READ);
        }while(!(bufr[1]&SPIFLASH_REG2CMD_SETQE));

寄存器读写通过写指令与地址后轮询状态寄存器完成,do 与 while 循环确保 QE 位真正置位。

3. 擦除后读回校验。 逐片擦除 32KB 扇区,再用读命令把数据取回并检查是否为全 0xFF。

src/main.csrc/main.c · main
        /*==========================Read flash===========================*/
        XSPI_Wbuffer[0]=SPIFLASH_Read_Data;
        XSPI_Wbuffer[1]=(flash_addr & 0xff0000) >> 16;;
        XSPI_Wbuffer[2]=(flash_addr & 0xff00) >> 8;;
        XSPI_Wbuffer[3]=flash_addr & 0xff;;
        XSPI_FlashSendData(XSPI_Wbuffer,XSPI_Rbuffer,0x104);
        log_info("============Read flash %X=================\r\n",(flash_cnt+1));
        for(i = 4; i < (TEST_WR_BYTE_LEN+4); i++)
        {
            if(XSPI_Rbuffer[i] != 0xFF)
            {
                printf("Erase flash %X fail,i=0X%X\r\n",(flash_cnt+1),i);
                break;
            }
        }

4. 写使能两片 Flash。 写入前对两片 Flash 分别发出写使能命令,并轮询状态寄存器确认写使能位。

src/main.csrc/main.c · main
    for(i = 0; i < TEST_WR_WORD_LEN; i++)
    {
        XSPI_Wbuffer[i] = 0xCC660000+i;
    }
    for(flash_cnt = 0; flash_cnt < 2; flash_cnt++) // enable write flash 1 and flash 2 respectively
    {
        if(flash_cnt == 1)// enable flash 2 and clear buffer
        {
            AFIO_Config_XSPI_DualQuadMode(AFIO_XSPI_DUAL_QUAD_ENABLE);
        }
        else
        {
            AFIO_Config_XSPI_DualQuadMode(AFIO_XSPI_DUAL_QUAD_DISABLE);
        }
        do/*write enable*/
        {
            bufw[0] = SPIFLASH_Write_Enable;
            XSPI_FlashREG_WR(bufw,bufr,1,TYPE_REG_WRITE);
            bufw[0] = SPIFLASH_Read_Reg1;
            XSPI_FlashREG_WR(bufw,bufr,NULL,TYPE_REG_READ);
        }while((bufr[1]&0x03) != 0x02);
    }

对应源码: src/main.c

5.33.3.2 XSPI_QUAD 四线读写外置 Flash

工程目录: projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD/

初始化日志、时钟与 GPIO→使能外置 Flash 四线模式→擦除扇区并写入测试数据→四线读回并与写入比较→擦除整片并校验读回数据

项目 源码解读
功能 用四线模式访问单片外置 Flash;
先置 QE 使能四线,擦除扇区后写入数据,读回比较一致后再擦除整片并校验读回是否全 0xFF。
源码组成 src/main.c:main、Delay、Buffercmp;
src/xspi_cfg.c:RCC_Configuration、GPIO_Configuration、GPIO_HD_WP_Configuration、XSPI_Configuration;
src/spi_flash.c:XSPI_FlashWrite、sFLASH_QuadEnable、sFLASH_EraseSector、sFLASH_ReadBuffer 等;
inc/main.h、inc/spi_flash.h、inc/xspi_cfg.h:宏与函数声明;
readme.txt、MDK-ARM/、EWARM/:说明与工程文件。
关键配置 时钟:RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE);
引脚:NSS0 用 PG6、SCK 用 PF10、IO0/IO1 用 PF8/PF9、IO2/IO3 用 PF7/PF6;
帧格式:寄存器阶段用 DFS_08_BIT,数据阶段用 QUAD_SPI_FORMAT 与 DFS_32_BIT;
阈值:XSPI_SetTXFIFOStartLevel 按传输长度设置。
程序与数据路径 main 先配置时钟与引脚,再置 QE 使能四线模式;
填充 XSPI_Wbuffer 后擦除扇区并写入数据;
四线读回数据后用 Buffercmp 比较写入与读出;
整片擦除后再读回校验是否全 0xFFFFFFFF 并打印结论。
主要 API XSPI_DeInit、XSPI_Cmd、XSPI_SetTXFIFOStartLevel、XSPI_SendData、XSPI_GetFlagStatus
验证方法 串口打印 Spi_flash write and read demo test success 表示读写一致且擦除后读回全 0xFF;
否则打印 Spi_flash write and read demo test failed。
使用提示 sFLASH_QuadEnable 会临时把 IO2/IO3 配为普通输出以驱动写保护与保持引脚,置位后再切回复用功能;
寄存器读写超过 16 个数据需改用 DMA 方式传输;
运行需外置 Flash 与全功能板跳线帽就位。
核心代码解读与移植

示例先用标准模式置 QE 使能四线,再擦除扇区写入数据、读回比较,最后整片擦除校验。

数据路径: RCC_Configuration 与 GPIO_Configuration 配置时钟与引脚 → sFLASH_QuadEnable 置 QE 使能四线 → sFLASH_EraseSector 擦除扇区 → sFLASH_WriteBuffer 写入 XSPI_Wbuffer → sFLASH_ReadBuffer 四线读回 → Buffercmp 比较 → sFLASH_EraseChip 整片擦除并校验读回全 0xFFFFFFFF

1. 直接写寄存器配置 XSPI。 XSPI_Configuration 先复位外设,再把帧格式、传输模式、帧长、帧数与波特率写入相关寄存器。

src/xspi_cfg.csrc/xspi_cfg.c · XSPI_Configuration
void XSPI_Configuration(uint32_t frame_format,uint32_t transfer_mode,uint32_t data_frame_size,uint16_t number_data_frame,uint16_t baudr)
{
    XSPI_DeInit();
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE);
    /*disable XSPI*/
    XSPI->SLAVE_EN = (0x0);
    XSPI_Cmd(DISABLE);

    /*set MST, SPI_FRF, TMOD ,SCPOL, SCPH, DFS, SSTE*/
    XSPI->CTRL0 = (XSPI_Mode_Master|frame_format|transfer_mode|SCPOL_LOW|START_BIT|data_frame_size|SSTE_BIT0);
    /*set NDF*/
    XSPI->CTRL1 = (number_data_frame);
    /*set CLKDIV */
    XSPI->BAUD = ((uint32_t)baudr<<1);

    /*set TRANSTYPE, ADDRLEN, INSTL, WAITCYCLES*/
    XSPI->ENH_CTRL0 = (TRANS_TYPE_STANDRD|ENSPI_ADDR_24BIT|ENSPI_INST_L_08BIT|ENSPI_WAIT_8CYCLES);
    if(transfer_mode == TX_ONLY || transfer_mode == RX_ONLY)
    {
        XSPI->RX_DELAY = (XSPI->BAUD)/2;
        XSPI->ENH_CTRL0 |= CLK_STRETCH_EN;
    }
    /*set TXFTTEI*/
    XSPI->TXFT = ((0x00<<16)|0x00)&0x1f001f;/* level = 0*/
    /*set RXFTTEI*/
    XSPI->RXFT = (0x08&0x1f);/* level = 8*/

    XSPI->IMASK = 0;
    
    /*enable XSPI*/
    XSPI->SLAVE_EN = (0x1);
    XSPI_Cmd(ENABLE);
}

2. 置 QE 使能四线模式。 sFLASH_QuadEnable 先把 IO2/IO3 配为普通输出驱动写保护与保持引脚,置位状态寄存器 2 的 QE 位后再切回复用功能。

src/spi_flash.csrc/spi_flash.c · sFLASH_QuadEnable
    GPIO_HD_WP_Configuration();
    XSPI_Configuration(STANDRD_SPI_FORMAT,TX_AND_RX,DFS_08_BIT,CTRL1_NDF_255,TEST_WR_CMDCLKDIV);
    flag |= sFLASH_WriteEnable();
    
    do/*set QE*/
    {
#if EXTERNAL_FLASH == FLASH_P25Q40
        bufw[0] = SPIFLASH_Write_Reg1;
        bufw[1] = 0x00;
        bufw[2] = SPIFLASH_REG2CMD_SETQE;
        XSPI_FlashREG_WR(bufw,bufr,3,TYPE_REG_WRITE);
#else
        bufw[0] = SPIFLASH_Write_Reg2;
        bufw[1] = SPIFLASH_REG2CMD_SETQE;
        XSPI_FlashREG_WR(bufw,bufr,2,TYPE_REG_WRITE);
#endif
        bufw[0] = SPIFLASH_Read_Reg2;
        XSPI_FlashREG_WR(bufw,bufr,NULL,TYPE_REG_READ);
    }while(!(bufr[1]&SPIFLASH_REG2CMD_SETQE) && timeout--);
    
    if(!(bufr[1]&SPIFLASH_REG2CMD_SETQE) && (timeout == 0))
    {
        flag |= FAILED_STATUS;
    }
    else
    {
        flag |= sFLASH_WaitForWriteEnd();
    }
    GPIO_Configuration();

3. 四线写页。 sFLASH_WritePage 先在四线模式下写使能,再配置帧格式并把页数据写入 Flash,最后等待写结束。

src/spi_flash.csrc/spi_flash.c · sFLASH_WritePage
TestResultStatus sFLASH_WritePage(uint32_t* pBuffer, uint32_t WriteAddr, uint32_t NumWordToWrite)
{
    TestResultStatus flag = SUCCESS_STATUS;
    if(NumWordToWrite != 0)
    {
        flag |= sFLASH_WriteEnable();

        XSPI_Configuration(QUAD_SPI_FORMAT,TX_ONLY,DFS_32_BIT,(NumWordToWrite-1),TEST_WR_CLKDIV);
        
        flag |= XSPI_FlashWrite(SPIFLASH_QuadPage_Pro,WriteAddr,NumWordToWrite,pBuffer);

        /* Wait the end of Flash writing */
        flag |= sFLASH_WaitForWriteEnd();
    }
    return flag;
}

4. 四线读回。 sFLASH_ReadBuffer 把传输模式设为只接收、帧格式设为四线,再读回指定字数的数据。

src/spi_flash.csrc/spi_flash.c · sFLASH_ReadBuffer
TestResultStatus sFLASH_ReadBuffer(uint32_t* pBuffer, uint32_t ReadAddr, uint32_t NumWordToRead)
{
    TestResultStatus flag = SUCCESS_STATUS;
    XSPI_Configuration(QUAD_SPI_FORMAT,RX_ONLY,DFS_32_BIT,(NumWordToRead-1),TEST_WR_CLKDIV);
    
    flag |= XSPI_FlashRead(SPIFLASH_Read_QUAD,ReadAddr,NumWordToRead,pBuffer);

    return flag;
}

对应源码: src/xspi_cfg.c、src/spi_flash.c

5.33.3.3 XSPI_QUAD_DMA 四线 DMA 读写外置 Flash

工程目录: projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD_DMA/

初始化日志、时钟、GPIO 与 DMA→使能外置 Flash 四线模式→擦除扇区并写入测试数据→用 DMA 读回并与写入比较→打印读写结论

项目 源码解读
功能 与四线示例流程一致,但读写改用 DMA 搬运数据;
在 XSPI->DAT0 与缓冲区之间搬运,提高大数据量传输效率。
源码组成 src/main.c:main、Delay、Buffercmp;
src/xspi_cfg.c:RCC_Configuration、GPIO_Configuration、GPIO_HD_WP_Configuration、XSPI_Configuration、DMA_Configuration;
src/spi_flash.c:XSPI_FlashWrite、XSPI_FlashRead(含 DMA 使能与等待)等;
inc/main.h、inc/spi_flash.h、inc/xspi_cfg.h:宏与函数声明;
readme.txt、MDK-ARM/、EWARM/:说明与工程文件。
关键配置 DMA 通道:发送用 DMA1_CH1 映射 DMA_REMAP_XSPI_TX,接收用 DMA1_CH2 映射 DMA_REMAP_XSPI_RX;
DMA 参数:WORD 数据宽度、存储器递增、突发使能(近似模式、长度 8);
XSPI:XSPI_ConfigDMATxLevel、XSPI_ConfigDMARxLevel 与 XSPI_EnableDMA 设置阈值与请求。
程序与数据路径 main 配置时钟与引脚并置 QE,擦除扇区后写入 XSPI_Wbuffer;
XSPI_FlashWrite 关闭 XSPI、设 DMA 阈值并使能发送请求,再用 DMA_Configuration 搬运数据;
XSPI_FlashRead 使能接收请求,用 DMA 把 XSPI->DAT0 读入 XSPI_Rbuffer;
main 比较读回与写入并打印结论。
主要 API XSPI_EnableDMA、XSPI_ConfigDMATxLevel、XSPI_ConfigDMARxLevel、XSPI_SendData、XSPI_GetFlagStatus
验证方法 串口打印 Spi_flash write and read demo test success 表示 DMA 写入与读回一致;
否则打印 Spi_flash write and read demo test failed。
使用提示 XSPI 的 DMA 阈值与使能须在 XSPI 关闭时配置,示例先 XSPI_Cmd(DISABLE) 再设置;
发送等待 DMA_FLAG_TC1、接收等待 DMA_FLAG_TC2,移植时按通道核对标志;
DMA 请求映射固定为发送 DMA_REMAP_XSPI_TX、接收 DMA_REMAP_XSPI_RX。
核心代码解读与移植

示例在四线模式基础上把数据搬运交给 DMA,DMA 配置通过请求映射把 XSPI->DAT0 与外设数据流连接。

数据路径: DMA_Configuration 按发送或接收选择通道与请求映射 → XSPI_FlashWrite 关闭 XSPI、设阈值并使能发送请求 → DMA 把缓冲区数据写入 XSPI->DAT0 → XSPI_FlashRead 使能接收请求 → DMA 把 XSPI->DAT0 读入缓冲区 → 等待传输完成标志

1. DMA 通道与请求映射。 DMA_Configuration 依据发送或接收方向选择 DMA1_CH1 或 DMA1_CH2,并设置对应的 XSPI 请求映射。

src/xspi_cfg.csrc/xspi_cfg.c · DMA_Configuration
    DMA_ChannelType* DMAy_Channelx;
    uint32_t DMA_Direction;
    uint32_t DMA_RemapNum = 0;
    
    if (TxRx == DMA_TX)/*DMA tx*/
    {
        DMAy_Channelx  = DMA1_CH1;
        DMA_Direction = DMA_DIR_PERIPH_DST;
        DMA_RemapNum = DMA_REMAP_XSPI_TX;/*DMA remap*/
    }
    else if (TxRx == DMA_RX)/*DMA rx*/
    {
        DMAy_Channelx = DMA1_CH2;
        DMA_Direction = DMA_DIR_PERIPH_SRC;
        DMA_RemapNum = DMA_REMAP_XSPI_RX;/*DMA remap*/
    }
    
    DMA_DeInit(DMAy_Channelx);
    DMA_StructInit(&DMA_InitStructure);
    /* config DMA channel*/
    DMA_InitStructure.PeriphAddr = PeripheralAddr;
    DMA_InitStructure.MemAddr = MemoryAddr;
    DMA_InitStructure.Direction = DMA_Direction;
    DMA_InitStructure.BufSize = Len;
    DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.MemoryInc = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_WIDTH_WORD;
    DMA_InitStructure.MemDataSize = DMA_MEM_DATA_WIDTH_WORD;
    DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority = DMA_PRIORITY_HIGH;
    DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
    DMA_InitStructure.BurstCmd = DMA_BURST_ENABLE;
    DMA_InitStructure.BurstMode = DMA_BURST_MODE_ALMOST;
    DMA_InitStructure.BurstLen = DMA_BURST_LEN_8;
    DMA_Init(DMAy_Channelx, &DMA_InitStructure);
    
    DMA_RequestRemap(DMA_RemapNum, DMAy_Channelx, NewState);

    /* enable DMA channel*/
    DMA_EnableChannel(DMAy_Channelx, NewState);

2. DMA 发送。 XSPI_FlashWrite 关闭 XSPI 后设置 DMA 收发阈值并使能发送请求,再启动 DMA 搬运并等待发送与传输完成。

src/spi_flash.csrc/spi_flash.c · XSPI_FlashWrite
    XSPI_Cmd(DISABLE);
    /*enable DMA    */
    XSPI_ConfigDMATxLevel(0x08);
    XSPI_ConfigDMARxLevel(0x08);
    XSPI_EnableDMA(XSPI_DMAREQ_TX,ENABLE);
    XSPI_Cmd(ENABLE);
    
    XSPI_SendData(PrgCmd);
    XSPI_SendData(addr);
    DMA_Configuration((uint32_t)&XSPI->DAT0, (uint32_t)Wbuf, (count), DMA_TX, ENABLE);

    /*wait TX end   */
    while(XSPI_GetFlagStatus(XSPI_STS_TXFE) == RESET)/*wait TX FIFO empty*/
    {
        if ((wtime--) == 0)
        {
            result |= FAILED_STATUS;
            break;
        }
    }
    wtime = FLASH_WAIT_CNT*1000;
    while(DMA_GetFlagStatus(DMA_FLAG_TC1,DMA1) == RESET)/*wait DMA transfer complete*/
    {
        if ((wtime--) == 0)
        {
            result |= FAILED_STATUS;
            break;
        }
    }
    /*disable DMA*/
    XSPI_Cmd(DISABLE);
    DMA_Configuration((uint32_t)&XSPI->DAT0, (uint32_t)Wbuf, (count), DMA_TX, DISABLE);
    XSPI_EnableDMA(XSPI_DMAREQ_TX,DISABLE);

3. DMA 接收。 XSPI_FlashRead 使能接收请求,启动 DMA 把 XSPI->DAT0 的数据读入缓冲区,等待传输完成标志后关闭 DMA。

src/spi_flash.csrc/spi_flash.c · XSPI_FlashRead
    XSPI_ConfigDMATxLevel(0x08);
    XSPI_ConfigDMARxLevel(0x08);
    XSPI_EnableDMA(XSPI_DMAREQ_RX,ENABLE);
    XSPI_Cmd(ENABLE);
    
    XSPI_SendData(PrgCmd);
    XSPI_SendData(StrAddr);
    DMA_Configuration((uint32_t)&XSPI->DAT0, (uint32_t)DstBuf, (Len), DMA_RX, ENABLE);

    /*wait RX end  */
    while(DMA_GetFlagStatus(DMA_FLAG_TC2,DMA1) == RESET)/*wait DMA transfer complete*/
    {
        if ((wtime--) == 0)
        {
            result |= FAILED_STATUS;
            break;
        }
    }
    
    /*disable DMA*/
    XSPI_Cmd(DISABLE);
    DMA_Configuration((uint32_t)&XSPI->DAT0, (uint32_t)DstBuf, (Len), DMA_RX, DISABLE);
    XSPI_EnableDMA(XSPI_DMAREQ_TX,DISABLE);

对应源码: src/xspi_cfg.c、src/spi_flash.c

5.33.4 注意与排障

场景 检查与建议 来源
命令阶段 每条命令包含 Instruction、Address、Mode bits、Wait cycles、Data 五个阶段,任一阶段可跳过,但至少要保留 Instruction、Address、Mode bits、Data 之一。 用户手册
Mode bits Mode bits 阶段只在 XIP 模式使用;
使能后会在地址阶段后插入模式位,位宽为 2、4、8 或 16。
用户手册
DDR 波特率 DDR 模式下波特率值应为 4 的倍数。 用户手册
XIP 帧格式 XIP 操作只支持 Dual、Quad、Octal 模式,XSPI_CTRL0.SPIFRF 不能配置为 0。 用户手册
Tx and Rx 模式 Tx and Rx 模式只有在标准 SPI 模式(XSPI_CTRL0.SPIFRF 为 00)下才可使用。 用户手册
EEPROM read 模式 EEPROM read 模式只有在标准 SPI 模式(XSPI_CTRL0.SPIFRF 为 00)下才可使用,读取字节数在 XSPI_CTRL1.NDF 中指定。 用户手册
指令与地址 一条指令占用 1 个 FIFO 地址,地址可以占用多个 FIFO 位置,指令和地址都需写入 XSPI_DATx 寄存器。 用户手册
XIP 接收 FIFO 溢出 XIP 传输中若 RX FIFO 深度不足可能溢出导致数据错误,软件检测到 RX FIFO 溢出后必须重新尝试数据传输。 用户手册
国民技术开发套件文档中心

按芯片系列在线查阅国民技术 MCU 开发套件的芯片资料、SDK、驱动 API 与 Demo 示例说明。

© 2026 国民技术股份有限公司 版权所有粤ICP备11069485号本站使用不含 Cookie 的匿名访问统计