NXP MCU 技术论坛
直播中

王萍

7年用户 1301经验值
私信 关注
[问答]

求分享使用DMA进行SPI Master传输的示例?

你好!
我正在制作一个使用 S32K144 进行 CAN 通信和 SPI 的项目。在 SPI 主模式下,我发送长消息(例如 282 x uint8)来控制 WS2812 LED。在 CAN 中,我以 50Hz 的频率接收和传输多条消息。
我对 SPI 和 CAN 有一个问题,因为当我用来自 CAN 总线的一些消息触发 CAN_Receive 时,SPI 停止并设置了 SPI_Busy 标志。对于如此长的消息,SPI 正在减慢我的模型步骤。
我认为带有 DMA 的 SPI 可以解决这个问题,因为使用 STM32 我设法发送长消息并保持 CAN 正常工作。但是我找不到任何使用 DMA 进行 SPI 通信的示例,并且设置不像其他工具箱那样简单,只需选中 DMA 选项即可激活它。
您能否与我分享一个使用 DMA 进行 SPI Master 传输的示例?

回帖(1)

杨福林

2023-9-22 10:03:50
您好,下面是一个使用DMA进行SPI Master传输的示例代码,该代码使用STM32F4作为示例MCU:

```
#include "stm32f4xx_hal.h"

//SPI handles
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_tx;

//Buffer to store data to be transmitted
uint8_t data_buffer[282];

void SPI_Send_DMA(void)
{
  //Enable DMA peripheral clock
  __HAL_RCC_DMA2_CLK_ENABLE();

  //Configure DMA peripheral
  hdma_spi1_tx.Instance = DMA2_Stream3;
  hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
  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_HIGH;
  hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
  {
    //Error handle
  }

  //Link DMA handle with SPI handle
  __HAL_LINKDMA(&hspi1, hdmatx, hdma_spi1_tx);

  //Start SPI and DMA transmission
  if (HAL_SPI_Transmit_DMA(&hspi1, data_buffer, sizeof(data_buffer)) != HAL_OK)
  {
    //Error handle
  }

  //Wait for DMA and SPI transmission to complete
  while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);
  while (HAL_DMA_GetState(&hdma_spi1_tx) != HAL_DMA_STATE_READY);

  //Disable DMA peripheral clock
  __HAL_RCC_DMA2_CLK_DISABLE();
}

int main(void)
{
  //Configure SPI peripheral
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    //Error handle
  }

  //Initialize data buffer
  for (int i = 0; i < sizeof(data_buffer); i++)
  {
    data_buffer[i] = 0xFF;
  }

  //Send data over SPI using DMA
  SPI_Send_DMA();

  while (1)
  {
    //Main program loop
  }
}
```

在上面的代码中,我们使用DMA进行SPI主机传输。首先,我们需要初始化SPI外设,然后配置DMA外设并将其链接到SPI外设。最后,我们通过调用 ```HAL_SPI_Transmit_DMA()``` 函数来启动SPI和DMA传输。在DMA传输完成之前,我们需要循环等待。一旦DMA传输完成,我们就可以将DMA外设关闭。

我们可以在主程序循环中调用 ```SPI_Send_DMA()``` 函数以启动DMA传输。在此实例中,数据缓冲区包含282个8位数据,我们使用 ```HAL_SPI_GetState()``` 和 ```HAL_DMA_GetState()``` 函数来检查SPI和DMA传输完成的状态。如果需要,您可以将数据缓冲区更改为包含不同数量的数据。

希望这可以帮助您解决问题!
举报

更多回帖

发帖
×
20
完善资料,
赚取积分