5.33 XSPI Guide

This chapter describes the files of the XSPI driver in the N32H49x standard peripheral library and its 34 public functions, together with the XSPI_DUALQUAD, XSPI_QUAD and XSPI_QUAD_DMA examples. XSPI supports standard, dual, quad and octal SPI communication and memory-mapped (XIP) access to external Flash; for indirect-mode FIFO transfer, interrupts and DMA, read it together with the “Multi-line serial peripheral interface (xSPI)” chapter of the user manual.

5.33.1 Related files

Relative path Purpose
firmware/n32h49x_std_periph_driver/inc/n32h49x_xspi.h Defines macros for frame format, transfer mode, FIFO thresholds, interrupts and DMA selection plus the XSPI_InitType structure, and declares 34 public functions
firmware/n32h49x_std_periph_driver/src/n32h49x_xspi.c Implements the 34 functions: reset and initialization, transfer type and wait cycles, FIFO thresholds and data count, data transfer and status flags, interrupt and DMA configuration
projects/n32h49x_EVAL/examples/XSPI/ XSPI example root directory, containing the XSPI_DUALQUAD, XSPI_QUAD and XSPI_QUAD_DMA examples
projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD/ Directory layout of this example: MDK-ARM/, EWARM/, inc/, src/, readme.txt
projects/n32h49x_EVAL/bsp/ Common board files referenced by this example: serial log functions

5.33.2 API reference

Search API34 functions

The following 34 public functions are grouped into 7 sets in the declaration order of n32h49x_xspi.h; each entry gives a summary and the comment text just above the function in n32h49x_xspi.c.

Reset and initialization

XSPI_DeInit, XSPI_Init, XSPI_StructInit, XSPI_Cmd, XSPI_XIP_Cmd

Transfer type and wait cycles

XSPI_SetTransType, XSPI_SetWaitCycles

FIFO thresholds and data count

XSPI_SetRXFIFOLevel, XSPI_SetTXFIFOLevel, XSPI_SetTXFIFOStartLevel, XSPI_GetRXFIFOLevel, XSPI_GetTXFIFOLevel, XSPI_ReadRxFifoNum, XSPI_ReadTxFifoNum

Data transfer and status flags

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

Interrupts

XSPI_GetINTStatus, XSPI_ClearITBit, XSPI_ConfigInt

DMA

XSPI_ConfigDMATxLevel, XSPI_ConfigDMARxLevel, XSPI_EnableDMA

FIFO data movement

XSPI_ClrFifo, XSPI_GetFifoData, XSPI_SendAndGetWords, XSPI_SendWordAndGetWords

void XSPI_DeInit(void)Deinitializes the XSPI peripheral registers to its default reset values.
Source comment
name    XSPI_DeInit.
fun     Deinitializes the XSPI peripheral registers to its default reset values.
return  none
void XSPI_Init(XSPI_InitType* XSPI_InitStruct)Merge configuration from the buffer of XSPI para struct, then write it into related registers.
Source comment
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

Use note: The name field in the source comment is written as XSPIInitConfig. and differs from the function name XSPI_Init; call it by the function name.

void XSPI_StructInit(XSPI_InitType* XSPI_InitStruct)Fills each XSPI_InitStruct member with its default value.
Source comment
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)Control XSPI function switch.
Source comment
name    XSPI_Cmd.
fun     Control XSPI function switch.
param   cmd
          - ENABLE
          - DISABLE
return  none
void XSPI_XIP_Cmd(FunctionalState cmd)Control XSPI XIP function switch.
Source comment
name    XSPI_XIP_Cmd.
fun     Control XSPI XIP function switch.
param   cmd
          - ENABLE
          - DISABLE
return  none
void XSPI_SetTransType(uint32_t TransType)Set the format of address and instruction sending (1/2/4/8 wire mode)
Source comment
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)Set the number of empty instruction cycles to wait
Source comment
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)Set Rx fifo transmission threshold, trigger full interrupt threshold
Source comment
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)Set the Tx fifo transmission threshold and trigger the interrupt threshold
Source comment
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)Set Tx fifo start transmission threshold
Source comment
name    XSPI_SetTXFIFOStartLevel.
fun     Set Tx fifo start transmission threshold
param   fifo_len:
          - 0x0-0xF
return  none
uint8_t XSPI_GetRXFIFOLevel(void)Get the amount of data in the Rx fifo
Source comment
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)Get the amount of data in the Tx fifo
Source comment
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)Get Pointer of XSPI DAT0 register.
Source comment
name    XSPIGetDataPointer.
fun     Get Pointer of XSPI DAT0 register.
return  The pointer of XSPI DAT0 register.

Use note: The name field in the source comment is written as XSPIGetDataPointer. and differs from the function name XSPI_GetDataPointer; call it by the function name.

uint32_t XSPI_ReadRxFifoNum(void)Read value from XSPI RXFN register which shows the number of the data from receive fifo.
Source comment
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)Read value from XSPI TXFN register which shows the number of the data from tx fifo.
Source comment
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)Write one data direct to XSPI DAT0 register to send.
Source comment
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)Read one data from XSPI DAT0 register.
Source comment
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)Checks whether the specified XSPI flag is set or not.
Source comment
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)Checks whether the specified XSPI interrupt has occurred or not.
Source comment
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)Checks whether the specified XSPI interrupt has occurred or not.
Source comment
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)Enables or disables the specified XSPI interrupts.
Source comment
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)Configuration of XSPI DMA Tx Level.
Source comment
name    XSPI_ConfigDMATxLevel.
fun     Configuration of XSPI DMA Tx Level.
param   TxDataLevel(transmit data):
          - 0~0x1F
return  none.
void XSPI_ConfigDMARxLevel(uint32_t RxDataLevel)Configuration of XSPI DMA Rx Level.
Source comment
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)Enables or disables the XSPI’s DMA interface.
Source comment
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)Get XSPI status,busy or not.
Source comment
name    XSPI_GetBusyStatus.
fun     Get XSPI status,busy or not.
return  SET:XSPI busy;
        RESET:XSPI idle.
FlagStatus XSPI_GetTxDataBusyStatus(void)Check transmit fifo full or not.
Source comment
name    XSPI_GetTxDataBusyStatus.
fun     Check transmit fifo full or not.
return  SET: Transmit fifo full;
        RESET: Transmit fifo not full.
FlagStatus XSPI_GetTxDataEmptyStatus(void)Check transmit fifo empty or not.
Source comment
name    XSPI_GetTxDataEmptyStatus.
fun     Check transmit fifo empty or not.
return  SET: Transmit fifo empty;
        RESET: Transmit fifo not empty.
FlagStatus XSPI_GetRxHaveDataStatus(void)Check receive fifo have data or not.
Source comment
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)Check receive fifo full or not.
Source comment
name    XSPI_GetRxDataFullStatus.
fun     Check receive fifo full or not.
return  SET: Receive fifo full;
        RESET: Receive fifo not full.
FlagStatus XSPI_GetDataConflictErrorStatus(void)Check data conflict error or not.
Source comment
name    XSPI_GetDataConflictErrorStatus.
fun     Check data conflict error or not.
return  SET: Data conflict error;
        RESET: No data conflict error.
void XSPI_ClrFifo(void)Read DAT0 register to clear fifo.
Source comment
name    ClrFifo.
fun     Read DAT0 register to clear fifo.
return  none.

Use note: The name field in the source comment is written as ClrFifo. and differs from the function name XSPI_ClrFifo; call it by the function name.

uint32_t XSPI_GetFifoData(uint32_t* pData, uint32_t Len)Get data from fifo.
Source comment
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.

Use note: The name field in the source comment is written as GetFifoData and differs from the function name XSPI_GetFifoData; call it by the function name.

void XSPI_SendAndGetWords(uint32_t* pSrcData, uint32_t* pDstData, uint32_t cnt)Send words out from source data buffer and get returned datas into destination data buffer.
Source comment
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.

Use note: The name field in the source comment is written as XSPISendAndGetWords. and differs from the function name XSPI_SendAndGetWords; call it by the function name.

uint32_t XSPI_SendWordAndGetWords(uint32_t WrData, uint32_t* pRdData, uint8_t LastRd)Send one word data and get returned words into destination data buffer.
Source comment
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.

Use note: The name field in the source comment is written as XSPISendWordAndGetWords. and differs from the function name XSPI_SendWordAndGetWords; call it by the function name.

5.33.3 Demo descriptions

This section describes the 3 XSPI examples: XSPI_DUALQUAD combines two external Flash devices into an octal data path by toggling the chip select, XSPI_QUAD reads and writes a single external Flash in quad mode, and XSPI_QUAD_DMA adds DMA data movement on top of the quad mode.

5.33.3.1 XSPI_DUALQUAD dual chip-select octal read and write of external Flash

Example directory: projects/n32h49x_EVAL/examples/XSPI/XSPI_DUALQUAD/

Initialize the log, clocks and GPIO→Configure XSPI in standard mode and enable quad on each Flash in turn→Erase each Flash and verify the readback→Toggle the chip select and write data in octal format→Read back in octal format and compare the result

Item Source analysis
Function Combines two external quad Flash devices into an octal data path by toggling the chip select;
first erases each Flash and verifies the readback in standard mode, then writes and reads back in octal format.
Source files 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: length and address macros;
readme.txt, MDK-ARM/, EWARM/: notes and project files.
Key configuration Clock: RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE) plus GPIO and AFIO clocks;
Frame format: STANDRD_SPI_FORMAT in the register stage and OCTAL_SPI_FORMAT in the data stage;
Chip select: AFIO_Config_XSPI_DualQuadMode selects the first or the second Flash;
Data: DFS_32_BIT with CTRL1_NDF_63 and CTRL1_NDF_255 control the frame size and count.
Program and data path main configures the clocks and pins and then enters standard mode;
inside the loop it selects each Flash in turn, writes enable, sets QE, erases a 32KB block and verifies the readback is all 0xFF;
after filling XSPI_Wbuffer it switches to octal format to write and read back the data;
main compares XSPI_Rbuffer with XSPI_Wbuffer and prints the conclusion.
Main APIs XSPI_DeInit, XSPI_Cmd, XSPI_SendData, XSPI_ReceiveData, XSPI_GetFlagStatus
Verification The UART prints “Spi_flash write and read demo end - dual quad mode” when the flow ends normally;
no “FALSH WR fail” from the compare loop means the written and read-back data match.
Use note The dual chip select is toggled through AFIO and should be adapted to the chip-select pins of the two Flash devices on the target board when porting;
the register stage and the data stage use different frame formats, so XSPI_Configuration must be called again when switching;
the jumper caps on the full-featured board must be in place before running.
Core-code walkthrough and porting

The example combines two external quad Flash devices into an octal data path by toggling the chip select, erases and verifies each device first, then writes and reads back.

Data path: RCC_Configuration and GPIO_Configuration set up the clocks and pins → XSPI_Configuration enters standard mode → AFIO_Config_XSPI_DualQuadMode selects the first or the second Flash → write enable, set QE, erase and verify the readback → switch to octal format to write and read back XSPI_Wbuffer → compare XSPI_Rbuffer with XSPI_Wbuffer

1. Initialize XSPI and select the chip select. main first configures standard mode, then toggles the chip select between the two Flash devices with AFIO_Config_XSPI_DualQuadMode.

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 directly writes registers such as CTRL0, CTRL1 and BAUD to complete the configuration; the two Flash devices are toggled by the AFIO chip select, so each loop iteration only drives the selected one.

2. Set QE to enable quad mode. In standard mode the write enable is issued and bit QE of status register 2 is set so that the Flash supports quad transfer.

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));

Register reads and writes work by issuing the command and address and then polling the status register, and the do-while loop ensures the QE bit is actually set.

3. Verify the readback after erase. Each device is erased block by block into a 32KB area, then read back with the read command and checked to be all 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. Write-enable both Flash devices. Before writing, a write enable command is issued to each Flash in turn and the status register is polled to confirm the write enable bit.

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);
    }

Corresponding source files: src/main.c

5.33.3.2 XSPI_QUAD quad read and write of external Flash

Example directory: projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD/

Initialize the log, clocks and GPIO→Enable quad mode on the external Flash→Erase a sector and write test data→Read back in quad mode and compare with the written data→Erase the whole chip and verify the readback

Item Source analysis
Function Accesses a single external Flash in quad mode;
first sets QE to enable quad, erases a sector and writes data, compares the readback, and finally erases the whole chip and verifies the readback is all 0xFF.
Source files 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_FlashREG_WR, XSPI_FlashWrite, XSPI_FlashRead, sFLASH_QuadEnable, sFLASH_EraseSector, sFLASH_EraseChip, sFLASH_ReadBuffer, sFLASH_WriteBuffer;
inc/main.h, inc/spi_flash.h, inc/xspi_cfg.h: macros and function declarations;
readme.txt, MDK-ARM/, EWARM/: notes and project files.
Key configuration Clock: RCC_EnableAHBPeriphClk(RCC_AHB_PERIPHEN_XSPI, ENABLE);
Pins: NSS0 on PG6, SCK on PF10, IO0/IO1 on PF8/PF9 and IO2/IO3 on PF7/PF6;
Frame format: DFS_08_BIT in the register stage and QUAD_SPI_FORMAT with DFS_32_BIT in the data stage;
Threshold: XSPI_SetTXFIFOStartLevel is set according to the transfer length.
Program and data path main first configures the clocks and pins, then sets QE to enable quad mode;
after filling XSPI_Wbuffer it erases a sector and writes the data;
it reads the data back in quad mode and compares the written and read words with Buffercmp;
it erases the whole chip and verifies the readback is all 0xFFFFFFFF before printing the conclusion.
Main APIs XSPI_DeInit, XSPI_Cmd, XSPI_SetTXFIFOStartLevel, XSPI_SendData, XSPI_GetFlagStatus
Verification The UART prints “Spi_flash write and read demo test success” when the read and write match and the readback after erase is all 0xFF;
otherwise it prints “Spi_flash write and read demo test failed”.
Use note sFLASH_QuadEnable temporarily configures IO2/IO3 as plain outputs to drive the write-protect and hold pins, and restores the alternate function after the bit is set;
more than 16 register read or write data items require DMA transfer instead;
the external Flash and the full-featured board jumper caps must be in place before running.
Core-code walkthrough and porting

The example first sets QE in standard mode to enable quad, then erases a sector, writes data, compares the readback and finally erases the whole chip for verification.

Data path: RCC_Configuration and GPIO_Configuration set up the clocks and pins → sFLASH_QuadEnable sets QE to enable quad → sFLASH_EraseSector erases a sector → sFLASH_WriteBuffer writes XSPI_Wbuffer → sFLASH_ReadBuffer reads back in quad mode → Buffercmp compares the buffers → sFLASH_EraseChip erases the whole chip and verifies the readback is all 0xFFFFFFFF

1. Configure XSPI by writing registers directly. XSPI_Configuration resets the peripheral first and then writes the frame format, transfer mode, frame size, frame count and baud rate into the related registers.

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. Set QE to enable quad mode. sFLASH_QuadEnable first configures IO2/IO3 as plain outputs to drive the write-protect and hold pins, sets bit QE of status register 2, and then restores the alternate function.

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. Quad page write. sFLASH_WritePage writes enable in quad mode, configures the frame format and writes the page data to the Flash, then waits for the write to finish.

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. Quad readback. sFLASH_ReadBuffer sets the transfer mode to receive-only and the frame format to quad, then reads back the requested number of words.

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;
}

Corresponding source files: src/xspi_cfg.c, src/spi_flash.c

5.33.3.3 XSPI_QUAD_DMA quad DMA read and write of external Flash

Example directory: projects/n32h49x_EVAL/examples/XSPI/XSPI_QUAD_DMA/

Initialize the log, clocks, GPIO and DMA→Enable quad mode on the external Flash→Erase a sector and write test data→Read back with DMA and compare with the written data→Print the read and write result

Item Source analysis
Function Follows the same flow as the quad example but moves data with DMA;
data is moved between XSPI->DAT0 and the buffers to improve efficiency for large transfers.
Source files 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 (and other functions with DMA enable and wait);
inc/main.h, inc/spi_flash.h, inc/xspi_cfg.h: macros and function declarations;
readme.txt, MDK-ARM/, EWARM/: notes and project files.
Key configuration DMA channels: transmit uses DMA1_CH1 with DMA_REMAP_XSPI_TX and receive uses DMA1_CH2 with DMA_REMAP_XSPI_RX;
DMA parameters: WORD data width, memory increment and burst enabled (almost mode, length 8);
XSPI: XSPI_ConfigDMATxLevel, XSPI_ConfigDMARxLevel and XSPI_EnableDMA set the thresholds and requests.
Program and data path main configures the clocks and pins and sets QE, then erases a sector and writes XSPI_Wbuffer;
XSPI_FlashWrite disables XSPI, sets the DMA thresholds and enables the transmit request before moving the data with DMA_Configuration;
XSPI_FlashRead enables the receive request and moves XSPI->DAT0 into XSPI_Rbuffer with DMA;
main compares the readback with the written data and prints the conclusion.
Main APIs XSPI_EnableDMA, XSPI_ConfigDMATxLevel, XSPI_ConfigDMARxLevel, XSPI_SendData, XSPI_GetFlagStatus
Verification The UART prints “Spi_flash write and read demo test success” when the DMA write and readback match;
otherwise it prints “Spi_flash write and read demo test failed”.
Use note The XSPI DMA thresholds and enable must be configured while XSPI is disabled, so the example calls XSPI_Cmd(DISABLE) first;
transmit waits for DMA_FLAG_TC1 and receive waits for DMA_FLAG_TC2, and the flags should be checked against the channel when porting;
the DMA request mapping is fixed to DMA_REMAP_XSPI_TX for transmit and DMA_REMAP_XSPI_RX for receive.
Core-code walkthrough and porting

The example hands data movement to DMA on top of quad mode, and the DMA path connects XSPI->DAT0 with the peripheral data stream through the request mapping.

Data path: DMA_Configuration selects the channel and request mapping for transmit or receive → XSPI_FlashWrite disables XSPI, sets the thresholds and enables the transmit request → DMA writes the buffer data into XSPI->DAT0 → XSPI_FlashRead enables the receive request → DMA reads XSPI->DAT0 into the buffer → wait for the transfer complete flag

1. DMA channel and request mapping. DMA_Configuration selects DMA1_CH1 or DMA1_CH2 according to the transmit or receive direction and sets the matching XSPI request mapping.

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 transmit. After disabling XSPI, XSPI_FlashWrite sets the DMA thresholds and enables the transmit request, then starts the DMA transfer and waits for transmit and transfer completion.

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 receive. XSPI_FlashRead enables the receive request, starts a DMA transfer that reads XSPI->DAT0 into the buffer, waits for the transfer complete flag and then disables 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);

Corresponding source files: src/xspi_cfg.c, src/spi_flash.c

5.33.4 Notes and troubleshooting

Scenario Check & action Source
Command phases Every command has the Instruction, Address, Mode bits, Wait cycles and Data phases;
any phase can be skipped, but at least one of Instruction, Address, Mode bits and Data must be kept.
User manual
Mode bits The Mode bits phase is used only in XIP mode;
once enabled, mode bits are inserted after the address phase with a width of 2, 4, 8 or 16.
User manual
DDR baud rate In DDR mode the baud rate value should be a multiple of 4. User manual
XIP frame format XIP operation supports only Dual, Quad and Octal mode, and XSPI_CTRL0.SPIFRF must not be configured as 0. User manual
Tx and Rx mode Tx and Rx mode can be used only in standard SPI mode (XSPI_CTRL0.SPIFRF equal to 00). User manual
EEPROM read mode EEPROM read mode can be used only in standard SPI mode (XSPI_CTRL0.SPIFRF equal to 00), and the number of bytes to read is specified in XSPI_CTRL1.NDF. User manual
Instruction and address One instruction occupies one FIFO location while the address may occupy several FIFO locations, and both the instruction and the address must be written to XSPI_DATx registers. User manual
XIP receive FIFO overflow During XIP transfer an RX FIFO that is too shallow may overflow and corrupt data, so after detecting the RX FIFO overflow the software must retry the data transfer. User manual
Nations Technologies DevKit Docs

Datasheets, SDK, driver APIs and demo guides for Nations Technologies MCU development kits, organized by chip series.

© 2026 Nations Technologies Inc. All rights reserved.粤ICP备11069485号This site uses cookie-free anonymous analytics.