接上一篇32H7串口接收问题,继续说,里边提供了中断,最大的缺点就是关于中断方式了,是为了解决这个问题,那就是把DMA迁移,不就是用数据搬运的嘛,不用多可惜。
首先我们需要东西了解,DMA和外设发送数据,例如串口,我们希望,当一帧数据接收完毕,大声告诉主程序,串口接收到一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
DMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。
还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。
/**
* @brief Receive an amount of data in DMA mode.
* @note When the UART parity is enabled (PCE = 1), the received data contain
* the parity bit (MSB position).
* @param huart UART handle.
* @param pData Pointer to data buffer.
* @param Size Amount of data to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
//1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄 修改某些状态
//2.判断和串口句柄关联的DMA句柄地址不为空 然后给DMA句柄注册一些回调函数
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK)
{
......
}
}
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。
/**
* @brief Start the DMA Transfer with interrupt enabled.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Stream.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
//1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置
//2.判断就绪状态
{
......
/* Configure the source, destination address and the data length */
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
......
//这里会开启一堆中断 完事要用 暂时可以不关心
}
}
上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。
/**
* @brief Sets the DMA Transfer parameter.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Stream.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval None
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
/* calculate DMA base and stream number */
//获取DMA控制器对应流的基地址
DMA_Base_Registers *regs_dma = (DMA_Base_Registers *)hdma->StreamBaseAddress;
BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
/* Clear the DMAMUX synchro overrun flag */
hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
if(hdma->DMAmuxRequestGen != 0U)
{
/* Clear the DMAMUX request generator overrun flag */
hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
}
if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
{
/* Clear all interrupt flags at correct offset within the register */
regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);
/* Clear DBM bit */
((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);
/* Configure DMA Stream data length */
//这里设置搬用的目标数据长度
((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;
/* Peripheral to Memory */
//整个这个if判断是在设置DMA搬运数据的目标地址和源地址
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Stream destination address */
((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;
/* Configure DMA Stream source address */
((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;
}
/* Memory to Peripheral */
else
{
/* Configure DMA Stream source address */
((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;
/* Configure DMA Stream destination address */
((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;
}
}
else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */
{
/* Clear all flags */
regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);
/* Configure DMA Channel data length */
((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;
/* Peripheral to Memory */
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Channel destination address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
/* Configure DMA Channel source address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;
}
/* Memory to Peripheral */
else
{
/* Configure DMA Channel source address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;
/* Configure DMA Channel destination address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;
}
}
else
{
/* Nothing To Do */
}
}
各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。
我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。
因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。
再试试贴代码吧,方便你我他,要积分的都无耻。改天
uart.c文件就这么多代码,
#include "Uart.h"
#include "stm32h7xx_hal.h"
#define RxBufSize 1024
UART_HandleTypeDef hUart1 = {0};
DMA_HandleTypeDef hDmaUart1Tx = {0};
DMA_HandleTypeDef hDmaUart1Rx = {0};
//数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法
uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));
void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);
void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count))
{
hUart1.Instance = USART1;
hUart1.Init.BaudRate = BaudRate;
hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hUart1.Init.Mode = UART_MODE_TX_RX;
hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
hUart1.Init.Parity = UART_PARITY_NONE;
hUart1.Init.StopBits = UART_STOPBITS_1;
hUart1.Init.WordLength = UART_WORDLENGTH_8B;
hUart1.FifoMode = UART_FIFOMODE_DISABLE;
HAL_UART_Init(&hUart1);
__HAL_RCC_DMA1_CLK_ENABLE();
hDmaUart1Tx.Instance = DMA1_Stream0;
hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;
hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;
hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;
hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hDmaUart1Tx.Init.Mode = DMA_NORMAL;
hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hDmaUart1Tx);
__HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);
hDmaUart1Rx.Instance = DMA1_Stream1;
hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;
hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;
hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;
hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hDmaUart1Rx.Init.Mode = DMA_NORMAL;
hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hDmaUart1Rx);
__HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);
HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
__HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART1_IRQn,14,0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);
Uart1RxCompleteCallback = RxCompleteCallback;
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
if(huart == &hUart1)//串口1
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}
}
void Uart1TxData(uint8_t *pData,uint16_t Count)
{
if(Count)
HAL_UART_Transmit_DMA(&hUart1,pData,Count);
}
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE))
{
static uint16_t count;
__HAL_UART_CLEAR_IDLEFLAG(&hUart1);
if(Uart1RxCompleteCallback)
{
hUart1.RxState = HAL_UART_STATE_READY;
hDmaUart1Rx.State = HAL_DMA_STATE_READY;
HAL_UART_RxCpltCallback(&hUart1);
}
}
else
HAL_UART_IRQHandler(&hUart1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &hUart1)
{
static uint16_t count;
count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);
if(count == 0)return;
hDmaUart1Rx.Lock = HAL_UNLOCKED;
if(huart->pRxBuffPtr < RxBuf[1])
{
Uart1RxCompleteCallback(RxBuf[0],&count);
HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);
}
else
{
Uart1RxCompleteCallback(RxBuf[1],&count);
HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
}
hDmaUart1Rx.Lock = HAL_LOCKED;
}
}
void DMA1_Stream0_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hDmaUart1Tx);
}
void DMA1_Stream1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hDmaUart1Rx);
}
这个是Uart.h文件
#ifndef __Uart_H_
#define __Uart_H_
#include "stdint.h"
void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));
void Uart1TxData(uint8_t *pData,uint16_t Count);
#endif /* End __Uart_H_ */
系我。
接上一篇32H7串口接收问题,继续说,里边提供了中断,最大的缺点就是关于中断方式了,是为了解决这个问题,那就是把DMA迁移,不就是用数据搬运的嘛,不用多可惜。
首先我们需要东西了解,DMA和外设发送数据,例如串口,我们希望,当一帧数据接收完毕,大声告诉主程序,串口接收到一帧n个字节的数据存在某个地方,接收过程中你丫别打搅我。
DMA就能胜任这个工作,他可以以中断的形式告诉你这些信息。相比中断接收方式,是不是省了很多中断,主程序被打断的次数也就少了。
还是按照上一篇形式大概看一下,HAL库中DMA是怎么和串口配合的。
/**
* @brief Receive an amount of data in DMA mode.
* @note When the UART parity is enabled (PCE = 1), the received data contain
* the parity bit (MSB position).
* @param huart UART handle.
* @param pData Pointer to data buffer.
* @param Size Amount of data to be received.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* 其他关系不大的代码省略 有兴趣可以自己看 下同 */
//1.检查参数 判断串口接收状态为就绪 把缓存区参数传递到串口句柄 修改某些状态
//2.判断和串口句柄关联的DMA句柄地址不为空 然后给DMA句柄注册一些回调函数
/* Enable the DMA channel */
if (HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->RDR, (uint32_t)huart->pRxBuffPtr, Size) != HAL_OK)
{
......
}
}
HAL_UART_Receive_DMA这个函数里最主要的就是调用了HAL_DMA_Start_IT这个函数,你看他连参数都没怎么变,就把句柄换了,其他三个原封不动的传递过去了。所以函数内其他内容几乎不用考虑了。直接往下看这个函数。
/**
* @brief Start the DMA Transfer with interrupt enabled.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Stream.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
//1.检查参数 给句柄上锁 判断状态 只有在就绪状态下才允许配置
//2.判断就绪状态
{
......
/* Configure the source, destination address and the data length */
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
......
//这里会开启一堆中断 完事要用 暂时可以不关心
}
}
上面这个函数也差不多还是那个意思,都懒的看了,主要是调用了DMA_SetConfig这个函数,追踪过去,它才是真正配置寄存器的函数,HAL库就是这么繁琐。
/**
* @brief Sets the DMA Transfer parameter.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Stream.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval None
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
/* calculate DMA base and stream number */
//获取DMA控制器对应流的基地址
DMA_Base_Registers *regs_dma = (DMA_Base_Registers *)hdma->StreamBaseAddress;
BDMA_Base_Registers *regs_bdma = (BDMA_Base_Registers *)hdma->StreamBaseAddress;
/* Clear the DMAMUX synchro overrun flag */
hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;
if(hdma->DMAmuxRequestGen != 0U)
{
/* Clear the DMAMUX request generator overrun flag */
hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask;
}
if(IS_DMA_STREAM_INSTANCE(hdma->Instance) != 0U) /* DMA1 or DMA2 instance */
{
/* Clear all interrupt flags at correct offset within the register */
regs_dma->IFCR = 0x3FUL << (hdma->StreamIndex & 0x1FU);
/* Clear DBM bit */
((DMA_Stream_TypeDef *)hdma->Instance)->CR &= (uint32_t)(~DMA_SxCR_DBM);
/* Configure DMA Stream data length */
//这里设置搬用的目标数据长度
((DMA_Stream_TypeDef *)hdma->Instance)->NDTR = DataLength;
/* Peripheral to Memory */
//整个这个if判断是在设置DMA搬运数据的目标地址和源地址
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Stream destination address */
((DMA_Stream_TypeDef *)hdma->Instance)->PAR = DstAddress;
/* Configure DMA Stream source address */
((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = SrcAddress;
}
/* Memory to Peripheral */
else
{
/* Configure DMA Stream source address */
((DMA_Stream_TypeDef *)hdma->Instance)->PAR = SrcAddress;
/* Configure DMA Stream destination address */
((DMA_Stream_TypeDef *)hdma->Instance)->M0AR = DstAddress;
}
}
else if(IS_BDMA_CHANNEL_INSTANCE(hdma->Instance) != 0U) /* BDMA instance(s) */
{
/* Clear all flags */
regs_bdma->IFCR = (BDMA_ISR_GIF0) << (hdma->StreamIndex & 0x1FU);
/* Configure DMA Channel data length */
((BDMA_Channel_TypeDef *)hdma->Instance)->CNDTR = DataLength;
/* Peripheral to Memory */
if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
{
/* Configure DMA Channel destination address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = DstAddress;
/* Configure DMA Channel source address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = SrcAddress;
}
/* Memory to Peripheral */
else
{
/* Configure DMA Channel source address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CPAR = SrcAddress;
/* Configure DMA Channel destination address */
((BDMA_Channel_TypeDef *)hdma->Instance)->CM0AR = DstAddress;
}
}
else
{
/* Nothing To Do */
}
}
各位同志你们自己看吧这个函数最主要的目的就是配置DMA寄存器。以上就是串口DMA接收函数中最重要的部分。好像没什么意义一样,因为我要用到其中的一点点东西,所以必须要分析源码。
我们只是说了调用接收函数,参数里边指定了接收缓存,也指定了大小,似乎和我们的目标不符合,假设我们的DMA和串口之间的配置已经配置好了,那现在能做到的就是把数据收集到这个缓冲区里,可是并不能告诉主程序接收到了数据,和接收了多少,想要知道这个,有两种方法,一种是CPU定时去问DMA接收了多少数据,然后自己定义一个记录变化的变量,配合,另一种是中断方式,我们通过查询得知,DMA只有接收完成和接收半完成两个中断。
最最主要的串口的空闲中断不要忘了呀,这个可以告诉你,一帧数据接收完了,你可以根据这个中断去搞,接收了多少,在什么地方。
因为这个编辑器不知道咋回事,贴代码总是挂,上边那个函数就贴了我很长时间,很生气,所以我就无耻的把源码整到这里了,整个工程哦(暂时还没有上传)。
再试试贴代码吧,方便你我他,要积分的都无耻。改天
uart.c文件就这么多代码,
#include "Uart.h"
#include "stm32h7xx_hal.h"
#define RxBufSize 1024
UART_HandleTypeDef hUart1 = {0};
DMA_HandleTypeDef hDmaUart1Tx = {0};
DMA_HandleTypeDef hDmaUart1Rx = {0};
//数组后边的那个限定跟你的内存分配有关 如果你的主RAM在512K的那个片内存就可以不加 这是AC6编译器用法
uint8_t RxBuf[2][RxBufSize] __attribute__((section (".RAM_D1")));
void (*Uart1RxCompleteCallback)(uint8_t *pData,uint16_t *Count);
void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count))
{
hUart1.Instance = USART1;
hUart1.Init.BaudRate = BaudRate;
hUart1.Init.ClockPrescaler = UART_PRESCALER_DIV2;
hUart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
hUart1.Init.Mode = UART_MODE_TX_RX;
hUart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;
hUart1.Init.OverSampling = UART_OVERSAMPLING_8;
hUart1.Init.Parity = UART_PARITY_NONE;
hUart1.Init.StopBits = UART_STOPBITS_1;
hUart1.Init.WordLength = UART_WORDLENGTH_8B;
hUart1.FifoMode = UART_FIFOMODE_DISABLE;
HAL_UART_Init(&hUart1);
__HAL_RCC_DMA1_CLK_ENABLE();
hDmaUart1Tx.Instance = DMA1_Stream0;
hDmaUart1Tx.Init.Request = DMA_REQUEST_USART1_TX;
hDmaUart1Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hDmaUart1Tx.Init.PeriphInc = DMA_PINC_DISABLE;
hDmaUart1Tx.Init.MemInc = DMA_MINC_ENABLE;
hDmaUart1Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDmaUart1Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hDmaUart1Tx.Init.Mode = DMA_NORMAL;
hDmaUart1Tx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hDmaUart1Tx);
__HAL_LINKDMA(&hUart1,hdmatx,hDmaUart1Tx);
hDmaUart1Rx.Instance = DMA1_Stream1;
hDmaUart1Rx.Init.Request = DMA_REQUEST_USART1_RX;
hDmaUart1Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hDmaUart1Rx.Init.PeriphInc = DMA_PINC_DISABLE;
hDmaUart1Rx.Init.MemInc = DMA_MINC_ENABLE;
hDmaUart1Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hDmaUart1Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hDmaUart1Rx.Init.Mode = DMA_NORMAL;
hDmaUart1Rx.Init.Priority = DMA_PRIORITY_MEDIUM;
HAL_DMA_Init(&hDmaUart1Rx);
__HAL_LINKDMA(&hUart1,hdmarx,hDmaUart1Rx);
HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
__HAL_UART_ENABLE_IT(&hUart1,UART_IT_IDLE);
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART1_IRQn,14,0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);//Tx
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn,14,0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);//Rx
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,14,0);
Uart1RxCompleteCallback = RxCompleteCallback;
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
if(huart == &hUart1)//串口1
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9;
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}
}
void Uart1TxData(uint8_t *pData,uint16_t Count)
{
if(Count)
HAL_UART_Transmit_DMA(&hUart1,pData,Count);
}
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&hUart1,UART_FLAG_IDLE))
{
static uint16_t count;
__HAL_UART_CLEAR_IDLEFLAG(&hUart1);
if(Uart1RxCompleteCallback)
{
hUart1.RxState = HAL_UART_STATE_READY;
hDmaUart1Rx.State = HAL_DMA_STATE_READY;
HAL_UART_RxCpltCallback(&hUart1);
}
}
else
HAL_UART_IRQHandler(&hUart1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart == &hUart1)
{
static uint16_t count;
count = RxBufSize - __HAL_DMA_GET_COUNTER(&hDmaUart1Rx);
if(count == 0)return;
hDmaUart1Rx.Lock = HAL_UNLOCKED;
if(huart->pRxBuffPtr < RxBuf[1])
{
Uart1RxCompleteCallback(RxBuf[0],&count);
HAL_UART_Receive_DMA(&hUart1,RxBuf[1],RxBufSize);
}
else
{
Uart1RxCompleteCallback(RxBuf[1],&count);
HAL_UART_Receive_DMA(&hUart1,RxBuf[0],RxBufSize);
}
hDmaUart1Rx.Lock = HAL_LOCKED;
}
}
void DMA1_Stream0_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hDmaUart1Tx);
}
void DMA1_Stream1_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hDmaUart1Rx);
}
这个是Uart.h文件
#ifndef __Uart_H_
#define __Uart_H_
#include "stdint.h"
void Uart1Init(uint32_t BaudRate,void (*RxCompleteCallback)(uint8_t *pData,uint16_t *Count));
void Uart1TxData(uint8_t *pData,uint16_t Count);
#endif /* End __Uart_H_ */
系我。
举报