深入理解drv_spi.c后,完全正向亲手移植rt-thread的drv_spi.c驱动 (基于stm32h750 artpi)

1. 按照移植rt-thread驱动的三部曲

  • 第1步,用cubeMX创建spi/qspi的工程,并在Keil下测试成功spi/qspi读写spi-flash。分别用dma模式和polling模式测试。这一步前面已经ok。
  • 第2步,在rt-thread环境下,创建test.c文件,将前面CubeMX工程的相应函数copy过来(main.c中的gpio/spi/dma初始化函数及测试函数及回调函数, stm32h7xx_hal_msp.c中的msp_init, msp_denit函数,以及stm32h7xx_it.c中的中断函数),并通过msh_cmd测试成功。
  • 第3步,修改drv_spi.c,实现相应的函数,并测试它直到成功。

2. drv_spi.c

  • spixfer中,定义#define DMA_MIN_SIZE 10 /set this=10000, means always use polling. set this=0, means always use dma. both works fine./
  • 我们定义了noncache region,方便dma使用。
  • 对于dma发送,我们无条件copy send_buf到tx_buffer,再发送。对于dma接收,我们总是使用rx_buffer执行dma,然后无条件copy rx_buffer到recv_buffer中。这样大大简化了操作。
  • 注意GPIO速度要HIGH
  • 注意分频比配置。先开始尽量让频率低,等成功了再逐步提高频率。
  • 注意DMA配置,先关闭fifo。测试成功了,再可以考虑开启fifo。
  • 注意检查drv_mpu.c配置nocache region
  • 注意检查link.lds配置nocache region
  • 注意rt_spi_configure函数存在一个提前return的bug,我已经修正了。
  • 在spixfer函数中,我调用底层HAL库函数的时候,大量使用了RT_ASSSERT()宏,感觉非常不错。
  • 注意,我们定义了DMA_SIZE=8192,这意味着支持的单个包的最大传输是8192 bytes。如果应用程序超过8192 bytes,需要做分包处理。
  • 后续优化,可以考虑修改spixfer函数,让其实现分包功能。这样软件应用层无需做分包处理,没有传输size限制。
c 复制代码
/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-11-5      SummerGift   first version
 * 2018-12-11     greedyhao    Porting for stm32f7xx
 * 2019-01-03     zylx         modify DMA initialization and spixfer function
 * 2020-01-15     whj4674672   Porting for stm32h7xx
 * 2020-06-18     thread-liu   Porting for stm32mp1xx
 * 2020-10-14     Dozingfiretruck   Porting for stm32wbxx
 */

#include <rtthread.h>
#include <rtdevice.h>
#include "board.h"
#include "trace_log.h"

#ifdef BSP_USING_SPI

#include "drv_spi.h"
#include "drv_config.h"

//#define DRV_DEBUG
#define LOG_TAG              "drv.spi"
#include <drv_log.h>

#define DMA_SIZE 8192
#define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable")))
#define USB_MEM_ALIGNX __attribute__((aligned(32)))
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t tx_buffer[DMA_SIZE];
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t rx_buffer[DMA_SIZE];

SPI_HandleTypeDef hspi1;
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi1_tx;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi2_tx;
DMA_HandleTypeDef hdma_spi2_rx;

static void MX_SPI1_Init(void);
static void MX_DMA_Init(void);


struct rt_completion spi_cpt;
struct rt_spi_bus spi_bus;

static rt_ssize_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
    #define DMA_MIN_SIZE 10 /*set this=10000, means always use polling. set this=0, means always use dma. both works fine.*/

    HAL_StatusTypeDef state = HAL_OK;
    rt_size_t message_length, already_send_length;
    rt_uint16_t send_length;
    rt_uint8_t *recv_buf;
    const rt_uint8_t *send_buf;    

    /*pull cs*/
    if (message->cs_take && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
    {
        if (device->config.mode & RT_SPI_CS_HIGH)
        {
            rt_pin_write(device->cs_pin, PIN_HIGH);
        }
        else
        {
            rt_pin_write(device->cs_pin, PIN_LOW);
        }
    }
    
    message_length = message->length;
    recv_buf = message->recv_buf;
    send_buf = message->send_buf;

    if(message_length < DMA_MIN_SIZE){ /*small length, use polling*/ 
        if (message->send_buf && message->recv_buf)
        {
            RT_ASSERT(HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)send_buf, (uint8_t *)recv_buf, message_length, 1000) == HAL_OK);
        }
        else if (message->send_buf)
        {
            RT_ASSERT(HAL_SPI_Transmit(&hspi1, (uint8_t *)send_buf, message_length, 1000) == HAL_OK);
        }
        else if (message->recv_buf)
        {
            RT_ASSERT(HAL_SPI_Receive(&hspi1, (uint8_t *)recv_buf, message_length, 1000) == HAL_OK);
        }

        while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
    }
    else { /*large length, use dma*/
        RT_ASSERT(message_length <= DMA_SIZE); /*now only support dma length < 8192 bytes*/

        /*copy to nocache tx_buffer*/
        if(message->send_buf){
            rt_memcpy(tx_buffer, send_buf, message_length);
        }

        /*start dma*/
        if (message->send_buf && message->recv_buf)
        {
            RT_ASSERT(HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t *)tx_buffer, (uint8_t *)rx_buffer, message_length) == HAL_OK);
        }
        else if (message->send_buf)
        {
            RT_ASSERT(HAL_SPI_Transmit_DMA(&hspi1, (uint8_t *)tx_buffer, message_length) == HAL_OK);
        }
        else if (message->recv_buf)
        {
            RT_ASSERT(HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)rx_buffer, message_length) == HAL_OK);
        }  

        /*wait dma finish*/
        RT_ASSERT(rt_completion_wait(&spi_cpt, 1000) == RT_EOK);

        /*copy from nocache rx_buffer*/
        if(message->recv_buf){
            rt_memcpy(recv_buf, rx_buffer, message_length);
        }
    }

    /*pull cs*/
    if (message->cs_release && !(device->config.mode & RT_SPI_NO_CS) && (device->cs_pin != PIN_NONE))
    {
        if (device->config.mode & RT_SPI_CS_HIGH)
        {
            rt_pin_write(device->cs_pin, PIN_LOW);
        }
        else
        {
            rt_pin_write(device->cs_pin, PIN_HIGH);
        }
    } 
    
    return message->length;
}

static rt_err_t spi_configure(struct rt_spi_device *device,
                              struct rt_spi_configuration *configuration)
{
    MX_DMA_Init();
    MX_SPI1_Init();

    return RT_EOK;
}

static const struct rt_spi_ops stm_spi_ops =
{
    .configure = spi_configure,
    .xfer = spixfer,
};



rt_err_t rt_hw_spi_device_attach(const char *bus_name, const char *device_name, rt_base_t cs_pin)
{
    RT_ASSERT(bus_name != RT_NULL);
    RT_ASSERT(device_name != RT_NULL);

    rt_err_t result;
    struct rt_spi_device *spi_device;

    /* attach the device to spi bus*/
    spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
    RT_ASSERT(spi_device != RT_NULL);

    result = rt_spi_bus_attach_device_cspin(spi_device, device_name, bus_name, cs_pin, RT_NULL);
    RT_ASSERT(result == RT_EOK);
    
    return result;
}



void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    rt_completion_done(&spi_cpt);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    rt_completion_done(&spi_cpt);
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    rt_completion_done(&spi_cpt);
}

int rt_hw_spi_init(void)
{
    rt_err_t result;

    rt_completion_init(&spi_cpt);
    result = rt_spi_bus_register(&spi_bus, "spi1", &stm_spi_ops);
    RT_ASSERT(result == RT_EOK);

    return result;
}
INIT_BOARD_EXPORT(rt_hw_spi_init);















/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
 static void MX_SPI1_Init(void)
 {
 
   /* USER CODE BEGIN SPI1_Init 0 */
 
   /* USER CODE END SPI1_Init 0 */
 
   /* USER CODE BEGIN SPI1_Init 1 */
 
   /* USER CODE END SPI1_Init 1 */
   /* SPI1 parameter configuration*/
   hspi1.Instance = SPI1;
   hspi1.Init.Mode = SPI_MODE_MASTER;
   hspi1.Init.Direction = SPI_DIRECTION_2LINES;
   hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
   hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
   hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
   hspi1.Init.NSS = SPI_NSS_SOFT;
   hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; /*must <25MHz is ok*/
   hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
   hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
   hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
   hspi1.Init.CRCPolynomial = 0x0;
   hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
   hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
   hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
   hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
   hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
   hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
   hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
   hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
   hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
   hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
   if (HAL_SPI_Init(&hspi1) != HAL_OK)
   {
     Error_Handler();
   }
   /* USER CODE BEGIN SPI1_Init 2 */
 
   /* USER CODE END SPI1_Init 2 */
 
 }

 
/**
  * @brief SPI MSP Initialization
  * This function configures the hardware resources used in this example
  * @param hspi: SPI handle pointer
  * @retval None
  */
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
    /* USER CODE BEGIN SPI1_MspInit 0 */

    /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PB5     ------> SPI1_MOSI
    PG9     ------> SPI1_MISO
    PA5     ------> SPI1_SCK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* SPI1 DMA Init */
    /* SPI1_TX Init */
    hdma_spi1_tx.Instance = DMA1_Stream0;
    hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi1_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_spi1_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi1_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);

    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA1_Stream1;
    hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_spi1_rx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi1_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);

    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI1_IRQn);
    /* USER CODE BEGIN SPI1_MspInit 1 */

    /* USER CODE END SPI1_MspInit 1 */
  }
  else if(hspi->Instance==SPI2)
  {
    /* USER CODE BEGIN SPI2_MspInit 0 */

    /* USER CODE END SPI2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOI_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PI1     ------> SPI2_SCK
    PI2     ------> SPI2_MISO
    PI3     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);

    /* SPI2 DMA Init */
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Stream2;
    hdma_spi2_tx.Init.Request = DMA_REQUEST_SPI2_TX;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_tx.Init.Mode = DMA_NORMAL;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmatx,hdma_spi2_tx);

    /* SPI2_RX Init */
    hdma_spi2_rx.Instance = DMA1_Stream3;
    hdma_spi2_rx.Init.Request = DMA_REQUEST_SPI2_RX;
    hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_rx.Init.Mode = DMA_NORMAL;
    hdma_spi2_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    hdma_spi2_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    hdma_spi2_rx.Init.MemBurst = DMA_MBURST_SINGLE;
    hdma_spi2_rx.Init.PeriphBurst = DMA_PBURST_SINGLE; /*要用single, spi dma才可以正常工作*/
    if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi2_rx);

    /* SPI2 interrupt Init */
    HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SPI2_IRQn);
    /* USER CODE BEGIN SPI2_MspInit 1 */

    /* USER CODE END SPI2_MspInit 1 */
  }

}

/**
  * @brief SPI MSP De-Initialization
  * This function freeze the hardware resources used in this example
  * @param hspi: SPI handle pointer
  * @retval None
  */
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
  if(hspi->Instance==SPI1)
  {
    /* USER CODE BEGIN SPI1_MspDeInit 0 */

    /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();

    /**SPI1 GPIO Configuration
    PB5     ------> SPI1_MOSI
    PG9     ------> SPI1_MISO
    PA5     ------> SPI1_SCK
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5);

    HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9);

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);

    /* SPI1 DMA DeInit */
    HAL_DMA_DeInit(hspi->hdmatx);
    HAL_DMA_DeInit(hspi->hdmarx);

    /* SPI1 interrupt DeInit */
    HAL_NVIC_DisableIRQ(SPI1_IRQn);
    /* USER CODE BEGIN SPI1_MspDeInit 1 */

    /* USER CODE END SPI1_MspDeInit 1 */
  }
  else if(hspi->Instance==SPI2)
  {
    /* USER CODE BEGIN SPI2_MspDeInit 0 */

    /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();

    /**SPI2 GPIO Configuration
    PI1     ------> SPI2_SCK
    PI2     ------> SPI2_MISO
    PI3     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOI, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

    /* SPI2 DMA DeInit */
    HAL_DMA_DeInit(hspi->hdmatx);
    HAL_DMA_DeInit(hspi->hdmarx);

    /* SPI2 interrupt DeInit */
    HAL_NVIC_DisableIRQ(SPI2_IRQn);
    /* USER CODE BEGIN SPI2_MspDeInit 1 */

    /* USER CODE END SPI2_MspDeInit 1 */
  }

}

/**
  * Enable DMA controller clock
  */
 static void MX_DMA_Init(void)
 {
 
   /* DMA controller clock enable */
   __HAL_RCC_DMA1_CLK_ENABLE();
 
   /* DMA interrupt init */
   /* DMA1_Stream0_IRQn interrupt configuration */
   HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
   /* DMA1_Stream1_IRQn interrupt configuration */
   HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
   /* DMA1_Stream2_IRQn interrupt configuration */
   HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
   /* DMA1_Stream3_IRQn interrupt configuration */
   HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
 
 }

 /**
  * @brief This function handles DMA1 stream0 global interrupt.
  */
void DMA1_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream0_IRQn 0 */

  /* USER CODE END DMA1_Stream0_IRQn 0 */
  rt_base_t level = rt_hw_interrupt_disable();
  HAL_DMA_IRQHandler(&hdma_spi1_tx);
  rt_hw_interrupt_enable(level);
  /* USER CODE BEGIN DMA1_Stream0_IRQn 1 */

  /* USER CODE END DMA1_Stream0_IRQn 1 */
}

/**
  * @brief This function handles DMA1 stream1 global interrupt.
  */
void DMA1_Stream1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Stream1_IRQn 0 */

  /* USER CODE END DMA1_Stream1_IRQn 0 */
  rt_base_t level = rt_hw_interrupt_disable();
  HAL_DMA_IRQHandler(&hdma_spi1_rx);
  rt_hw_interrupt_enable(level);
  /* USER CODE BEGIN DMA1_Stream1_IRQn 1 */

  /* USER CODE END DMA1_Stream1_IRQn 1 */
}

/**
  * @brief This function handles SPI1 global interrupt.
  */
 void SPI1_IRQHandler(void)
 {
   /* USER CODE BEGIN SPI1_IRQn 0 */
 
   /* USER CODE END SPI1_IRQn 0 */
   rt_base_t level = rt_hw_interrupt_disable();
   HAL_SPI_IRQHandler(&hspi1);
   rt_hw_interrupt_enable(level);
   /* USER CODE BEGIN SPI1_IRQn 1 */
 
   /* USER CODE END SPI1_IRQn 1 */
 }

 #endif /* BSP_USING_SPI */

3. port_spi_flash.c 挂载flash disk

c 复制代码
#include <rtdevice.h>
#include <rtthread.h>
#include <board.h>
#include <dev_spi_flash.h>
#include <drv_spi.h>
#include "dev_spi_flash_sfud.h"
#include <dfs_fs.h>
#include <fal.h>
#include "trace_log.h"

// #define DBG_TAG "app.port_spi_flash"
// #define DBG_LVL DBG_INFO
// #include <rtdbg.h>

#define SPI_BUS_NAME "spi1"
#define SPI_DEVICE_NAME "spi10"
#define SPI_FLASH_DEVICE_NAME "W25Q64S"
#define SPI_SECT_DEVICE_NAME "flashdb"

#define SPI_FLASH_CS_PIN    GET_PIN(A, 4)   // CS=PA4
int spi_flash_init(void)
{
    /* 挂载SPI Flash设备到软SPI1总线 */
    if (rt_hw_spi_device_attach(SPI_BUS_NAME, SPI_DEVICE_NAME, SPI_FLASH_CS_PIN) != RT_EOK)
    {
        rt_kprintf("Failed to attach SPI Flash!\n");
        return -RT_ERROR;
    }    
  
    if (RT_NULL == rt_sfud_flash_probe(SPI_FLASH_DEVICE_NAME, SPI_DEVICE_NAME))
    {
        return -RT_ERROR;
    };

    fal_init();
    fal_blk_device_create(SPI_SECT_DEVICE_NAME);

    /* 挂载文件系统 */
    #ifdef BSP_USING_FATFS_ROOTFS

    int try=10;
    while(dfs_mount(SPI_SECT_DEVICE_NAME, "/spi", "elm", 0, 0) != 0)
    {
        LOG_W("mount to '/spi' failed! try again...");

        rt_thread_mdelay(100);
        try--;
        if(try<=0) break;
    }
    LOG_I("mount to '/spi' success!");

    // if (dfs_mount(SPI_SECT_DEVICE_NAME, "/spi", "elm", 0, 0) != 0)
    // {
    //     LOG_W("mount to '/spi' failed! try to mkfs %s", SPI_SECT_DEVICE_NAME);
    //     // dfs_mkfs("elm", SPI_SECT_DEVICE_NAME);
    //     if (dfs_mount(SPI_SECT_DEVICE_NAME, "/spi", "elm", 0, 0) == 0)
    //     {
    //         LOG_I("mount to '/spi' success!");
    //         goto _exit;
    //     }
    // }
    // LOG_I("mount to '/spi' success!");
    #endif

_exit:
    return 0;
}
INIT_APP_EXPORT(spi_flash_init); 

4. 测试结果

  • 将#define DMA_MIN_SIZE 10,混合使用polling+dma,测试成功
  • 将#define DMA_MIN_SIZE 0,相当于只使用dma,测试成功
  • 将#define DMA_MIN_SIZE 10000,相当于只使用polling,测试成功