Problem with DMA and USART receiving problem
Hello,
I have an STM32F107 microcontroller that uses DMA and USART to receive 250 bytes every 10 ms. The RTOS tick is 1 kHz, so osDelay(1) results in a delay of about 1 ms.
The sender transmits 200 bytes every 5 ms, and during this phase, it is not critical if a 200-byte packet is missed.
On the receiver side, I check DMA_GetCurrDataCounter to determine if 200 bytes have been received. Once 200 bytes are confirmed, I disable the DMA and start processing, which takes less than 1 ms. After processing, I re-enable the DMA and wait to receive the next packet.
__NO_RETURN static void app_main (void *argument){
int DMA_Buffer_Current;
USART3Config();
DMA_Configuration();
While(1)
{
DMA_Time_Alive=DMA_Time_Alive+1;
if(DMA_Time_Alive>=10)
{
DMA_Enable(false);
DMA_Time_Alive=0;
DMA_Enable(true);
}
DMA_Buffer_Current=500-DMA_GetCurrDataCounter(DMA1_Channel3);
If(DMA_Buffer_Current>=200)
{
DMA_Time_Alive=0;
DMA_Enable(false);
//Do Processing
DMA_Enable(true);
}
osDelay(4);
}
}
My DMA buffer[500] array has a size of 500, which is more than twice the size of the input packet.
void DMA_Configuration(void){
// DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ClearITPendingBit(DMA1_IT_TC3| DMA1_IT_TE3);
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel3,sizeof(Buffer));
DMA_DeInit(DMA1_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART3->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize =sizeof(Buffer);
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_Normal ;// DMA_Mode_Circular ;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Channel3,DMA_IT_TE, ENABLE);
USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
}
I've defined DMA_Time_Alive to confirm that DMA is operational and receiving packets every 10 ms.
Given the baud rate of 921600, each packet is fully transmitted in less than 3.5 ms.
DMA_Time_Alive=DMA_Time_Alive+1;
if(DMA_Time_Alive>=10)
{
DMA_Enable(false);
DMA_Time_Alive=0;
DMA_Enable(true);
}
As far as I understand, if there's an error in the DMA or USART, the DMA stops functioning. Therefore, even if errors occur, DMA_Time_Alive will reinitialize DMA every 40 ms. Furthermore, I handle all errors within the USART interrupts and DMA. Given that the DMA size is larger than each packet size, and considering that I disable and enable DMA upon receiving each packet size, I prefer to clear flags and disable the DMA when it's full.
void DMA1_Channel3_IRQHandler(void){ // USART3_RX
DMA_ClearITPendingBit(DMA1_IT_TC3| DMA1_IT_TE3);
DMA_Cmd(DMA1_Channel3, DISABLE);
USART_DMACmd(USART3, USART_DMAReq_Rx, DISABLE);
}
void USART3_IRQHandler(void){
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
USART_ReceiveData(USART3);
//USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
}
if (USART_GetITStatus(USART3, USART_IT_TXE) != RESET)
{
USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
}
if (USART_GetFlagStatus(USART3, USART_FLAG_FE) != RESET)
{
USART_ReceiveData(USART3);
USART_ClearFlag(USART3, USART_FLAG_FE);
}
if(USART_GetFlagStatus(USART3, USART_FLAG_PE) != RESET)
{
USART_ReceiveData(USART3);
USART_ClearFlag(USART3, USART_FLAG_PE);
}
if(USART_GetFlagStatus(USART3,USART_FLAG_ORE) != RESET)
{
USART_ReceiveData(USART3);
USART_ClearFlag(USART3,USART_FLAG_ORE);
}
if(USART_GetFlagStatus(USART3,USART_FLAG_NE) != RESET )
{
USART_ReceiveData(USART3);
USART_ClearFlag(USART3,USART_FLAG_NE);
}
}
here is my USART config:
void USART3Config(void){
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USARTConfigVar;
GPIO_InitTypeDef GPIOStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE);//Map
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
GPIO_PinRemapConfig(GPIO_PartialRemap_USART3,ENABLE);
GPIOStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING ;
GPIOStructure.GPIO_Pin=GPIO_Pin_11;
GPIOStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIOStructure);
GPIOStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIOStructure.GPIO_Pin=GPIO_Pin_10;
GPIOStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIOStructure);
USARTConfigVar.USART_BaudRate=921600;
USARTConfigVar.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 10;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//USART_DeInit(USART3);
USARTConfigVar.USART_StopBits=USART_StopBits_1;
USARTConfigVar.USART_WordLength=USART_WordLength_8b;
USARTConfigVar.USART_Parity=USART_Parity_No ;
USARTConfigVar.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART3,&USARTConfigVar);
USART_ITConfig(USART3, USART_IT_ERR, ENABLE);
USART_ITConfig(USART3, USART_IT_PE, ENABLE);
USART_Cmd(USART3,ENABLE);
}
But after about 30 minutes and working well, the DMA stops working and nothing is received even after 40ms that DMA_Time_Alive is present to reinitialize the DMA.
I need to know what my problem is.
