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
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.
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.
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.
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.
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.
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)
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
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
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
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
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
/* 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.
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.
/*==========================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.
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.
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.
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.
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.
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.
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.
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.
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 |