STM32F4 HAL SPI_Receive dma 只接收一次
Posted
技术标签:
【中文标题】STM32F4 HAL SPI_Receive dma 只接收一次【英文标题】:STM32F4 HAL SPI_Receive dma just receive one time 【发布时间】:2021-06-16 23:14:35 【问题描述】:我尝试了很多方法和读取参考,但我无法从 SPI_Receive_DMA 模式正确读取数据。
在 spi 1 中,我想在一个线程中以 dma 模式通过 spi 连续读取 Ad7606 数据。 但是,我总是在 SPI1 dma 模式下收到相同的数据。好像我没有收到任何新数据。我知道如果我只想在 spi dma 模式下接收数据,我还必须打开 TX 和 RX DMA 通道。 我不知道我错过了哪一步或错了。有谁知道如何解决这个问题?非常感谢。
static void MX_SPI1_Init(void)
/* 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_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
Error_Handler();
static void MX_DMA_Init(void)
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Stream4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
/* DMA2_Stream3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
** Note
DMA2_Stream0 - > SPI1 Receive
DMA2_Stream3 - > SPI1 Transmit
DMA1_Stream4 - > SPI2 Transmit
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_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PB5 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
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);
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);
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA2_Stream0;
hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
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;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
Error_Handler();
__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
/* SPI1_TX Init */
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_LOW;
hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
Error_Handler();
__HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
int main(void)
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_SPI1_Init();
MX_SPI2_Init();
MX_TIM7_Init();
MX_USART2_UART_Init();
uint8_t receive_buffer[256] ;
/* Init scheduler */
osKernelInitialize();
/*handle */
SendTaskHandle = osThreadNew(SendTaskFun, NULL, &SendTask_attributes);
ReceiveTaskHandle = osThreadNew(ReceiveTaskFun, NULL, &ReceiveTask_attributes);
osKernelStart();
while (1)
void ReceiveTaskFun(void *argument)
for (;;)
//-- SPI1 callback
HAL_SPI_RxCpltCallback(&hspi1);
HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 1); //-- cs=1 deactive
void DMA2_Stream0_IRQHandler(void)
HAL_DMA_IRQHandler(&hdma_spi1_rx);
void DMA2_Stream3_IRQHandler(void)
HAL_DMA_IRQHandler(&hdma_spi1_tx);
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
if (hspi->Instance == SPI1)
//-- Enable CS
HAL_GPIO_WritePin(GPIO_A, GPIO_PIN_7, 0); //-- cs=0 active low
//- - SPI2_DMA_receive
...... (Here is for receive data from AD7606 )
HAL_SPI_Receive_DMA(&hspi1, receive_buffer, 8);
【问题讨论】:
【参考方案1】:假设您的所有功能都正确映射,当前流程似乎是:
-
ReceiveTaskFun 调用 HAL_SPI_RxCpltCallback() 断言您的芯片选择,启动 DMA 传输并返回
ReceiveTaskFun() 将您的 CS 引脚置为无效并进入下一个循环。
HAL_SPI_RxCpltCallback()(从 ReceiveTaskFun 调用)再次断言您的 CS 引脚并尝试设置 DMA 传输,但很可能会失败。检查返回值看HAL_BUSY,因为它还没有完成传输
同时,您的 DMA 传输可能会发生,也可能不会发生(外设将传输,无论您的从设备是否输出数据),因为您正在切换 CS 引脚
当 8 个字节的传输完成时,会调用 HAL_SPI_RxCpltCallback(),它会重新置位 CS 引脚并开始 DMA 传输。这可能会成功,但由于您一直在切换 CS 引脚,所以您得到的只是垃圾
解决方案可能是:
-
在 ReceiveTaskFun() 中使用延迟。您知道传输 + 捕获持续时间,以此为基础
使用来自 SPI 中断的 RTOS 信号 - 让您的 ReceiveTaskFun 等待来自 ISR 回调的信号,然后设置新的传输。
【讨论】:
以上是关于STM32F4 HAL SPI_Receive dma 只接收一次的主要内容,如果未能解决你的问题,请参考以下文章