STM32串口DMA接收数据错位——暴力解决方法

背景:两片STM32通过串口通信,为了减小CPU负担,采用DMA进行通信,发送端为STM32F103C8T6,接收端为STM32F407VET6。在调试的过程中发现,一直出现数据错位的问题,接收端尝试了串口空闲中断和串口DMA传输完成中断,错位问题依旧,其实我之前遇到过这个问题,那次发送端没有使用DMA,而是直接用串口发送,接收端采用DMA接收完成中断,检测到错位后,延时重置DMA,直到DMA接收同步后,不再重置,此后DMA便会保持同步,不会错位。但是这次不知道为什么采用上次的方法没有解决,因此决定直接用最简单粗暴的方法——查找,但是弊端是会在中断中运行一段比较占空时间的代码。

 

说明:主要部分在接收中断(本文最后的代码段),发送端发送的DMA数据长度为a,接收端DMA配置的BufferSize为2a,这样即使错位,在2a的数据长度中也一定会存在一段完整的有效数据。接收中断中,在接收buffer的前半段查找帧头,找到之后,判断帧头+a-1的位置是否是帧尾,如果是,则基本可以认为中间即为有效数据,将该段数据拷贝到一个新的数组中,等待解析。

 

配置部分:发送端 STM32F103C8T6

/* uart3 for communicate with the master */
void vUart3Config(void)
{GPIO_InitTypeDef 	GPIO_InitStructure;USART_InitTypeDef       USART_InitStructure;NVIC_InitTypeDef 	NVIC_InitStructure;DMA_InitTypeDef		DMA_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* USART3_RX	  GPIOB.11 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);  /* USART3_TX   GPIOB.10 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART3, &USART_InitStructure);USART_Cmd(USART3, ENABLE); USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);{ /* send dma */USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE);DMA_DeInit(DMA1_Channel2);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(USART3->DR));DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendToMaster_Buff;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = USART3_DMA_send_buffersize;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel2,&DMA_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);DMA_Cmd(DMA1_Channel2,ENABLE);}
}

配置部分:接收端 STM32F407VET6

void vUTConfig(void)
{USART_InitTypeDef usart;GPIO_InitTypeDef  gpio;NVIC_InitTypeDef  nvic;DMA_InitTypeDef   dma;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);GPIO_PinAFConfig(GPIOA,GPIO_PinSource9 ,GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); /* USART1_RX	  GPIOA.10 */gpio.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;gpio.GPIO_Mode = GPIO_Mode_AF;gpio.GPIO_OType = GPIO_OType_PP;gpio.GPIO_Speed = GPIO_Speed_100MHz;gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA,&gpio);usart.USART_BaudRate = 115200;usart.USART_WordLength = USART_WordLength_8b;usart.USART_StopBits = USART_StopBits_1;usart.USART_Parity = USART_Parity_No;usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Init(USART1,&usart);USART_Cmd(USART1,ENABLE);{ /* receive dma */USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);DMA_DeInit(DMA2_Stream2);dma.DMA_Channel= DMA_Channel_4;dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);dma.DMA_Memory0BaseAddr = (uint32_t)ReceiveFromUT_Buffer;dma.DMA_DIR = DMA_DIR_PeripheralToMemory;dma.DMA_BufferSize = USART1_UT_DMA_receive_buffersize;dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;dma.DMA_MemoryInc = DMA_MemoryInc_Enable;dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;dma.DMA_Mode = DMA_Mode_Circular;dma.DMA_Priority = DMA_Priority_VeryHigh;dma.DMA_FIFOMode = DMA_FIFOMode_Disable;dma.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream2,&dma);nvic.NVIC_IRQChannel = DMA2_Stream2_IRQn;           nvic.NVIC_IRQChannelPreemptionPriority = 1;          nvic.NVIC_IRQChannelSubPriority = 1; nvic.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic);DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);DMA_Cmd(DMA2_Stream2,ENABLE);}
}

中断部分:发送中断

/* USART3 DMA send interrupt */
void DMA1_Channel2_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_IT_TC2)){DMA_ClearFlag(DMA1_IT_TC2);DMA_ClearITPendingBit(DMA1_IT_TC2);
//		DMA_Cmd(DMA1_Channel2,DISABLE);
//		DMA_SetCurrDataCounter(DMA1_Channel2,USART3_DMA_send_buffersize);
//		DMA_Cmd(DMA1_Channel2, ENABLE);}
}

中断部分:接收中断
 

/* USART1 dma receive for ut */
void DMA2_Stream2_IRQHandler(void)
{uint8_t i = 0;if(DMA_GetFlagStatus(DMA2_Stream2,DMA_IT_TCIF2) == SET){/* 在前半部分查找帧头并校验对应位置是否为帧尾 */for(i=0;i<(USART1_UT_DMA_receive_buffersize/2);i++){if((ReceiveFromUT_Buffer[i] == 0x05)&&(ReceiveFromUT_Buffer[i+USART1_UT_DMA_receive_buffersize-1] == 0x06)){/* 拷贝有效数据段到待解析数组 */memcpy(ReceiveFromUT_Data,&ReceiveFromUT_Buffer[i],USART1_UT_DMA_receive_buffersize/2);/* 数据解析 */UTReceive();}}/* 没有有效数据 */if(i >= USART1_UT_DMA_receive_buffersize/2){/* 重置DMA */DMA_Cmd(DMA2_Stream2,DISABLE);DMA_SetCurrDataCounter(DMA2_Stream2,USART1_UT_DMA_receive_buffersize);	DMA_Cmd(DMA2_Stream2,ENABLE);}DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);		}
}

 

——cloudos

——2020/4/17

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部