5.16 SPI 使用说明

本章说明 N32G033 标准外设库中 SPI 驱动的文件组成、22 个公开函数,以及 FullDuplex_SoftNSS、Simplex_Interrupt、SPI_CRC、SPI_DMA、SPI_FLASH 5 个示例。时钟极性相位、NSS 管理与 CRC 请配合用户手册的“SPI”章节阅读;芯片已知问题以勘误手册为准。

5.16.1 相关文件

相对路径 作用
firmware/n32g033_std_periph_driver/inc/n32g033_spi.h 定义 SPI_InitType 结构体与数据方向、主从模式、数据长度、时钟极性相位、NSS、波特率预分频、CRC 等宏,并按复位与初始化、中断与 DMA、NSS 与数据长度、CRC 与状态等区段声明 22 个公开函数
firmware/n32g033_std_periph_driver/src/n32g033_spi.c 实现上述 22 个函数:SPI 复位与初始化、数据收发、NSS 与数据长度配置、CRC 计算与传输、状态标志与中断处理
projects/n32g033_EVAL/examples/SPI/ SPI 示例根目录,含 FullDuplex_SoftNSS、Simplex_Interrupt、SPI_CRC、SPI_DMA、SPI_FLASH 5 个示例
projects/n32g033_EVAL/examples/SPI/SPI_FLASH/ 该示例的工程目录组成:MDK-ARM/、EWARM/、inc/、src/、readme.txt,inc/ 与 src/ 下另有 spi_flash.h、spi_flash.c
projects/n32g033_EVAL/bsp/ 示例共用的板级支持文件:delay.h 的 SysTick 延时与 log.h 的串口日志接口

5.16.2 API 参考

搜索 API共 22 个函数

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

复位与初始化

SPI_DeInit、SPI_Init、SPI_InitStruct、SPI_Enable

中断、DMA 与数据收发

SPI_EnableInt、SPI_EnableDma、SPI_TransmitData、SPI_ReceiveData

NSS 与数据长度配置

SPI_SetNssLevel、SPI_SSOutputEnable、SPI_ConfigDataLen

CRC 与双向模式

SPI_TransmitCrcNext、SPI_EnableCalculateCrc、SPI_GetCRCDat、SPI_GetCRCPoly、SPI_ConfigBidirectionalMode

状态与标志

SPI_GetStatus、SPI_ClrCRCErrFlag、SPI_GetIntStatus、SPI_ClrITPendingBit

主机时钟延时与 CRC 失效控制

SPI_Configdelaytime、SPI_NSSFailCRCEnable

void SPI_DeInit(SPI_Module* SPIx)复位 SPI 寄存器。
源码注释
name    SPI_DeInit.
fun     Reset the SPI registers.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
return  none
void SPI_Init(SPI_Module* SPIx, SPI_InitType* SPI_InitStruct)根据 SPI_InitStruct 初始化 SPI。
源码注释
name    SPI_Init.
fun     Initializes the SPI according to SPI_InitStruct.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_InitStruct (The input parameters must be the following values):
          - DataDirection
            - SPI_DIR_DOUBLELINE_FULLDUPLEX
            - SPI_DIR_DOUBLELINE_RONLY
            - SPI_DIR_SINGLELINE_RX
            - SPI_DIR_SINGLELINE_TX
          - SpiMode
            - SPI_MODE_MASTER
            - SPI_MODE_SLAVE
          - DataLen
            - SPI_DATA_SIZE_16BITS
            - SPI_DATA_SIZE_8BITS
          - CLKPOL
            - SPI_CLKPOL_LOW
            - SPI_CLKPOL_HIGH
          - CLKPHA
            - SPI_CLKPHA_FIRST_EDGE
            - SPI_CLKPHA_SECOND_EDGE
          - NSS
            - SPI_NSS_SOFT
            - SPI_NSS_HARD
          - BaudRatePres
            - SPI_BR_PRESCALER_2
            - SPI_BR_PRESCALER_4
            - SPI_BR_PRESCALER_8
            - SPI_BR_PRESCALER_16
            - SPI_BR_PRESCALER_32
            - SPI_BR_PRESCALER_64
            - SPI_BR_PRESCALER_128
            - SPI_BR_PRESCALER_256
          - FirstBit
            - SPI_FB_MSB
            - SPI_FB_LSB
          - CRCPoly
            - 0x01 ~ 0xffff
return  none
void SPI_InitStruct(SPI_InitType* SPI_StructInit)用默认值填充 SPI_InitStruct 的各个成员。
源码注释
name    SPI_InitStruct.
fun     Fills each SPI_InitStruct member with its default value.
param   SPI_InitStruct (The input parameters must be the following values):
          - DataDirection
          - SpiMode
          - DataLen
          - CLKPOL
          - CLKPHA
          - NSS
          - BaudRatePres
          - FirstBit
return  none
void SPI_Enable(SPI_Module* SPIx, FunctionalState Cmd)使能或关闭指定的 SPI 外设。
源码注释
name    SPI_Enable.
fun     Enables or disables the specified SPI peripheral.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void SPI_EnableInt(SPI_Module* SPIx, uint32_t SPI_IT, FunctionalState Cmd)使能或关闭 SPI 中断。
源码注释
name    SPI_EnableInt.
fun     Enable/disable SPI interrupts.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_IT (The input parameters must be the following values):
          - SPI_INT_TE
          - SPI_INT_RNE
          - SPI_INT_ERR
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void SPI_EnableDma(SPI_Module* SPIx, uint32_t SPI_DMAReq, FunctionalState Cmd)使能 SPI 的 DMA 传输。
源码注释
name    SPI_EnableDma.
fun     Enable SPI DMA transfer.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_DMAReq (The input parameters must be the following values):
          - SPI_DMA_TX
          - SPI_DMA_RX
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void SPI_TransmitData(SPI_Module* SPIx, uint16_t Data)通过 SPI 外设发送一个数据。
源码注释
name    SPI_TransmitData.
fun     Transmits a Data through the SPI peripheral.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   Data: data to be transmitted
return  none
uint16_t SPI_ReceiveData(SPI_Module* SPIx)从 SPI_DAT 寄存器读取 SPI 数据。
源码注释
name    SPI_ReceiveData.
fun     Get SPI data from SPI_DAT register.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
return  The data in the SPI_DAT register
void SPI_SetNssLevel(SPI_Module* SPIx, uint32_t SPI_NSSInternalSoft)用软件配置所选 SPI 的 NSS 引脚。
源码注释
name    SPI_SetNssLevel.
fun     Configures internally by software the NSS pin for the selected SPI.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_NSSInternalSoft (The input parameters must be the following values):
          - SPI_NSS_HIGH Set NSS pin internally
          - SPI_NSS_LOW  Reset NSS pin internally
return  none
void SPI_SSOutputEnable(SPI_Module* SPIx, FunctionalState Cmd)用软件配置所选 SPI 的 NSS 引脚。
源码注释
name    SPI_SSOutputEnable.
fun     Configures internally by software the NSS pin for the selected SPI.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
void SPI_ConfigDataLen(SPI_Module* SPIx, uint32_t DataLen)配置所选 SPI 的数据长度。
源码注释
name    SPI_ConfigDataLen.
fun     Configures the data size for the selected SPI.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   DataLen (The input parameters must be the following values):
          - SPI_DATA_SIZE_16BITS
          - SPI_DATA_SIZE_8BITS
return  none
void SPI_TransmitCrcNext(SPI_Module* SPIx)发送 SPIx 的 CRC 值。
源码注释
name    SPI_TransmitCrcNext.
fun     Transmit the SPIx CRC value.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
return  none
void SPI_EnableCalculateCrc(SPI_Module* SPIx, FunctionalState Cmd)使能或关闭已传输字节的 CRC 值计算。
源码注释
name    SPI_EnableCalculateCrc.
fun     Enables or disables the CRC value calculation of the transferred bytes.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none
uint32_t SPI_GetCRCDat(SPI_Module* SPIx, uint8_t SPI_CRC)从 SPI_CRCTDAT/SPI_CRCRDAT 寄存器读取 SPI CRC 数据。
源码注释
name    SPI_GetCRCDat.
fun     Get SPI CRC data from SPI_CRCTDAT/SPI_CRCRDAT register.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_CRC (The input parameters must be the following values):
          - SPI_CRC_TX
          - SPI_CRC_RX
return  Tx/Rx CRC register value.
uint32_t SPI_GetCRCPoly(SPI_Module* SPIx)从 SPI_CRC_POLY 寄存器读取 CRC 多项式。
源码注释
name    SPI_GetCRCPoly.
fun     Get CRC Polynomial from SPI_CRC_POLY register.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
return  The CRC Polynomial register value.
void SPI_ConfigBidirectionalMode(SPI_Module* SPIx, uint32_t DataDirection)在双向模式下选择指定 SPI 的数据传输方向。
源码注释
name    SPI_ConfigBidirectionalMode.
fun     Selects the data transfer direction in bi-directional mode for the specified SPI.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   DataDirection (The input parameters must be the following values):
          - SPI_BIDIRECTION_RX
          - SPI_BIDIRECTION_TX
return  none
FlagStatus SPI_GetStatus(SPI_Module* SPIx, uint32_t SPI_FLAG)获取 SPI 标志状态。
源码注释
name    SPI_GetStatus.
fun     Get SPI flag status.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_FLAG (The input parameters must be the following values):
          - SPI_TE_FLAG
          - SPI_RNE_FLAG
          - SPI_CRCERR_FLAG
          - SPI_MODERR_FLAG
          - SPI_OVER_FLAG
          - SPI_BUSY_FLAG
return  SET or RESET
void SPI_ClrCRCErrFlag(SPI_Module* SPIx, uint32_t SPI_FLAG)清除 SPI 标志状态。
源码注释
name    SPI_ClrCRCErrFlag.
fun     Clear SPI flag status.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_FLAG (The input parameters must be the following values):
          - SPI_CRCERR_FLAG
return  none
note
        - OVER (OverRun error) flag is cleared by software sequence: a read
          operation to SPI_DAT register (SPI_ReceiveData()) followed by a read
          operation to SPI_STS register (SPI_GetStatus()).
        - UNDER (UnderRun error) flag is cleared by a read operation to
          SPI_STS register (SPI_GetStatus()).
        - MODERR (Mode Fault) flag is cleared by software sequence: a read/write
          operation to SPI_STS register (SPI_GetStatus()) followed by a
          write operation to SPI_CTRL1 register (SPI_Enable() to enable the SPI).
INTStatus SPI_GetIntStatus(SPI_Module* SPIx, uint32_t SPI_IT)获取 SPI 中断标志状态。
源码注释
name    SPI_GetIntStatus.
fun     Get SPI interrupt flag status.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_IT (The input parameters must be the following values):
          - SPI_INT_FLAG_RNE
          - SPI_INT_FLAG_TE
          - SPI_INT_FLAG_CRCERR
          - SPI_INT_FLAG_MODERR
          - SPI_INT_FLAG_OVER
          - SPI_INT_FLAG_ERR
return  SET or RESET
void SPI_ClrITPendingBit(SPI_Module* SPIx, uint32_t SPI_FLAG)清除 SPI 标志状态。
源码注释
name    SPI_ClrITPendingBit.
fun     Clear SPI flag status.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   SPI_FLAG (The input parameters must be the following values):
          - SPI_INT_FLAG_CRCERR
return  none
note
        - OVER (OverRun error) flag is cleared by software sequence: a read
          operation to SPI_DAT register (SPI_ReceiveData()) followed by a read
          operation to SPI_STS register (SPI_GetStatus()).
        - UNDER (UnderRun error) flag is cleared by a read operation to
          SPI_STS register (SPI_GetStatus()).
        - MODERR (Mode Fault) flag is cleared by software sequence: a read/write
          operation to SPI_STS register (SPI_GetStatus()) followed by a
          write operation to SPI_CTRL1 register (SPI_Enable() to enable the SPI).
void SPI_Configdelaytime(SPI_Module* SPIx,uint32_t DelayTime)配置 SPI 主机时钟延时时间。
源码注释
name    SPI_Configdelaytime.
fun     SPI Host Clock Delay Time Configuration.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   DelayTime (The input parameters must be the following values):
          - 0x00 ~ 0x0f  delay DelayTime/2 PCLK2
return  The CRC Polynomial register value.
void SPI_NSSFailCRCEnable(SPI_Module* SPIx,FunctionalState Cmd)NSS 失效时 CRC 计算停止或继续。
源码注释
name    SPI_NSSFailCRCEnable.
fun     NSS failure, CRC calculation stops or continues.
param   SPIx (The input parameters must be the following values):
          - SPI1
          - SPI2
param   Cmd (The input parameters must be the following values):
          - ENABLE
          - DISABLE
return  none

5.16.3 Demo 示例说明

本节说明 SPI 的 5 个示例:FullDuplex_SoftNSS 用软件 NSS 做全双工互相收发并交换主从,Simplex_Interrupt 用单线模式与收发中断完成数据搬运,SPI_CRC 用 16 位帧校验收发数据,SPI_DMA 用 DMA 搬运主发从收的数据,SPI_FLASH 读写并擦除串行 FLASH。

5.16.3.1 FullDuplex_SoftNSS 软件 NSS 全双工收发

工程目录: projects/n32g033_EVAL/examples/SPI/FullDuplex_SoftNSS/

使能 GPIO 与 SPI 时钟→配置 SPI 引脚→把两路 SPI 分别设为主与从→全双工互相收发并比对→交换主从后再次收发并比对

项目 源码解读
功能 用两个 SPI 实例一主一从做全双工互发,再交换主从角色重复一次,各自比对收发数据。
源码组成 src/main.c 含双实例初始化、收发流程与比对函数;
src/n32g033_it.c 与 inc/n32g033_it.h 提供中断入口;
inc/main.h 定义两个实例的引脚与时钟宏;
readme.txt 给出配置与测试步骤;
工程文件在 MDK-ARM/ 与 EWARM/。
关键配置 引脚:主从两路 SCK、MISO、MOSI 均复用推挽;
模式:8 位数据、全双工、软件 NSS、从机第二位边沿采样;
位序:低位在前;
预分频:8 分频;
时钟极性:空闲低电平。
程序与数据路径 main → RCC_Configuration 开时钟 → GPIO_Configuration 配引脚 → SPI_Init 配一主一从 → 主循环全双工互换数据 → Buffercmp 比对 → 交换主从后再来一轮。
主要 API SPI_InitStruct、SPI_Init、SPI_Enable、SPI_TransmitData、SPI_ReceiveData、SPI_GetStatus
验证方法 编译下载后复位运行,串口分别打印两轮的主从测试结果;
两轮都通过说明全双工与角色互换都正常。
使用提示 两路 SPI 的 SCK、MISO、MOSI 需交叉相连,主设备片选由软件控制;
开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1,硬件基于评估板 N32G033K8Q7-1_STB V1.0;
系统时钟 64 MHz。
核心代码解读与移植

示例先用一套参数配好一主一从,再通过软件 NSS 与轮询收发完成全双工互换。

数据路径: SPI_InitStruct 填公共参数 → SPI_Init 先后配主从 → SPI_Enable 使能两路 → 主循环经发送与接收寄存器逐字节互换 → Buffercmp 比对 → 交换主从后再一轮

1. 同一套参数先配主机再配从机,只改主从模式一项。

src/main.csrc/main.c · main
    SPI_InitStruct(&SPI_InitStructure);
    SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
    SPI_InitStructure.SpiMode       = SPI_MODE_MASTER;
    SPI_InitStructure.DataLen       = SPI_DATA_SIZE_8BITS;
    SPI_InitStructure.CLKPOL        = SPI_CLKPOL_LOW;
    SPI_InitStructure.CLKPHA        = SPI_CLKPHA_SECOND_EDGE;
    SPI_InitStructure.NSS           = SPI_NSS_SOFT;
    SPI_InitStructure.BaudRatePres  = SPI_BR_PRESCALER_8;
    SPI_InitStructure.FirstBit      = SPI_FB_LSB;
    SPI_InitStructure.CRCPoly       = 7;
    SPI_Init(SPIy, &SPI_InitStructure);

    /* SPIz configuration */
    SPI_InitStructure.SpiMode       = SPI_MODE_SLAVE;
    SPI_Init(SPIz, &SPI_InitStructure);

两路共用参数便于保持时钟极性相位与位序一致,改参数时两侧同步。

2. 全双工收发:等发送空后写入,等接收非空后读回。

src/main.csrc/main.c · main
    while (TxIdx < BufferSize)
    {
        /* Wait for SPIy Tx buffer empty */
        while (SPI_GetStatus(SPIy, SPI_TE_FLAG) == RESET)
            ;
        /* Send SPIz data */
        SPI_TransmitData(SPIz, SPIz_Buffer_Tx[TxIdx]);
        /* Send SPIy data */
        SPI_TransmitData(SPIy, SPIy_Buffer_Tx[TxIdx++]);
        /* Wait for SPIz data reception */
        while (SPI_GetStatus(SPIz, SPI_RNE_FLAG) == RESET)
            ;
        /* Read SPIz received data */
        SPIz_Buffer_Rx[RxIdx] = SPI_ReceiveData(SPIz);
        /* Wait for SPIy data reception */
        while (SPI_GetStatus(SPIy, SPI_RNE_FLAG) == RESET)
            ;
        /* Read SPIy received data */
        SPIy_Buffer_Rx[RxIdx++] = SPI_ReceiveData(SPIy);
    }

收发时序要对齐,先把两侧数据写入再读回,避免读写顺序错乱。

3. 交换主从角色后重新配置,再跑一遍收发。

src/main.csrc/main.c · main
    /* SPIy Re-configuration */
    SPI_InitStructure.SpiMode = SPI_MODE_SLAVE;
    SPI_Init(SPIy, &SPI_InitStructure);

    /* SPIz Re-configuration */
    SPI_InitStructure.SpiMode = SPI_MODE_MASTER;
    SPI_Init(SPIz, &SPI_InitStructure);

    /* Reset TxIdx, RxIdx indexes and receive tables values */
    TxIdx = 0;
    RxIdx = 0;
    for (k = 0; k < BufferSize; k++)
        SPIz_Buffer_Rx[k] = 0;
    for (k = 0; k < BufferSize; k++)
        SPIy_Buffer_Rx[k] = 0;

改模式前先关闭对应 SPI,重新配置后再使能,避免通信中改配置。

4. 时钟与引脚:开两路 SPI 时钟并配置引脚复用。

src/main.csrc/main.c · RCC_Configuration
void RCC_Configuration(void)
{
    /* Enable peripheral clocks --------------------------------------------------*/
    /* GPIO clock enable */
    RCC_EnableAPBPeriphClk(RCC_APB_PERIPH_GPIO, ENABLE);

    /* SPI Periph clock enable */
    RCC_EnableAPBPeriphClk(SPIy_CLK | SPIz_CLK, ENABLE);
}

两路 SPI 挂在各自总线上,移植到其他引脚时同步修改时钟与复用宏。

对应源码: src/main.c、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_spi.h

5.16.3.2 Simplex_Interrupt 单线中断收发

工程目录: projects/n32g033_EVAL/examples/SPI/Simplex_Interrupt/

使能 GPIO 与 SPI 时钟→配置引脚与中断优先级→主机配单线发送、从机配单线接收→使能收发中断并启动→主循环等待接收完成并比对

项目 源码解读
功能 主机用单线发送、从机用单线接收,主机侧发送中断补数据,从机侧接收中断取数据。
源码组成 src/main.c 含双实例初始化、NVIC 配置与比对函数;
src/n32g033_it.c 与 inc/n32g033_it.h 提供两路中断服务函数;
inc/main.h 定义两个实例的引脚、中断号线与缓冲区;
readme.txt 给出配置与测试步骤;
工程文件在 MDK-ARM/ 与 EWARM/。
关键配置 引脚:主机 SCK 接 PB3、MOSI 接 PB5,从机 SCK 接 PB0、MISO 接 PA12;
模式:8 位数据、单线、软件 NSS、从机第二位边沿采样;
传输中断使能;
时钟极性:空闲低电平。
程序与数据路径 main → 使能两路的一线收发中断 → 从机接收中断逐字节取数、主机发送中断逐字节补数 → 主循环等待接收计数达到长度 → Buffercmp 比对。
主要 API SPI_InitStruct、SPI_Init、SPI_Enable、SPI_EnableInt、SPI_TransmitData、SPI_ReceiveData、SPI_GetIntStatus、SPI_GetStatus
验证方法 编译下载后复位运行,主机侧数据发完后从机侧接收计数达到长度即完成;
串口打印比对一致即为通过。
使用提示 单线模式下数据线在主机端为 MOSI、在从机端为 MISO,两线需直接连接;
开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1,硬件基于评估板 N32G033K8Q7-1_STB V1.0;
系统时钟 64 MHz。
核心代码解读与移植

示例把数据搬运交给收发中断,主循环只等到接收计数达到长度为止。

数据路径: 使能两路收发中断 → 主机发送寄存器空时经中断补数 → 从机接收寄存器非空时经中断取数 → 接收计数达到长度 → 主循环 Buffercmp 比对

1. 两个实例分别按单线发送与单线接收配置,并各自使能收发中断。

src/main.csrc/main.c · main
    SPI_InitStruct(&SPI_InitStructure);
    SPI_InitStructure.DataDirection = SPI_DIR_SINGLELINE_TX;
    SPI_InitStructure.SpiMode       = SPI_MODE_MASTER;
    SPI_InitStructure.DataLen       = SPI_DATA_SIZE_8BITS;
    SPI_InitStructure.CLKPOL        = SPI_CLKPOL_LOW;
    SPI_InitStructure.CLKPHA        = SPI_CLKPHA_SECOND_EDGE;
    SPI_InitStructure.NSS           = SPI_NSS_SOFT;
    SPI_InitStructure.BaudRatePres  = SPI_BR_PRESCALER_8;
    SPI_InitStructure.FirstBit      = SPI_FB_MSB;
    SPI_InitStructure.CRCPoly       = 7;
    SPI_Init(SPI_MASTER, &SPI_InitStructure);

    /* SPI_SLAVE configuration */
    SPI_InitStructure.DataDirection = SPI_DIR_SINGLELINE_RX;
    SPI_InitStructure.SpiMode       = SPI_MODE_SLAVE;
    SPI_Init(SPI_SLAVE, &SPI_InitStructure);

    /* Enable SPI_MASTER TXE interrupt */
    SPI_EnableInt(SPI_MASTER, SPI_INT_TE, ENABLE);
    /* Enable SPI_SLAVE RXNE interrupt */
    SPI_EnableInt(SPI_SLAVE, SPI_INT_RNE, ENABLE);

    /* Enable SPI_SLAVE */
    SPI_Enable(SPI_SLAVE, ENABLE);
    /* Enable SPI_MASTER */
    SPI_Enable(SPI_MASTER, ENABLE);

单线方向由数据方向参数决定,主机与从机的参数要互为反向。

2. 中断优先级:主机与从机两路分开配置。

src/main.csrc/main.c · NVIC_Configuration
    /* Configure and enable SPI_MASTER interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = SPI_MASTER_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority           = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Configure and enable SPI_SLAVE interrupt */
    NVIC_InitStructure.NVIC_IRQChannel                   = SPI_SLAVE_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority           = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

从机接收中断要及时响应,优先级不宜低于主机发送中断。

3. 主机发送中断:发送寄存器空时写入下一个字节,发完即关闭该中断。

src/n32g033_it.csrc/n32g033_it.c · SPI1_IRQHandler
void SPI1_IRQHandler(void)
{
    if (SPI_GetIntStatus(SPI_MASTER, SPI_INT_FLAG_TE) != RESET)
    {
        /* Send SPI_MASTER data */
        SPI_TransmitData(SPI_MASTER, MASTER_Buffer_Tx[TxIdx++]);

        /* Disable SPI_MASTER TE interrupt */
        if (TxIdx == BufferSize)
        {
            SPI_EnableInt(SPI_MASTER, SPI_INT_TE, DISABLE);
        }
    }
}

发送完成要主动关闭发送中断,避免空转重复进入。

4. 从机接收中断:收到一个字节即存入缓冲区并递增计数。

src/n32g033_it.csrc/n32g033_it.c · SPI2_IRQHandler
void SPI2_IRQHandler(void)
{
    if(SPI_GetIntStatus(SPI_SLAVE, SPI_INT_FLAG_RNE) != RESET)
    {
        /* Store SPI_SLAVE received data */
        SLAVE_Buffer_Rx[RxIdx++] = SPI_ReceiveData(SPI_SLAVE);
    }
}

接收计数会作为完成判据,长度要与发送侧严格一致。

对应源码: src/main.c、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_spi.h

5.16.3.3 SPI_CRC CRC 校验收发

工程目录: projects/n32g033_EVAL/examples/SPI/SPI_CRC/

使能 GPIO 与 SPI 时钟→配置两路 SPI 为 16 位帧→使能两路 CRC 计算→传输数据并在末字节触发 CRC→读取 CRC 并检查错误标志

项目 源码解读
功能 用 16 位数据帧在主从之间传输,逐字节发送后在末字节触发 CRC,再核对接收 CRC 与错误标志。
源码组成 src/main.c 含双实例初始化、收发流程、CRC 计算与比对;
src/n32g033_it.c 与 inc/n32g033_it.h 提供中断入口;
inc/main.h 定义两个实例的引脚、时钟宏与缓冲区;
readme.txt 给出配置与测试步骤;
工程文件在 MDK-ARM/ 与 EWARM/。
关键配置 引脚:SPI1 的 SCK、MISO、MOSI 与 SPI2 对应引脚交叉相连;
模式:16 位数据、全双工、软件 NSS;
位序:高位在前;
预分频:16 分频;
CRC:两路均使能,多项式为 7。
程序与数据路径 main → 两路 SPI_Init 配 16 位帧 → SPI_EnableCalculateCrc 使能 CRC → 主循环逐字发送与接收 → 末字调 SPI_TransmitCrcNext → SPI_GetCRCDat 读取 CRC 并检查错误标志。
主要 API SPI_InitStruct、SPI_Init、SPI_Enable、SPI_EnableCalculateCrc、SPI_TransmitCrcNext、SPI_TransmitData、SPI_ReceiveData、SPI_GetStatus、SPI_GetCRCDat
验证方法 编译下载后复位运行,串口打印收发比对与 CRC 校验结果;
CRC 收发值一致且无错误标志即为通过。
使用提示 16 位帧要求两路数据长度一致,CRC 多项式与使能时机要按手册顺序设置;
开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1,硬件基于评估板 N32G033K8Q7-1_STB V1.0;
系统时钟 64 MHz。
核心代码解读与移植

示例在 16 位帧下传输数据,并在末字触发 CRC,再核对双方 CRC 与错误标志。

数据路径: SPI_Init 配 16 位帧 → SPI_EnableCalculateCrc 使能 CRC → 主循环逐字发送与接收 → 末字 SPI_TransmitCrcNext 触发 CRC → SPI_GetCRCDat 读取本端 CRC → 与对端比较并查错误标志

1. 把数据长度改成 16 位并让两路都使能 CRC 计算。

src/main.csrc/main.c · main
    SPI_InitStruct(&SPI_InitStructure);
    SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
    SPI_InitStructure.SpiMode       = SPI_MODE_MASTER;
    SPI_InitStructure.DataLen       = SPI_DATA_SIZE_16BITS;
    SPI_InitStructure.CLKPOL        = SPI_CLKPOL_LOW;
    SPI_InitStructure.CLKPHA        = SPI_CLKPHA_SECOND_EDGE;
    SPI_InitStructure.NSS           = SPI_NSS_SOFT;
    SPI_InitStructure.BaudRatePres  = SPI_BR_PRESCALER_16;
    SPI_InitStructure.FirstBit      = SPI_FB_MSB;
    SPI_InitStructure.CRCPoly       = 7;
    SPI_Init(SPI1, &SPI_InitStructure);

    /* SPI2 configuration */
    SPI_InitStructure.SpiMode = SPI_MODE_SLAVE;
    SPI_Init(SPI2, &SPI_InitStructure);

    /* Enable SPI1 CRC calculation */
    SPI_EnableCalculateCrc(SPI1, ENABLE);
    /* Enable SPI2 CRC calculation */
    SPI_EnableCalculateCrc(SPI2, ENABLE);

    /* Enable SPI1 */
    SPI_Enable(SPI1, ENABLE);
    /* Enable SPI2 */
    SPI_Enable(SPI2, ENABLE);

数据长度要在通信前设定,两路必须一致,改动后同步核对多项式。

2. 末字先发数据,再触发本端 CRC 发送。

src/main.csrc/main.c · main
    /* Wait for SPI1 Tx buffer empty */
    while (SPI_GetStatus(SPI1, SPI_TE_FLAG) == RESET)
        ;
    /* Wait for SPI2 Tx buffer empty */
    while (SPI_GetStatus(SPI2, SPI_TE_FLAG) == RESET)
        ;

    /* Send last SPI2_Buffer_Tx data */
    SPI_TransmitData(SPI2, SPI2_Buffer_Tx[TxIdx]);
    /* Enable SPI2 CRC transmission */
    SPI_TransmitCrcNext(SPI2);
    /* Send last SPI1_Buffer_Tx data */
    SPI_TransmitData(SPI1, SPI1_Buffer_Tx[TxIdx]);
    /* Enable SPI1 CRC transmission */
    SPI_TransmitCrcNext(SPI1);

    /* Wait for SPI1 last data reception */
    while (SPI_GetStatus(SPI1, SPI_RNE_FLAG) == RESET)
        ;
    /* Read SPI1 last received data */
    SPI1_Buffer_Rx[RxIdx] = SPI_ReceiveData(SPI1);
    /* Read SPI2 last received data */
    SPI2_Buffer_Rx[RxIdx] = SPI_ReceiveData(SPI2);

CRC 触发要紧跟在最后一个数据之后,顺序错误会导致 CRC 校验失败。

3. CRC 错误标志:任一方向置位即判为失败。

src/main.csrc/main.c · main
    /* Test on the SPI1 CRC Error flag */
    if ((SPI_GetStatus(SPI1, SPI_CRCERR_FLAG)) == SET)
    {
        TransferStatus2 = FAILED;
    }

    /* Test on the SPI2 CRC Error flag */
    if ((SPI_GetStatus(SPI2, SPI_CRCERR_FLAG)) == SET)
    {
        TransferStatus1 = FAILED;
    }

读标志要在收发完成后进行,早读会读到中间状态。

4. 读取数据 CRC 与本端 CRC 值并互相比对。

src/main.csrc/main.c · main
    /* Read SPI1 received CRC value */
    CRC1Value = SPI_ReceiveData(SPI1);
    /* Read SPI2 received CRC value */
    CRC2Value = SPI_ReceiveData(SPI2);

    /* Get SPI1&SPI2 CRC value */
    SPI1_CRCTX = SPI_GetCRCDat(SPI1,SPI_CRC_TX);
    SPI1_CRCRX = SPI_GetCRCDat(SPI1,SPI_CRC_RX);
    SPI2_CRCTX = SPI_GetCRCDat(SPI2,SPI_CRC_TX);
    SPI2_CRCRX = SPI_GetCRCDat(SPI2,SPI_CRC_RX);

    if((CRC1Value == SPI1_CRCRX) && (SPI1_CRCRX == SPI2_CRCTX))
    {
        log_info("SPI1 CRC is OK! \r\n");
    }
    else
    {
        log_info("SPI1 CRC is Fail! \r\n");
    }

    if((CRC2Value == SPI2_CRCRX) && (SPI2_CRCRX == SPI1_CRCTX))
    {
        log_info("SPI2 CRC is OK! \r\n");
    }
    else
    {
        log_info("SPI2 CRC is Fail! \r\n");
    }

本端发送 CRC 应等于对端接收 CRC,改多项式或长度时该等式同步变化。

对应源码: src/main.c、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_spi.h

5.16.3.4 SPI_DMA DMA 收发

工程目录: projects/n32g033_EVAL/examples/SPI/SPI_DMA/

使能 GPIO 与 SPI 时钟→配置一主一从两路 SPI→配置主机发送 DMA 通道→配置从机接收 DMA 通道→使能通道并等待传输完成

项目 源码解读
功能 主机的发送与从机的接收各交由一个 DMA 通道搬运,主循环只等待两个通道完成。
源码组成 src/main.c 含双实例初始化、两个 DMA 通道配置与比对函数;
src/n32g033_it.c 与 inc/n32g033_it.h 提供中断入口;
inc/main.h 定义两个实例的引脚、DMA 通道与缓冲区;
readme.txt 给出配置与测试步骤;
工程文件在 MDK-ARM/ 与 EWARM/。
关键配置 引脚:两路 SPI 的 SCK、MISO、MOSI 交叉相连;
模式:8 位数据、全双工、软件 NSS;
位序:高位在前;
预分频:8 分频;
DMA:主机走发送通道、从机走接收通道。
程序与数据路径 main → SPI_Init 配一主一从 → DMA_Init 分别配主机发送与从机接收通道并做请求重映射 → SPI_EnableDma 使能两路 DMA 请求 → 主循环等两个通道完成 → Buffercmp 比对。
主要 API SPI_InitStruct、SPI_Init、SPI_Enable、SPI_EnableDma、SPI_TransmitData、SPI_ReceiveData、SPI_GetStatus
验证方法 编译下载后复位运行,两个 DMA 通道均完成搬运后比对收发数据;
串口打印一致即为通过。
使用提示 DMA 通道与 SPI 的请求映射要对应各自的收发方向,改通道时同步修改重映射与请求宏;
开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1,硬件基于评估板 N32G033K8Q7-1_STB V1.0;
系统时钟 64 MHz。
核心代码解读与移植

示例把主机发送与从机接收都交给 DMA,主循环只等待两个通道搬运完成。

数据路径: SPI_Init 配一主一从 → 主机发送 DMA 通道指向数据寄存器 → 从机接收 DMA 通道指向数据寄存器 → SPI_EnableDma 使能请求 → 启动通道 → 两个完成标志置位后 Buffercmp 比对

1. 先配好一主一从两路 SPI,参数共用一套。

src/main.csrc/main.c · main
    SPI_InitStruct(&SPI_InitStructure);
    SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
    SPI_InitStructure.SpiMode       = SPI_MODE_MASTER;
    SPI_InitStructure.DataLen       = SPI_DATA_SIZE_8BITS;
    SPI_InitStructure.CLKPOL        = SPI_CLKPOL_LOW;
    SPI_InitStructure.CLKPHA        = SPI_CLKPHA_SECOND_EDGE;
    SPI_InitStructure.NSS           = SPI_NSS_SOFT;
    SPI_InitStructure.BaudRatePres  = SPI_BR_PRESCALER_8;
    SPI_InitStructure.FirstBit      = SPI_FB_MSB;
    SPI_InitStructure.CRCPoly       = CRC_POLYNOMIAL;
    SPI_Init(SPI_MASTER, &SPI_InitStructure);

    /* SPI_SLAVE configuration */
    SPI_InitStructure.SpiMode = SPI_MODE_SLAVE;
    SPI_Init(SPI_SLAVE, &SPI_InitStructure);

两路参数保持一致,只有主从模式不同,便于 DMA 直接对接。

2. 主机发送通道:外设地址指向数据寄存器,传输方向为外设目标。

src/main.csrc/main.c · main
    DMA_DeInit(SPI_MASTER_TX_DMA_CHANNEL);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.PeriphAddr     = (uint32_t)&SPI1->DAT;
    DMA_InitStructure.MemAddr        = (uint32_t)SPI_Master_Tx_Buffer;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = BUFFER_SIZE;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_LOW;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(SPI_MASTER_TX_DMA_CHANNEL, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_SPI1_TX,DMA,SPI_MASTER_TX_DMA_CHANNEL,ENABLE);

通道与 SPI 请求要做重映射,改通道后同步修改重映射参数。

3. 从机接收通道:外设地址指向数据寄存器,传输方向为外设源。

src/main.csrc/main.c · main
    DMA_DeInit(SPI_SLAVE_RX_DMA_CHANNEL);
    DMA_InitStructure.PeriphAddr = (uint32_t)&SPI2->DAT;
    DMA_InitStructure.MemAddr    = (uint32_t)SPI_Slave_Rx_Buffer;
    DMA_InitStructure.Direction  = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.Priority   = DMA_PRIORITY_VERY_HIGH;
    DMA_Init(SPI_SLAVE_RX_DMA_CHANNEL, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_SPI2_RX,DMA,SPI_SLAVE_RX_DMA_CHANNEL,ENABLE);

收发方向要与各自的 DMA 请求匹配,方向写反会导致数据不入缓冲。

4. 使能两路 DMA 请求与通道,再等待两个完成标志。

src/main.csrc/main.c · main
    /* Enable SPI_MASTER DMA Tx request */
    SPI_EnableDma(SPI_MASTER, SPI_DMA_TX, ENABLE);
    /* Enable SPI_SLAVE DMA Rx request */
    SPI_EnableDma(SPI_SLAVE, SPI_DMA_RX, ENABLE);

    /* Enable SPI_SLAVE */
    SPI_Enable(SPI_SLAVE, ENABLE);
    /* Enable SPI_MASTER */
    SPI_Enable(SPI_MASTER, ENABLE);

    /* Enable DMA channels */
    DMA_EnableChannel(SPI_SLAVE_RX_DMA_CHANNEL, ENABLE);
    DMA_EnableChannel(SPI_MASTER_TX_DMA_CHANNEL, ENABLE);

    /* Transfer complete */
    while (!DMA_GetFlagStatus(SPI_SLAVE_RX_DMA_FLAG, DMA))
        ;
    while (!DMA_GetFlagStatus(SPI_MASTER_TX_DMA_FLAG, DMA))
        ;

先使能请求与通道再启动传输,两个标志都要等到才算完成。

对应源码: src/main.c、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_spi.h

5.16.3.5 SPI_FLASH 读写串行 FLASH

工程目录: projects/n32g033_EVAL/examples/SPI/SPI_FLASH/

使能 GPIO 与 SPI 时钟→初始化 SPI 与片选引脚→读取 FLASH 器件 ID→擦除扇区后写入数据→读回并比对,再擦除后检查全为擦除态

项目 源码解读
功能 用 SPI 驱动片外串行 FLASH:读器件 ID、擦除扇区、写入数据、读回比对,再擦除后检查是否全为擦除态。
源码组成 src/main.c 组织初始化、读写擦除与比对流程;
src/spi_flash.c 实现 FLASH 的初始化、命令收发、页写、读回与等待;
inc/spi_flash.h 定义命令、器件 ID 与引脚宏;
src/n32g033_it.c 提供中断入口;
readme.txt 给出配置与测试步骤。
关键配置 引脚:SPI 的 SCK、MISO、MOSI 复用推挽,片选为推挽输出;
模式:8 位数据、全双工、软件 NSS、从机第二位边沿采样;
位序:高位在前;
预分频:4 分频;
时钟极性:空闲高电平。
程序与数据路径 main → sFLASH_Init 初始化 SPI 与片选 → sFLASH_ReadID 校验器件 → sFLASH_EraseSector 擦除 → sFLASH_WriteBuffer 页写 → sFLASH_ReadBuffer 读回 → Buffercmp 比对。
主要 API SPI_InitStruct、SPI_Init、SPI_Enable、SPI_TransmitData、SPI_ReceiveData、SPI_GetStatus
验证方法 编译下载后复位运行,串口分别打印读写与擦除的校验结果;
读写一致且擦除后全为 0xFF 即为通过。
使用提示 FLASH 命令与器件 ID 要与实际器件匹配,片选时序需按手册保证;
开发环境为 KEIL MDK-ARM V5.34.0.0 或 IAR EWARM 8.50.1,硬件基于评估板 N32G033K8Q7-1_STB V1.0;
系统时钟 64 MHz。
核心代码解读与移植

示例用 SPI 逐字节驱动串行 FLASH,把命令、地址与数据拼装成一次传输。

数据路径: sFLASH_Init 配 SPI 与片选 → sFLASH_SendByte 收发一字节 → sFLASH_ReadID 发读 ID 命令取三字节 → sFLASH_WriteBuffer 拆页写命令、地址与数据 → sFLASH_ReadBuffer 读回 → Buffercmp 比对

1. 初始化 SPI 与片选引脚,并把片选置为未选中。

src/spi_flash.csrc/spi_flash.c · sFLASH_Init
void sFLASH_Init(void)
{
    SPI_InitType SPI_InitStructure;

    sFLASH_LowLevel_Init();

    /* Deselect the FLASH: Chip Select high */
    sFLASH_CS_HIGH();

    /* SPI configuration */
    SPI_InitStruct(&SPI_InitStructure);
    SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
    SPI_InitStructure.SpiMode       = SPI_MODE_MASTER;
    SPI_InitStructure.DataLen       = SPI_DATA_SIZE_8BITS;
    SPI_InitStructure.CLKPOL        = SPI_CLKPOL_HIGH;
    SPI_InitStructure.CLKPHA        = SPI_CLKPHA_SECOND_EDGE;
    SPI_InitStructure.NSS           = SPI_NSS_SOFT;

    SPI_InitStructure.BaudRatePres = SPI_BR_PRESCALER_4;

    SPI_InitStructure.FirstBit = SPI_FB_MSB;
    SPI_InitStructure.CRCPoly  = 7;
    SPI_Init(sFLASH_SPI, &SPI_InitStructure);

    /* Enable the sFLASH_SPI  */
    SPI_Enable(sFLASH_SPI, ENABLE);
}

片选空闲保持高电平,移植时把命令与引脚宏换成目标器件即可。

2. 单字节收发:等发送空后写入,再等接收非空后读回,构成一次全双工交换。

src/spi_flash.csrc/spi_flash.c · sFLASH_SendByte
uint8_t sFLASH_SendByte(uint8_t byte)
{
    /* Loop while DAT register in not emplty */
    while (SPI_GetStatus(sFLASH_SPI, SPI_TE_FLAG) == RESET)
        ;

    /* Send byte through the SPI1 peripheral */
    SPI_TransmitData(sFLASH_SPI, byte);

    /* Wait to receive a byte */
    while (SPI_GetStatus(sFLASH_SPI, SPI_RNE_FLAG) == RESET)
        ;

    /* Return the byte read from the SPI bus */
    return SPI_ReceiveData(sFLASH_SPI);
}

FLASH 命令都基于这一字节交换拼接,改动底层会波及全部命令。

3. 读器件 ID:发读 ID 命令后连收三个字节并拼成 24 位值。

src/spi_flash.csrc/spi_flash.c · sFLASH_ReadID
uint32_t sFLASH_ReadID(void)
{
    uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

    /* Select the FLASH: Chip Select low */
    sFLASH_CS_LOW();

    /* Send "RDID " instruction */
    sFLASH_SendByte(0x9F);
    /* Read a byte from the FLASH */
    Temp0 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);

    /* Read a byte from the FLASH */
    Temp1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);

    /* Read a byte from the FLASH */
    Temp2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);

    /* Deselect the FLASH: Chip Select high */
    sFLASH_CS_HIGH();

    Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;

    return Temp;
}

器件 ID 与期望值不匹配时后续读写会被跳过,移植时先核对 ID 宏。

4. 主流程:读 ID、擦除、写入、读回比对,再擦除后检查擦除态。

src/main.csrc/main.c · main
    sFLASH_Init();

    /* Get SPI Flash ID */
    FlashID = sFLASH_ReadID();

    /* Check the SPI Flash ID */
    if (FlashID == sFLASH_ID)
    {
        /* Perform a write in the Flash followed by a read of the written data */
        /* Erase SPI FLASH Sector to write on */
        sFLASH_EraseSector(FLASH_SectorToErase);

        /* Write Tx_Buffer data to SPI FLASH memory */
        sFLASH_WriteBuffer(Tx_Buffer, FLASH_WriteAddress, BufferSize);

        /* Read data from SPI FLASH memory */
        sFLASH_ReadBuffer(Rx_Buffer, FLASH_ReadAddress, BufferSize);

        /* Check the correctness of written dada */
        TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
        /* TransferStatus1 = PASSED, if the transmitted and received data by SPI1
           are the same */
        /* TransferStatus1 = FAILED, if the transmitted and received data by SPI1
           are different */

        /* Perform an erase in the Flash followed by a read of the written data */
        /* Erase SPI FLASH Sector to write on */
        sFLASH_EraseSector(FLASH_SectorToErase);

        /* Read data from SPI FLASH memory */
        sFLASH_ReadBuffer(Rx_Buffer, FLASH_ReadAddress, BufferSize);

擦除后再写入,写入后等内部写完成,顺序颠倒会读回错误数据。

对应源码: src/main.c、src/spi_flash.c、inc/spi_flash.h、src/n32g033_it.c、firmware/n32g033_std_periph_driver/inc/n32g033_spi.h

5.16.4 注意与排障

场景 检查与建议 来源
NSS 管理 用户手册 N32G033 的 SPI 章写明 NSS 有软件与硬件两种管理模式,主设备 NSS 应保持高电平、从设备 NSS 应保持低电平;
多主或需外部片选时按手册选择内部软件置位或外部引脚控制。
用户手册
主模式失效 用户手册 N32G033 的 SPI 章写明主模式下 NSS 被外部拉低会触发模式失效,硬件会清除 SPIEN 与 MSEL 并置 MODERR;
需软件重新初始化后再通信。
用户手册
通信中修改配置 用户手册 N32G033 的 SPI 章写明 LSBFF、MSEL、CLKPHA、CLKPOL、BR 等位不得在通信过程中修改;
改配置前先关闭 SPI。
用户手册
关闭 SPI 的时机 用户手册 N32G033 的 SPI 章写明关闭 SPI 前要等待发送为空、总线不忙且接收非空等标志全部满足,避免丢数据。 用户手册
CRC 计算使能时机 用户手册 N32G033 的 SPI 章写明 DATFF 与 CRCEN 只在 SPIEN 为 0 时可写,使能顺序为先清 SPIEN 与 CRCEN 再置 CRCEN 与 SPIEN;
下一 CRC 值需在写完最后一个数据后立即触发。
用户手册
从机 CRC 用户手册 N32G033 的 SPI 章写明从模式使能 CRC 时,即使 NSS 为高电平,收到时钟也会参与 CRC 计算。 用户手册

勘误手册 V1.0.0(2025.9.25)针对 A 版芯片,未列出 SPI 相关条目。

国民技术开发套件文档中心

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

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