stm32f412 SPI dma接收和UART dma发送问题解决

在做STM32F412和RT1052的SPI通信和UART通信时,遇到了一些问题,主要还是对STM的HAL库不熟悉,在这里做个记录

使用STM32F412的SPI1作为从机通过DMA方式接收RT1052的数据,STM32的程序通过CubeMX生成的。出了2个问题:

1、如果接收出错后,就是丢了字节后,DMA就不能正常接收了。一直停留在SPI_WaitFlagStateUntilTimeout()这个函数出不来。然后把DMA的模式从正常改为了循环模式后就好了

hdma_spi1_rx.Init.Mode                = DMA_CIRCULAR ;//模式:外设流控模式,循环模式,普通模式

2、我直接在

void DMA2_Stream0_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */

  /* USER CODE END DMA2_Stream0_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_spi1_rx);
    

  /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */

  /* USER CODE END DMA2_Stream0_IRQn 1 */
}

这个函数里面去处理SPI接收的中断,发现每帧数据过来后会进两次中断,第一次数据并没有完全接收,一直找不出问题来。后来看了: HAL_DMA_IRQHandler(&hdma_spi1_rx);这个函数里面的内容,发现对应了2种接收的处理,一种是: 

/* Half Transfer Complete Interrupt management ******************************/
  if ((tmpisr & (DMA_FLAG_HTIF0_4 << hdma->StreamIndex)) != RESET)

相当于接收一半后的中断。还有一个是:

  /* Transfer Complete Interrupt management ***********************************/
  if ((tmpisr & (DMA_FLAG_TCIF0_4 << hdma->StreamIndex)) != RESET)

完全接收后的中断,我需要的是第二种。然后在看下面的处理,实际上是对应的有对应的回调函数的:

    void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
    {
    }

这个函数会在完全接收以后被调用,这样就不用自己还去判断是否接收完毕了,实际上CubMX生成的程序已经给处理好了,只是我自己之前比较熟悉直接在中断函数里面直接进行处理,没有用回调函数的方式,这样就需要自己去写对应的寄存器的处理和判断了。

我用的STM32F412的uart1进行DMA的发送和接收,发现在调用

HAL_UART_Transmit_DMA(&huart1,tBuf,11);

发送以后怎么就不能再发送了,查找后发现发送把串口状态切换到busy,但是切回Ready状态的操作需要我们自己动手;在HAL_DMA_Start_IT()函数里面会将DMA加锁但是没有解锁,同时函数会开启DMA 半传输、完成传输、传输错误、FIFO溢出错误中断位;这样一来,就需要自己手动来处理这个事情了。

//UART1 TX中断
void DMA2_Stream7_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream7_IRQn 0 */

  /* USER CODE END DMA2_Stream7_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_usart1_tx);
  /* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
    
    //解决DMA发送发送几次就不能在发送了
    // 1.建议开启DMA传输完成中断
    // 2.在完成中断函数里面将串口状态切换到Ready状况;
    // 3.将DMA解锁
    // 4.Clear相应中断标志位
    huart1.gState = HAL_UART_STATE_READY;
    hdma_usart1_tx.State = HAL_DMA_STATE_READY;
    __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_TCIF3_7);
    __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_HTIF3_7);
    __HAL_DMA_CLEAR_FLAG(&hdma_usart1_tx, DMA_FLAG_FEIF3_7 );
    __HAL_UNLOCK(&hdma_usart1_tx); 

  /* USER CODE END DMA2_Stream7_IRQn 1 */
}

然后就可以正常一直发送了。

发布了46 篇原创文章 · 获赞 28 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/x13163303344/article/details/104170158