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:
Zoom in to show:
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
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- Rambus Launches Industry's First HBM 4 Controller IP: What Are the Technical Details Behind It?
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- Are there any netizens working in the field of motors?
- Evaluation report summary: Mir MYS-8MMX
- Zigbee Technology Exchange
- ST's new 400W power board
- Allwinner V853+XR829 Tina wireless network wifimanger2.0 user guide
- Confusion about TFT LCD interface
- What is the function of TI DSP GEL file?
- EEWORLD University ---- stm32f407 video tutorial
- CCS compilation error: Solution for missing header file
- Regarding the timing issues and acquisition issues of AD chip ADS1251