UART DMA方式
MM32F0270 UART使用DMA方式接收数据可以减小CPU的开销。
对于接收定长数据,可以将DMA接收缓冲区的长度设定为待接收数据的长度,这样利用DMA的传输完成中断就可以知道已经接收了一帧数据。
对于接收不定长数据,由于内核在串口接收数据到空闲这段时间,是不受理串口数据的,所以可以使用DMA来协助我们把数据传送到指定的地方,当数据传输完成后,通知内核去处理。
截取MM32F0270的DMA各通道请求映像表如下,其中UART1_RX对应通道3。
各通道DMA请求一览表(部分) 实验 本次实验使用UART空闲中断功能,通过DMA方式把数据传送到指定的缓存区。当UART接收完一帧数据后,会产生一个空闲中断。这个中断在UART其他任何状态都不产生,只会在接收完一帧数据后才会产生,一帧数据可以是1个字节或者多个字节。因此,我们可以在这个空闲中断函数中,设置一个接收完成标志位。那么,我们只需要在主程序中检测这个标志位就知道数据是否接收完成了,如果数据接收完成,将数据发送到上位机显示。
程序部分
程序参考官网UART空闲中断代码,并在此基础上修改。
UART初始化
void UART1_NVIC_Init(u32 baudrate)
{
UART_InitTypeDef UART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphclockCmd(RCC_APB2ENR_UART1, ENABLE);
//UART1 NVIC
NVIC_InitStruct.NVIC_IRQChannel = UART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
//Baud rate
UART_StructInit(&UART_InitStruct);
UART_InitStruct.BaudRate = baudrate;
//The word length is in 8-bit data format.
UART_InitStruct.WordLength = UART_WordLength_8b;
UART_InitStruct.StopBits = UART_StopBits_1;
//No even check bit.
UART_InitStruct.Parity = UART_Parity_No;
//No hardware data flow control.
UART_InitStruct.HWFlowControl = UART_HWFlowControl_None;
UART_InitStruct.Mode = UART_Mode_Rx | UART_Mode_Tx;
UART_Init(UART1, &UART_InitStruct);
UART_Cmd(UART1, ENABLE);
UART1_GPIO_Init();
}
DMA初始化
void DMA_Config_Init(DMA_Channel_TypeDef* dam_chx, u32 cpar, u32 cmar, u16 cndtr)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);
DMA_DeInit(dam_chx);
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_PeripheralBaseAddr = cpar;
DMA_InitStruct.DMA_MemoryBaseAddr = cmar;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = cndtr;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_InitStruct.DMA_Auto_reload = DMA_Auto_Reload_Disable;
DMA_Init(dam_chx, &DMA_InitStruct);
UART_DMACmd(UART1, UART_DMAReq_EN, ENABLE);
DMA_Cmd(dam_chx, ENABLE);
}
在程序中调用DMA初始化函数配置DMA1_Channel3,将UART1接收寄存器的数据通过DMA搬运到接收缓冲区sRecvBuf[RECVBUFLENGTH],数据单元数目为RECVBUFLENGTH。DMA_Config_Init(DMA1_Channel3, (u32)&UART1->RDR, (u32)sRecvBuf, RECVBUFLENGTH);
UART中断服务函数
void UART1_IRQHandler(void)
{
/* Omit the code related to sending. */
// Recv packet
IF (UART_GetITStatus(UARTx, UART_ISR_RX) != RESET) {
UART_ClearITPendingBit(UARTx, UART_ICR_RX);
if(Flag_RecvComplete == 0) {
if(RecvCnt < RECVBUFLENGTH) { //(1)
RecvCnt++;
}
else {
RecvCnt = 0;
Flag_RecvComplete = 1; //(2)
}
}
}
//Idle interrupt
if (UART_GetITStatus(UARTx, UART_ISR_RXIDLE) != RESET) {
receive_len = RECVBUFLENGTH - DMA_GetCurrDataCounter(DMA1_Channel3); //(3)
if(receive_len > 0){
Flag_RecvComplete = 1; //(4)
}
UART_ClearITPendingBit(UARTx, UART_ICR_RXIDLE);
}
}
|