STM32 serial port uses DMA to receive data test

Publisher:dswecdLatest update time:2016-06-02 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
environment:

Host: WINXP

Development environment: MDK4.23

MCU:STM32F103CBT6

 

illustrate:

The serial port can be configured to receive data using DMA, but DMA requires a fixed length to generate a receive interrupt. How can we receive data of variable length?

There are three methods:

1. Connect the RX pin to an external clock pin. When a frame is sent by the serial port, this timer can be used to generate a timeout interrupt. This has high real-time performance and can achieve real-time monitoring of 1 byte.

2. Without changing the hardware, start a timer to monitor DMA reception, and generate an interrupt if it times out. This is not very real-time, because the timeout must be greater than the time required to receive the frame, and the accuracy is difficult to control.

3. Some serial ports of STM32 microcontrollers can monitor whether the bus is idle, and generate an interrupt if it is idle. It can be used to monitor whether DMA reception is completed. This method has high real-time performance.

This article adopts the third method. The impact of large data packets at a baud rate of 576000 proves to be feasible.

 

source code:

 

//Serial port receive DMA buffer
#define UART_RX_LEN 128
extern uint8_t Uart_Rx[UART_RX_LEN];

//Serial port receive DMA buffer
uint8_t Uart_Rx[UART_RX_LEN] = {0};

//---------------------Serial port function configuration---------------------
	//Open the peripheral clock corresponding to the serial port  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	//Serial port DMA configuration  
	//Start DMA clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	//DMA send interrupt setting
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	//DMA1 channel 4 configuration
	DMA_DeInit(DMA1_Channel4);
	//Peripheral address
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
	//Memory address
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
	//dma transmission direction is one-way
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	//Set the length of the DMA buffer during transmission
	DMA_InitStructure.DMA_BufferSize = 100;
	//Set the DMA peripheral increment mode, a peripheral
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//Set DMA memory increment mode
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//Peripheral data word length
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	//Memory data word length
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	//Set DMA transfer mode
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	//Set the DMA priority level
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	//Set the variables in the two DMA memories to access each other
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel4,&DMA_InitStructure);
	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
	
	// Enable channel 4
	//DMA_Cmd(DMA1_Channel4, ENABLE);

	//Serial port receiving DMA configuration  
	//Start DMA clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	//DMA1 channel 5 configuration
	DMA_DeInit(DMA1_Channel5);
	//Peripheral address
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
	//Memory address
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
	//dma transmission direction is one-way
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	//Set the length of the DMA buffer during transmission
	DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
	//Set the DMA peripheral increment mode, a peripheral
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//Set DMA memory increment mode
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//Peripheral data word length
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	//Memory data word length
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	//Set DMA transfer mode
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	//Set the DMA priority level
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
	//Set the variables in the two DMA memories to access each other
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel5,&DMA_InitStructure);

	// Enable channel 5
	DMA_Cmd(DMA1_Channel5,ENABLE);
	
	  
    //Initialization parameters  
    //USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;  
    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_InitStructure.USART_BaudRate = DEFAULT_BAUD;
	// Initialize the serial port
    USART_Init(USART1,&USART_InitStructure);  
    //TXE send interrupt, TC transmission completion interrupt, RXNE receive interrupt, PE parity error interrupt, can be multiple   
    //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	//Interrupt configuration
	USART_ITConfig(USART1,USART_IT_TC,DISABLE);
	USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);  

	//Configure UART1 interrupt  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //Channel is set to serial port 1 interrupt  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //Interrupt preemption level 0  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //Interrupt response priority 0  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //Enable interrupt  
    NVIC_Init(&NVIC_InitStructure);   
        
	//Send using DMA
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
	//Receive using DMA
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
    //Start the serial port  
    USART_Cmd(USART1, ENABLE);

 

 

//Serial port 1 receive interrupt   
void USART1_IRQHandler(void)                               
{   
	uint32_t temp = 0;
	uint16_t i = 0;
	
	if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
    	//USART_ClearFlag(USART1,USART_IT_IDLE);
    	temp = USART1->SR;
    	temp = USART1->DR; // Clear USART_IT_IDLE flag
    	DMA_Cmd(DMA1_Channel5,DISABLE);

		temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
		for (i = 0;i < temp;i++)
		{
			Data_Receive_Usart = Uart_Rx[i];
		  	//Start the serial port state machine
			usart_state_run();
		}

		//Set the transmission data length
		DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
    	//Open DMA
		DMA_Cmd(DMA1_Channel5,ENABLE);
    }
	
	__nop();
}

Test Results:

Conditions: The microcontroller runs at 72M and communicates with the PC at a rate of 460800. The PC sends a 9-byte packet every 100ms: c5 5c 6 0 6F 10 5 4e f7.

Test: Each time the MCU receives this packet, an IO jumps to a level, and then processes and returns a packet.

Oscilloscope display:

STM32 serial port uses DMA to receive data test
 

Zoom in to show:

STM32 serial port uses DMA to receive data test
 

 

Keywords:STM32 Reference address:STM32 serial port uses DMA to receive data test

Previous article:STM32 RCC basic principles and configuration process
Next article:STM32's SPI uses DMA transmission test

Recommended ReadingLatest update time:2024-11-17 03:05

STM32 register list RCC clock related register
RCC_CR (Clock Control Register) Bit 25: PLLRDY-PLL clock ready flag (set by hardware after PLL is locked) Definition: 0 (unlocked), 1 (locked) Bit 24: PLLON - PLL enable (manual) Defined as: 0 (PLL off), 1 (PLL enabled). This bit is cleared by hardware when entering standby or stop mode. This bit cannot be cleared
[Microcontroller]
stm32 interrupt function changes the value of global variables
First describe the problem: When a key is detected, the PA.0 led flashes. The function cannot be written in the interrupt service program. I want to change the value of the variable biaozhi (0 to 1) after entering the interrupt function, and then the while loop in main keeps detecting the value of biaozhi. If it is
[Microcontroller]
Personal suggestions for getting started with stm32 from the library function direction
Necessary tools: stm32 development board, a book on library functions; (1) After selecting a development board, pay attention to the STM32 model corresponding to the board. Generally, F103ZET6 is selected. There is a lot of information online. Check the size of the flash it corresponds to. You will use it to set the
[Microcontroller]
STM32 FSMC TFT LCD
STM32+SSD1963+TFT(FSMC) has been debugged and passed the code. Two points to note: 1. External access addresses need to be added with volatile, otherwise Keil MDK optimization will optimize part of the code and cause errors.  The volatile keyword is a type modifier. The type variable declared with it indicates that it
[Microcontroller]
STM32 - Input capture of timer TIME module
The timer module of STM32 has very powerful functions. In addition to the ordinary timing function, it can also perform input capture and output comparison (PWM). PWM has been introduced in other articles. Now let's introduce input capture. Here are two questions I thought of during the test: Question 1: Can the s
[Microcontroller]
STM32 - Input capture of timer TIME module
USE_STDPERIPH_DRIVER, STM32F10X_HD description
If USE_STDPERIPH_DRIVER is not added when compiling the STM32 project, the following error will occur when compiling the STM32F10X_HD: ..\library\cortex_m3\stm32f10x.h(96): error:   #35: #error directive: "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" At this time,
[Microcontroller]
USE_STDPERIPH_DRIVER, STM32F10X_HD description
STM32 IAP implementation
After understanding the STM32 memory structure and related knowledge, we can design IAP. In the previous note, a simple IAP program structure and the system design of the interconnection with the User App program were carried out. This article discusses the details of IAP implementation in detail, including the desi
[Microcontroller]
STM32 IAP implementation
STM32 learning notes timer input capture experiment
Purpose: Print the time the key is pressed on the serial debugging assistant Experimental steps: Experimental Procedure: /******************************timer.c****************** *******************/   #include "sys.h"   #include "stm32f4xx.h"         extern u8 TIM5CHA1_CAPTURE_STA;   extern u16 TIM5CHA
[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号