HAL库下Uart与SPI的DMA发送与接收
一直有想法对HAL库下对串口与与SPI进行DMA方式接收与发送的详细配置了解,以及正确的操作流程。
首先介绍Uart在HAL中实现DMA的发送与接收
串口配置这个就无需我在此叙述,直接进入主题:
软件配置如图,DMA中断默认开启,需要我们采用DMA传输必须要使能串口中断;
HAL_UART_Transmit_DMA(&huart1,Uart_tx_buf,sizeof(Uart_tx_buf));为DMA发送函数
在配置完成后,调用上面的函数就可以直接发送到电脑。
串口的DMA接收,就要麻烦一些,需要了解回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)和
HAL_UART_Receive_IT(&huart1,(uint8_t *)Uart_rx_temp,Length);//Uart_DMA数据缓存接收中断
其中Uart_rx_temp,Length为在进入callback函数之前需要接收到的数据长度以及数据接收存放地址。所以在代码main初始化时需要加上。当满足一次接收中断的要求后,就会直接调转到HAL_UART_RxCpltCallback;当然此前CUBEMAX已经就为我们初始化了Uart1的中断。
下面是一段简单的测试代码:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
Uart_rx_buf[Rx_cnt++]= Uart_rx_temp[0];
Uart_rx_buf[Rx_cnt++]= Uart_rx_temp[1];
if((Uart_rx_temp[0] == 0x0D)&&(Uart_rx_temp[1] == 0x0A))
{
Uart_rec_success= 1;
}
HAL_UART_Receive_IT(&huart1,(uint8_t *)Uart_rx_temp,Length);
}
在主函数中我们就只要轮询 Uart_rec_success= 1;这个条件是否满足,去执行相对应的结果就行。
在此我遇到一个DMA发送的一个坑,就是谨防在DMA数据没有发送完成时,将数据进行改变。我最开始用:HAL_SPI_Transmit(&hspi1,(uint8_t*)tx_buf,1,10);测试没有任何问题,但: HAL_UART_Transmit_DMA(&huart1,Uart_tx_buf,11);会出现数据掉包,不完整的;结果是因为我在下面一条语句就是
for(i=0;i
我也就不多说串口 。下面介绍SPI_DMA 中的配置;
最开始测试:采用 HAL_SPI_Transmit_DMA(&hspi1,(uint8_t*)tx_buf,7);
效果波形如图:
数据正常,但是数据边沿有脉冲,考虑原因可能是采样率太高,造成波形抖动,降低采样率后,有好转,但是尚未完全解决。
HAL_SPI_TransmitReceive_DMA(&hspi1,(uint8_t *)tx_buf,(uint8_t *)rec_buf,(sizeof(tx_buf)/sizeof(uint16_t)));
函数在最开始使用时,数据掉包,审查了发现:
HAL_SPI_TransmitReceive_IT(&hspi1,(uint8_t *)tx_buf,(uint8_t *)rec_buf,7);
接收数据正常,与上图波形一致。为什么DMA全双工数据就会掉包呢?
考虑到并未对缓冲区数据进行操作,就去检查自己的配的工程,发现原来没有打开SPI接收DMA。在此三个函数都能正常数据传输。
对于回调函数,也和串口相似,只需要在发送或则从机接收完成后,就会进去执行各种flag,需要控制操作就在主函数进行操作判断。但是最近从机的SPI一直有问题,数据乱码不稳定,希望后面能够解决,或得到网友的帮助。