STM32 serial port DMA timeout reception method can greatly save CPU time

Publisher:火箭飞人Latest update time:2016-06-03 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
This method uses a timer to periodically query the data received by DMA. If it exceeds the set period, it is considered that the data packet has ended, and the data is copied to the buffer and handed over to other programs for processing. It can receive data packets of any size, especially suitable for protocols such as MODBUS. It has been used for GPS, GPRS, etc., and is very practical. This method takes up very little CPU time, especially when the baud rate is very high, the effect is more obvious.
When the data reception of a serial port times out, the data is copied to the buffer in the timer interrupt. The data flag UART1_Flag can be judged in the main program. When it is greater than 0, it means that data has been received and can be processed. After processing, this variable can be cleared.
When the interval between two data packets is small, the timer period can be shortened.

//Timeout definition
#define UART1_TimeoutComp 2 //20ms
#define UART2_TimeoutComp 10 //100ms
#define UART3_TimeoutComp 10 //100ms

#define SRC_USART1_DR (&(USART1->DR)) //Serial port receive register as source
#define SRC_USART2_DR (&(USART2->DR)) //Serial port receive register as source
#define SRC_USART3_DR (&(USART3->DR)) //Serial port receive register as source


extern u16 UART1_Flag,UART2_Flag,UART3_Flag;
extern u8 uart1_data[200],uart3_data[500],uart2_data[500];

u8 UART1_Timeout,UART2_Timeout,UART3_Timeout;
u16 UART1_FlagTemp,UART2_FlagTemp,UART3_FlagTemp;
u8 uart1_data_temp[200],uart2_data_temp[500],uart3_data_temp[500];

u16 uart1_Flag_last=0,uart2_Flag_last=0,uart3_Flag_last=0;

//Timer initialization
void TimerInit(void)
{
   //Timer initialization data structure definition
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
   //Initialize timer for timeout reception, 20ms

        //Reset counter
        TIM_DeInit(TIM2);                                                        

        TIM_TimeBaseStructure.TIM_Period = 100; //Count upper limit, 100*100us = 10000us = 10ms
        TIM_TimeBaseStructure.TIM_Prescaler = 4799; //Pre-divided 4800, 48MHz main frequency, divided clock period 100us
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //No frequency division
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //Count up
        TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
        //Initialize
        TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

        //Clear interrupt
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);


        //Enable timer interrupt
        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
       TIM_UpdateDisableConfig(TIM2,DISABLE); 
        //Timer clear
        TIM_SetCounter(TIM2,0);
        //Timer start        
      TIM_Cmd(TIM2,ENABLE);        
}


//DMA initialization, only one channel is listed, the other two channels are the same
void DMA5_Init(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  DMA_DeInit(DMA1_Channel5); //Reset DMA channel 1 register to default value
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR; //Source BUF is (&(USART1->DR))
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)uart1_data_temp; //Destination BUF is to be written into which array DMA_InitStructure.DMA_DIR 
  = DMA_DIR_PeripheralSRC; //Peripheral as source //Is the peripheral the destination or source of data transmission 
  DMA_InitStructure.DMA_BufferSize = 200; //The size unit of DMA buffer is set below
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Peripheral address register does not incrementDMA_InitStructure.DMA_MemoryInc
  = DMA_MemoryInc_Enable; //Memory address incrementDMA_InitStructure.DMA_PeripheralDataSize
  = DMA_PeripheralDataSize_Byte; //Peripheral bytes are in unitsDMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte
  ; //Memory bytes are in unitsDMA_InitStructure.DMA_Mode
  = DMA_Mode_Circular; //Work in circular cache modeDMA_InitStructure.DMA_Priority
  = DMA_Priority_High; //One of the 4 priorities (high priority) VeryHigh/High/Medium/Low
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //Non-memory to memoryDMA_Init 
  (DMA1_Channel5, &DMA_InitStructure); //Initialize DMA channel 1 register according to the parameters specified in DMA_InitStructDMA_ITConfig 
  (DMA1_Channel5, DMA_IT_TC, ENABLE); //DMA5 transfer completion 
  interruptUSART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //Enable USART1 receive DMA requestDMA_Cmd

  (DMA1_Channel5, ENABLE); //Formally allow DMA         
}

//Serial port initialization, only one channel is listed, the other two channels are        
the samevoid USART1_Configuration(void)
{
    //Serial port initialization data structure definitionUSART_InitTypeDef
        USART_InitStructure; 

        //Initialize the serial port to 38400,n,8,1
        USART_InitStructure.USART_BaudRate = 38400 ;
        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;
        //Initialize
        USART_Init(USART1, &USART_InitStructure);
        
        //Start the serial port, no need to receive interrupt
        USART_Cmd(USART1, ENABLE);
        
        //Default is set to input state   
        DMA5_Init();
}

//Timer interrupt service routine
void TIM2_IRQHandler(void)
{
  u16 i;   
  //Clear timer interrupt
  TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update); 

  UART1_Timeout++;
  UART2_Timeout++;
  UART3_Timeout++;
//------------------------------------------------------------------
  i=DMA_GetCurrDataCounter(DMA1_Channel5);
  DMA_ClearITPendingBit(DMA1_IT_GL5); //Clear all interrupt flagsif

  (i!=uart1_Flag_last) //Unfinished transmission
  {
          UART1_Timeout=0;
        uart1_Flag_last=i;
  }
  else
  {
    if(UART1_Timeout>UART1_TimeoutComp) //Timeout
        {
           if(i<200) //Data received
           {
                  UART1_FlagTemp=200-i; //Get the number of bytes receivedfor
              
                (i=0;i                  uart1_data[i]=uart1_data_temp[i];
                UART1_Flag=UART1_FlagTemp;
                
                DMA_ClearFlag(DMA1_FLAG_TC5);
                DMA_Cmd(DMA1_Channel5, DISABLE); //Formally allow DMA                 
                DMA5_Init();                  
           }
           UART1_Timeout=0;
        }
  }
  //------------------------------------------------------------------
  i=DMA_GetCurrDataCounter(DMA1_Channel6);
  DMA_ClearITPendingBit(DMA1_IT_GL6); //Clear all interrupt flags

  if(i!=uart2_Flag_last) //Unfinished transmission
  {
          UART2_Timeout=0;
        uart2_Flag_last=i;
  }
  else
  {
    if(UART2_Timeout>UART2_TimeoutComp) //Timeout occurs
        {
           if(i<500) //Data is received
           {
                  UART2_FlagTemp=500-i; //Get the number of bytes receivedfor

                (i=0;i                  [i]=uart2_data_temp[i];
                UART2_Flag=UART2_FlagTemp;
                
                DMA_ClearFlag(DMA1_FLAG_TC6);
                DMA_Cmd(DMA1_Channel6, DISABLE); //Formally allow DMA                 
                DMA6_Init();
                                
           }
           UART2_Timeout=0;
        }
  }
  //------------------------------------------------------------------
  i=DMA_GetCurrDataCounter(DMA1_Channel3);
  DMA_ClearITPendingBit(DMA1_IT_GL3); //Clear all interrupt flagsif

  (i!=uart3_Flag_last) //Unfinished transmission
  {
          UART3_Timeout=0;
        uart3_Flag_last=i;
  }
  else
  {
    if(UART3_Timeout>UART3_TimeoutComp) //Timeout occurs
        {
           if(i<500) //Data received
           {
                  UART3_FlagTemp=500-i; //Get the number of bytes receivedfor

                (i=0;i                  [i]=uart3_data_temp[i];
                UART3_Flag=UART3_FlagTemp;
                
                DMA_ClearFlag(DMA1_FLAG_TC3);
                DMA_Cmd(DMA1_Channel3, DISABLE); //Formally allow DMA                 
                DMA3_Init();  
                
           }
           UART3_Timeout=0;
        }
  }  
}
Keywords:STM32 Reference address:STM32 serial port DMA timeout reception method can greatly save CPU time

Previous article:STM32 serial port DMA mode receives data
Next article:Use of STM32 SPI DMA

Recommended ReadingLatest update time:2024-11-16 15:19

STM32 - interrupt priority
   Interrupts are an important type of system resource, which can play an indispensable role in the operation of hardware. Basically, every hardware will have corresponding interrupts, but it is just a matter of the type and number of interrupts. For example, the hardware of the 51 single-chip microcomputer has relati
[Microcontroller]
stm32 Flash read and write
                The programming operation of stm32 can be realized by reading and writing the flash inside stm32.                   The built-in programmable Flash of stm32 is of great significance in many occasions. For example, its support for ICP features allows developers to debug and develop stm32, and can prog
[Microcontroller]
The transplantation process of generating no less than 64 bytes of transmission based on STM32 HID routines
Preface This article briefly introduces how to use the ST USB HID (MOUSE) routine to generate a transplant process that can input and output any length less than or equal to 64 bytes. Problem description: HID is widely used in USB, but many applications are not simple mouse or keyboard operations, but some customiz
[Microcontroller]
The transplantation process of generating no less than 64 bytes of transmission based on STM32 HID routines
STM32 serial port obtains ammonia sensor data
Sensor: ZE03 electrochemical module NH3NH3 (0-100ppm) This is similar to the previous blog post about the STM32 serial port receiving laser dust sensor. Because this sensor provides serial port output data, other configurations can remain the same as the dust sensor. The main thing to do is to modify the serial port
[Microcontroller]
stm32-Serial port uses IDLE interrupt to accept variable length data method
Method 1: The serial port receives data, and the timer is used to determine whether the data reception is completed after the timeout. Method 2: DMA accept + IDLE interrupt Implementation idea: Use the serial port 1 of STM32F103, configure it to the idle interrupt IDLE mode and enable DMA reception, and set the re
[Microcontroller]
stm32-Serial port uses IDLE interrupt to accept variable length data method
STM32 APB1 bus clock configuration problem
When debugging the carrier communication system, I encountered such a problem: two devices, A and B, both used timers 2~4 for communication, PCLK1 of device A was configured as HCLK, and PCLK1 of device B was configured as 1/2HCLK. During the communication process, it was found that A and B could communicate occasional
[Microcontroller]
STM32 APB1 bus clock configuration problem
STM32 interrupt vector nesting NVIC understanding
1. Interrupt priority: The concept of priority in STM32 (Cortex-M3) There are two concepts of priority in STM32 (Cortex-M3) - preemptive priority and response priority. Some people call response priority 'sub-priority' or 'sub-priority'. Each interrupt source needs to be assigned these two priorities. An interrup
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号