uu799 发表于 2019-5-15 18:47:12

STM32H750VB SPI DMA 接受异常,怀疑硬件或者HAL库的问题

本帖最后由 uu799 于 2019-5-15 18:49 编辑

最近在在H750VB移植RT-Thread最新发布的RW007 SPI WIFI,目前已经把轮训模式调通,但是由于SPI WIFI的通讯速度很高,轮训容易把CPU吃满,所以准备使用SPI DMA去处理,但是使用HAL1.4.0版本的库,使用SPI DMA的API只发送是正常的,但是一旦DMA接受就异常,SPI DMA无法再次正常通讯,相同逻辑在F4是可以正常运行。

下面是基于RTT的SPI驱动,SPI DMA区域在AXI区域不在TCM内存区域,没有开启cache。不知道有人遇到和我一样的问题吗,调试了1周无果,虚心请求解答。

/*
* @File:   drv_sdcard.c
* @Author: liuguang
* @Date:   2019-02-24 23:48:19
*
* @LICENSE:
* The code owner is liuguang. Other personnel may
* not be used or modified.
*
* Change Logs:
* Date         Author       Notes
* 2019-02-24   liuguang   The first version.
*/

#include "drv_spi.h"
#include "board.h"
#include "rtdevice.h"

// iperf:   
#define BSP_SPI_ENABLE_DEBUG
//#define BSP_SPI_USING_DMA

#define DBG_ENABLE
#define DBG_SECTION_NAME "drv.spi"
#if defined(BSP_SPI_ENABLE_DEBUG)
#define DBG_LEVEL DBG_LOG
#else
#define DBG_LEVEL DBG_INFO
#endif
#define DBG_COLOR
#include <rtdbg.h>

struct stm32_spi
{
    SPI_HandleTypeDef hspi;
    struct rt_spi_configuration *cfg;

#if defined(BSP_SPI_USING_DMA)
    DMA_HandleTypeDef hdma_tx;
    DMA_HandleTypeDef hdma_rx;
#endif
};
typedef struct stm32_spi* stm32_spi_t;

struct stm32_spi_cs
{
    rt_uint32_t pin;
};
typedef struct stm32_spi_cs* stm32_spi_cs_t;

#if defined(BSP_SPI_ENABLE_PORT3)
static __align(8) struct stm32_spi spi3 = {.hspi.Instance = SPI3};
static __align(8) struct rt_spi_bus spi3_bus = {.parent.user_data = &spi3};
#endif

#if defined(BSP_SPI_ENABLE_PORT4)
static __align(8) struct stm32_spi spi4 = {.hspi.Instance = SPI4};
static __align(8) struct rt_spi_bus spi4_bus = {.parent.user_data = &spi4};
#endif

static rt_uint32_t get_spi_clk_source_freq(SPI_HandleTypeDef *hspi)
{
    rt_uint32_t freq = 0;

#if defined(BSP_SPI_ENABLE_PORT3)
    if(hspi->Instance == SPI3)
    {
      PLL1_ClocksTypeDef pll1 = {0};
      
      HAL_RCCEx_GetPLL1ClockFreq(&pll1);
      freq = (rt_uint32_t)pll1.PLL1_Q_Frequency;
    }
#endif

#if defined(BSP_SPI_ENABLE_PORT4)
    if(hspi->Instance == SPI4)
    {
      PLL2_ClocksTypeDef pll2 = {0};
      
      HAL_RCCEx_GetPLL2ClockFreq(&pll2);
      freq = (rt_uint32_t)pll2.PLL2_Q_Frequency;
    }
#endif

    return freq;
}

static rt_err_t spi_init(stm32_spi_t spi, struct rt_spi_configuration *cfg)
{
    rt_uint32_t freq = 0;
    rt_uint32_t divx = 0;
    rt_uint32_t max_hz = 0;
    SPI_HandleTypeDef *hspi = &(spi->hspi);   

    RT_ASSERT(spi != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    if((cfg->data_width >= 4) && (cfg->data_width <= 32))
    {
      LOG_D("SPI_DATASIZE_8BIT");
      hspi->Init.DataSize = SPI_DATASIZE_8BIT;
    }
    else
    {
      LOG_E("SPI data width error.");
      return (-RT_EINVAL);   
    }

    /* 计算能配置的最接近(不高于)于目标时钟频率的分频数 */
    max_hz = cfg->max_hz;
    freq = get_spi_clk_source_freq(hspi);
    divx = divx;

    if(max_hz >= freq/4)
    {
      divx = 4;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    }
    else if(max_hz >= freq/8)
    {
      divx = 8;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    }
    else if(max_hz >= freq/16)
    {
      divx = 16;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    }
    else if(max_hz >= freq/32)
    {
      divx = 32;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
    }
    else if(max_hz >= freq/64)
    {
      divx = 64;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
    }
    else if(max_hz >= freq/128)
    {
      divx = 128;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
    }
    else
    {
      divx = 256;
      hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    }

    LOG_D("spi clk source freq is %dHz.", freq);
    LOG_D("spi clk target freq is %dHz.", cfg->max_hz);
    LOG_D("spi clk divx is %d.", divx);
    LOG_D("spi clk freq is %dHz.", freq / divx);

    /* CPOL */
    if(cfg->mode & RT_SPI_CPOL)
    {
      LOG_D("SPI_POLARITY_HIGH");
      hspi->Init.CLKPolarity = SPI_POLARITY_HIGH;
    }
    else
    {
      LOG_D("SPI_POLARITY_LOW");
      hspi->Init.CLKPolarity = SPI_POLARITY_LOW;
    }

    /* CPHA */
    if(cfg->mode & RT_SPI_CPHA)
    {
      LOG_D("SPI_PHASE_2EDGE");
                hspi->Init.CLKPhase = SPI_PHASE_2EDGE;
    }
    else
    {
      LOG_D("SPI_PHASE_1EDGE");
                hspi->Init.CLKPhase = SPI_PHASE_1EDGE;
    }

    /* MSB or LSB */
    if(cfg->mode & RT_SPI_MSB)
    {
      LOG_D("SPI_FIRSTBIT_MSB");
      hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
    }
    else
    {
      LOG_D("SPI_FIRSTBIT_LSB");
      hspi->Init.FirstBit = SPI_FIRSTBIT_LSB;
    }

    /* SPI3强制为3线模式3WIRE */
    if(hspi->Instance == SPI3)
    {
      LOG_D("SPI_DIRECTION_2LINES_TXONLY");
      hspi->Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
    }
    else
    {
      LOG_D("SPI_DIRECTION_2LINES");
      hspi->Init.Direction = SPI_DIRECTION_2LINES;
    }
   
    /* DMA */
#if defined(BSP_SPI_USING_DMA)
    if(hspi->Instance == SPI4)
    {
      __HAL_RCC_DMA2_CLK_ENABLE();
      
      spi->hdma_rx.Instance               = DMA2_Stream2;
      spi->hdma_rx.Init.Request             = DMA_REQUEST_SPI4_RX;
      spi->hdma_rx.Init.Direction         = DMA_PERIPH_TO_MEMORY;
      spi->hdma_rx.Init.PeriphInc         = DMA_PINC_DISABLE;
      spi->hdma_rx.Init.MemInc            = DMA_MINC_ENABLE;      
      spi->hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
      spi->hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
      spi->hdma_rx.Init.Mode                = DMA_NORMAL;
      spi->hdma_rx.Init.Priority            = DMA_PRIORITY_VERY_HIGH;
      spi->hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
      spi->hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
      spi->hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;
      spi->hdma_rx.Init.PeriphBurst         = DMA_PBURST_INC4;
      
      spi->hdma_tx.Instance               = DMA2_Stream3;
      spi->hdma_tx.Init.Request             = DMA_REQUEST_SPI4_TX;
      spi->hdma_tx.Init.Direction         = DMA_MEMORY_TO_PERIPH;
      spi->hdma_tx.Init.PeriphInc         = DMA_PINC_DISABLE;
      spi->hdma_tx.Init.MemInc            = DMA_MINC_ENABLE;      
      spi->hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
      spi->hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
      spi->hdma_tx.Init.Mode                = DMA_NORMAL;
      spi->hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
      spi->hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
      spi->hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
      spi->hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;
      spi->hdma_tx.Init.PeriphBurst         = DMA_PBURST_INC4;

      HAL_DMA_Abort(&(spi4.hdma_rx));
      HAL_DMA_DeInit(&(spi->hdma_rx));
      HAL_DMA_Init(&(spi->hdma_rx));
      __HAL_LINKDMA(hspi, hdmatx, spi->hdma_rx);
      
      HAL_DMA_Abort(&(spi4.hdma_tx));
      HAL_DMA_DeInit(&(spi->hdma_tx));
      HAL_DMA_Init(&(spi->hdma_tx));
      __HAL_LINKDMA(hspi, hdmatx, spi->hdma_tx);
      
      HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 1, 0);
      HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
      HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 1, 1);
      HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);

      LOG_D("spi4 dma configuration.");
    }
#endif

    hspi->Init.Mode                     = SPI_MODE_MASTER;
    hspi->Init.NSS                        = SPI_NSS_SOFT;
    hspi->Init.NSSPMode                   = SPI_NSS_PULSE_DISABLE;
    hspi->Init.NSSPolarity                = SPI_NSS_POLARITY_LOW;
    hspi->Init.TIMode                     = SPI_TIMODE_DISABLE;
    hspi->Init.CRCCalculation             = SPI_CRCCALCULATION_DISABLE;
    hspi->Init.CRCPolynomial            = 7;
    hspi->Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi->Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi->Init.MasterSSIdleness         = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi->Init.MasterInterDataIdleness    = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi->Init.MasterReceiverAutoSusp   = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi->Init.MasterKeepIOState          = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    hspi->Init.IOSwap                     = SPI_IO_SWAP_DISABLE;
    hspi->Init.FifoThreshold            = SPI_FIFO_THRESHOLD_01DATA;
   
    HAL_SPI_Abort(hspi);
    HAL_SPI_DeInit(hspi);
    if (HAL_SPI_Init(hspi) != HAL_OK)
    {
      return (-RT_ERROR);
    }
   
//    HAL_NVIC_SetPriority(SPI4_IRQn, 1, 0);
//    HAL_NVIC_EnableIRQ(SPI4_IRQn);

    rt_thread_mdelay(100);
    LOG_D("spi configuration.");

    return RT_EOK;
}

static rt_err_t configure(struct rt_spi_device *device, struct rt_spi_configuration *cfg)
{
    rt_err_t ret = RT_EOK;

    struct stm32_spi *spi = (struct stm32_spi *)device->bus->parent.user_data;
    spi->cfg = cfg;

    ret = spi_init(spi, cfg);

    return ret;
}

static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
    HAL_StatusTypeDef ret;
    rt_uint32_t length = message->length;
   
    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(device->bus != RT_NULL);
    RT_ASSERT(device->bus->parent.user_data != RT_NULL);

    struct stm32_spi *spi = (struct stm32_spi *)device->bus->parent.user_data;
    struct stm32_spi_cs *cs = device->parent.user_data;

    if (message->cs_take)
    {
      rt_pin_write(cs->pin, PIN_LOW);
    }
   
    if(message->length == 0)
    {
      length = 0;
      goto _ret;
    }
   
    if(message->send_buf == RT_NULL && message->recv_buf == RT_NULL)
    {
      LOG_E("send_buf and recv_buf is null.");
      while(1);
    }
    else if(message->send_buf != RT_NULL && message->recv_buf == RT_NULL)
    {
    #if defined(BSP_SPI_USING_DMA)
      SCB_InvalidateDCache_by_Addr((uint32_t *)message->send_buf, message->length);
      ret = HAL_SPI_Transmit_DMA(&(spi->hspi), (uint8_t *)(message->send_buf), message->length);
    #else
      ret = HAL_SPI_Transmit(&(spi->hspi), (uint8_t *)(message->send_buf), message->length, 1000);
    #endif
      if(ret != HAL_OK)
      {
            LOG_E("HAL_SPI_Transmit = failed.", ret);
            while(1);
      }
    #if defined(BSP_SPI_USING_DMA)
      else
      {
            LOG_D("HAL_SPI_Transmit = ok.");
      }
    #endif
    }
    else if(message->send_buf == RT_NULL && message->recv_buf != RT_NULL)
    {
    #if defined(BSP_SPI_USING_DMA)
      SCB_InvalidateDCache_by_Addr((uint32_t *)message->recv_buf, message->length);
      ret = HAL_SPI_Receive_DMA(&(spi->hspi), (uint8_t *)(message->recv_buf), message->length);
    #else
      ret = HAL_SPI_Receive(&(spi->hspi), (uint8_t *)(message->recv_buf), message->length, 1000);
    #endif
      if(ret != HAL_OK)
      {
            LOG_E("HAL_SPI_Receive = failed.", ret);
            while(1);
      }
    #if defined(BSP_SPI_USING_DMA)         
      else
      {
            LOG_D("HAL_SPI_Receive = ok.");
      }   
    #endif      
    }
    else if(message->send_buf != RT_NULL && message->recv_buf != RT_NULL)
    {
    #if defined(BSP_SPI_USING_DMA)
      SCB_InvalidateDCache_by_Addr((uint32_t *)message->send_buf, message->length);
      SCB_InvalidateDCache_by_Addr((uint32_t *)message->recv_buf, message->length);
      ret = HAL_SPI_TransmitReceive_DMA(&(spi->hspi), (uint8_t *)(message->send_buf), (uint8_t *)(message->recv_buf), message->length);
    #else
      ret = HAL_SPI_TransmitReceive(&(spi->hspi), (uint8_t *)(message->send_buf), (uint8_t *)(message->recv_buf), message->length, 1000);
    #endif
      if(ret != HAL_OK)
      {
            LOG_E("HAL_SPI_TransmitReceive = failed.", ret);
            while(1);
      }
    #if defined(BSP_SPI_USING_DMA)
      else
      {
            LOG_D("HAL_SPI_TransmitReceive = ok.");
      }
    #endif
    }

#if defined(BSP_SPI_USING_DMA)
    rt_thread_mdelay(1000);
#else
    while (HAL_SPI_GetState(&(spi->hspi)) != HAL_SPI_STATE_READY);
#endif

_ret:
    if (message->cs_release)
    {
      rt_pin_write(cs->pin, PIN_HIGH);
    }

    return length;
}

rt_err_t stm32_spi_bus_attach_device(const char *bus_name, const char *device_name, rt_uint32_t pin)
{
    rt_err_t ret = RT_EOK;
   
    struct rt_spi_device *spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
    RT_ASSERT(spi_device != RT_NULL);

    struct stm32_spi_cs *cs_pin = (struct stm32_spi_cs *)rt_malloc(sizeof(struct stm32_spi_cs));
    RT_ASSERT(cs_pin != RT_NULL);

    cs_pin->pin = pin;
    rt_pin_mode(pin, PIN_MODE_OUTPUT);
    rt_pin_write(pin, PIN_HIGH);

    ret = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);
   
    return ret;
}

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
   
    LOG_D("HAL_SPI_MspInit");
   
#if defined(BSP_SPI_ENABLE_PORT3)   
    if(hspi->Instance == SPI3)
    {
      __HAL_RCC_SPI3_CLK_ENABLE();
      __HAL_RCC_GPIOC_CLK_ENABLE();

      GPIO_InitStruct.Pin       = GPIO_PIN_10 | GPIO_PIN_12;
      GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull      = GPIO_NOPULL;
      GPIO_InitStruct.Speed   = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
      HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    }
#endif
   
#if defined(BSP_SPI_ENABLE_PORT4)   
    if(hspi->Instance == SPI4)
    {
      __HAL_RCC_SPI4_CLK_ENABLE();
      __HAL_RCC_GPIOE_CLK_ENABLE();

      GPIO_InitStruct.Pin       = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
      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_SPI4;
      HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    }
#endif
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
#if defined(BSP_SPI_ENABLE_PORT3)   
    if(hspi->Instance == SPI3)
    {
      __HAL_RCC_SPI3_CLK_DISABLE();
      HAL_GPIO_DeInit(GPIOC, GPIO_PIN_10 | GPIO_PIN_12);
    }
#endif
   
#if defined(BSP_SPI_ENABLE_PORT4)   
    if(hspi->Instance == SPI4)
    {
      __HAL_RCC_SPI4_CLK_DISABLE();
      HAL_GPIO_DeInit(GPIOE, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
    }
#endif
}

static struct rt_spi_ops ops = {configure, spixfer};

int rt_hw_spi_init(void)
{
#if defined(BSP_SPI_ENABLE_PORT3)
    rt_spi_bus_register(&spi3_bus, "spi3", &ops);
#endif

#if defined(BSP_SPI_ENABLE_PORT4)
    rt_spi_bus_register(&spi4_bus, "spi4", &ops);
#endif

    return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_spi_init);

#if defined(BSP_SPI_USING_DMA)

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
#if defined(BSP_SPI_ENABLE_PORT4)
    if(hspi->Instance == SPI4)
    {
      LOG_I("HAL_SPI_TxRxCpltCallbacks.");
    }
#endif
}

#if defined(BSP_SPI_ENABLE_PORT4)
void DMA2_Stream2_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&(spi4.hdma_rx));
}

void DMA2_Stream3_IRQHandler(void)
{
    HAL_DMA_IRQHandler(&(spi4.hdma_tx));
}

void SPI4_IRQHandler(void)
{
    HAL_SPI_IRQHandler(&(spi4.hspi));
}
#endif
#endif


3111272 发表于 2019-5-20 13:44:50

打破零回复。

chuanlinrong 发表于 2019-8-16 18:38:01

兄弟,你这个问题解决了吗?我现在也是,使用SPI FLASH,轮询模式没有问题,但是DMA模式接收的数据全是0.不清楚这个是为啥
页: [1]
查看完整版本: STM32H750VB SPI DMA 接受异常,怀疑硬件或者HAL库的问题