In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "the introduction and functional usage of serial port DMA in STM32". In daily operation, I believe that many people have doubts about the introduction and functional usage of serial port DMA in STM32. The editor consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the questions of "introduction and functional usage of serial port DMA in STM32". Next, please follow the editor to study!
Introduction to STM32 Serial Port DMA receiving variable length data
When using stm32 or other single-chip computers, serial communication is often used, so how to receive data effectively? If this piece of data is of variable length, how can it be received efficiently?
Classmate A: when the data comes, it will enter the serial port interrupt, just read the data in the interrupt!
Interrupt is to interrupt the normal operation of the program, how can it be efficient? Often interrupt the main program, do you still want to run the main program?
Classmate B: the serial port can be configured to receive data in the way of DMA, and you can read it after receiving it!
This student is right, we can use DMA to receive data, but DMA needs a fixed length to produce a receiving interrupt, how to receive data with variable length?
Introduction to DMA
Digression: in fact, the above question is very necessary to think about, keep thinking in order to make progress.
What is DMA?
DMA: full name Direct Memory Access, that is, direct memory access
DMA transports copy data from one address space to another. CPU only needs to initialize the DMA, and the transmission action itself is realized and completed by the DMA controller. A typical example is to move a block of external memory to a faster memory area inside the chip. This operation does not allow the processor to participate in the processing, CPU can do other things, when the DMA transfer is completed, there is an interrupt to tell CPU that I have finished, and then CPU knows it can process the data, which improves the utilization of CPU, because CPU is the brain, mainly for data operations, rather than to move data. DMA transmission is very important for high-performance embedded system algorithms and networks.
DMA resources in STM32
The MCU of the STM32F1 series has two DMA controllers (DMA2 exists only in high-capacity products), DMA1 has seven channels, and DMA2 has five channels, each of which is dedicated to managing memory access requests from one or more peripherals. There is also an arbitrator to coordinate the priority of each DMA request.
The MCU of the STM32F4/F7/H7 series has two DMA controllers with a total of 16 data streams (8 for each DMA controller). Each DMA controller is used to manage memory access requests for one or more peripherals. Each data stream can have a total of up to 8 channels (or requests). Each channel has an arbiter that handles priorities between DMA requests.
DMA receives data
When DMA receives the data, the serial port receiving DMA is on at the time of initialization, waiting for the arrival of the data. There is no need to do anything in the software, as long as the configuration is set up when initializing the configuration. When the data is received, tell CPU to deal with it.
Judge that the data reception is complete.
So the question is, how do you know if the data has been received?
In fact, there are many ways:
For fixed-length data, you only need to judge the number of data received to know whether the reception is complete. This is very simple and will not be discussed for the time being.
For variable-length data, in fact, there are several ways, troublesome I certainly will not introduce, students interested in doing complex work can see how others do online, the following method is the simplest, make full use of stm32 serial port resources, efficiency is also very high.
DMA+ serial port idle interrupt
The coordination of these two resources is simply flawless. No matter what variable-length data you receive, no matter how much data you have, I will accept one, just like Cantonese eat mangosteen and eat one at a time. I'm so scared.
Maybe when many people learn stm32, they don't know what idle is, so first look at the status register of stm32 serial port:
When we detect that the serial bus idle interrupt has been triggered, we know that this wave of data transmission is complete, and then we can get the data and process it. This method is the simplest, we do not need to do much processing, just need to configure, the serial port is waiting for the arrival of data, dma is also in the working state, to a data will automatically move a data.
Processing after receiving data
Serial port to receive data is to be processed, so what are the steps of processing?
Temporarily close the serial port to receive DMA channel, there are two reasons: 1. To prevent the subsequent data received, resulting in interference, because the data has not yet been processed. 2.DMA needs to be reconfigured.
Clear the DMA flag bit.
Gets the number of bytes of data received from the DMA register (optional).
Reset the number of bytes of data that DMA will receive next time, and note that the number of data transfers ranges from 0 to 65535. This register can only be written when the channel is not working (DMA_CCRx 's EN=0). After the channel is opened, the register becomes read-only, indicating the remaining number of bytes to be transferred. The register contents are decremented after each DMA transfer. At the end of the data transfer, the contents of the register either change to 0, or when the channel is configured in automatic reload mode, the contents of the register will be automatically reloaded to the previously configured value. When the content of the register is 0, no data transfer occurs regardless of whether the channel is open or not.
The semaphore is given and the new data flag is sent and received for the foreground program to query.
Open the DMA channel and wait for the next data reception. Note that the relevant registers of DMA are configured to write. If you reset the length of data received by DMA, you must do so under the condition of closing DMA, otherwise the operation is invalid.
Matters needing attention
The IDLE interrupt of STM32 will not always occur when there is no data reception in the serial port. The condition is like this: when the IDLE flag bit is cleared, the first data must be received before it begins to trigger. When the received data is cut off, no data is received, that is, IDLE interrupt is generated. If the rate of interrupting the transmission of data frames is very fast, and the MCU does not have time to process the data received this time, and if the data is interrupted and sent again, it cannot be opened here, otherwise the data will be overwritten. There are two ways to solve this problem:
Before reopening the receive DMA channel, copy the data in the Rx_Buf buffer to another array, then turn on DMA, and then process the copied data immediately.
Establish a double buffer and reconfigure the buffer address of the DMA_MemoryBaseAddr, so that the next received data will be saved to the new buffer and will not be overwritten.
Program realization
Experimental effect: when the external data is sent to the single-chip microcomputer, assuming that the frame data length is 1000 bytes, then when the single-chip microcomputer receives a byte, there will be no serial port interruption, but DMA silently carries the data to the buffer you specify. When the whole frame of data is sent, the serial port will have an interrupt. At this time, the DMA_GetCurrDataCounter () function can be used to calculate the data acceptance length, so as to carry out data processing.
The configuration of the serial port is very simple, basically the same as when using the serial port, but usually we open the receive buffer non-empty interrupt, but now we open the idle interrupt-USART_ITConfig (DEBUG_USARTx, USART_IT_IDLE, ENABLE);.
/ * * @ brief USART GPIO configuration, working parameter configuration * @ param none * @ retval none * / void USART_Config (void) {GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; / / turn on the clock DEBUG_USART_GPIO_APBxClkCmd (DEBUG_USART_GPIO_CLK, ENABLE) of the serial port GPIO / / turn on the clock DEBUG_USART_APBxClkCmd (DEBUG_USART_CLK, ENABLE) of the serial peripheral; / / configure the GPIO of USART Tx to push-pull multiplexing mode GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz GPIO_Init (DEBUG_USART_TX_GPIO_PORT, & GPIO_InitStructure); / / configure USART Rx's GPIO to float input mode GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init (DEBUG_USART_RX_GPIO_PORT, & GPIO_InitStructure) / / configure serial port working parameters / / configure baud rate USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; / / configure pin data word length USART_InitStructure.USART_WordLength = USART_WordLength_8b; / / configure stop bit USART_InitStructure.USART_StopBits = USART_StopBits_1 / / configure check bit USART_InitStructure.USART_Parity = USART_Parity_No; / / configure hardware flow control USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; / / configure working mode, send and receive USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx / / complete serial port initialization configuration USART_Init (DEBUG_USARTx, & USART_InitStructure); / / Serial port interrupt priority configuration NVIC_Configuration (); # if USE_USART_DMA_RX / / enable serial port idle IDEL interrupt USART_ITConfig (DEBUG_USARTx, USART_IT_IDLE, ENABLE) / / enable serial port DMA to receive USART_DMACmd (DEBUG_USARTx, USART_DMAReq_Rx, ENABLE); / * enable serial port DMA * / USARTx_DMA_Rx_Config (); # else / / enable serial port to receive interrupt USART_ITConfig (DEBUG_USARTx, USART_IT_RXNE, ENABLE) # endif#if USE_USART_DMA_TX / / enable serial port DMA send / / USART_DMACmd (DEBUG_USARTx, USART_DMAReq_Tx, ENABLE); USARTx_DMA_Tx_Config (); # endif / / enable serial port USART_Cmd (DEBUG_USARTx, ENABLE);}
Serial port DMA configuration
After configuring the DMA, you can directly open the DMA, make it in the working state, and move the data directly when it is available.
# if USE_USART_DMA_RX static void USARTx_DMA_Rx_Config (void) {DMA_InitTypeDef DMA_InitStructure; / / enable DMA clock RCC_AHBPeriphClockCmd (RCC_AHBPeriph_DMA1, ENABLE); / / set DMA source address: serial port data register address * / DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) USART_DR_ADDRESS / / memory address (pointer to the variable to be transferred) DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) Usart_Rx_Buf; / / Direction: from memory to peripheral DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; / / transfer size DMA_InitStructure.DMA_BufferSize = USART_RX_BUFF_SIZE / / Peripheral address does not increase DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; / / memory address increment DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; / / Peripheral data unit DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; / / memory data unit DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte / / DMA mode, one-time or circular mode / / DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; / / priority: medium DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; / / disable memory-to-memory transfer DMA_InitStructure.DMA_M2M = DMA_M2M_Disable / / configure DMA channel DMA_Init (USART_RX_DMA_CHANNEL, & DMA_InitStructure); / / clear all DMA flags DMA_ClearFlag (DMA1_FLAG_TC5); DMA_ITConfig (USART_RX_DMA_CHANNEL, DMA_IT_TE, ENABLE); / / enable DMA DMA_Cmd (USART_RX_DMA_CHANNEL,ENABLE);} # endif
After receiving the data processing
Because after receiving the data, there will be an idle interrupt, that is, an idle interrupt, so we can know in the interrupt service function that it has been received, and then we can process the data, but the context of the interrupt service function is interrupt, so, try to fast-forward and fast-out, generally set some signs in the interrupt for the foreground to query. In the interrupt, we first determine whether the type of interrupt we generate is an idle interrupt, and if so, proceed to the next step, otherwise we will ignore it.
/ * @ brief Serial Port interrupt Service function * @ author jiejie * @ version V1.0 * @ date 2018-xx-xx * * / void DEBUG_USART_IRQHandler (void) {# if USE_USART_DMA_RX / * use serial port DMA * / if (USART_GetITStatus (DEBUG_USARTx) USART_IT_IDLE)! = RESET) {/ * receive data * / Receive_DataPack () / / clear idle interrupt flag bit USART_ReceiveData (DEBUG_USARTx);} # else / * receive interrupt * / if (USART_GetITStatus (DEBUG_USARTx,USART_IT_RXNE)! = RESET) {Receive_DataPack ();} # endif}
Receive_DataPack ()
This is the real receiving data processing function, why should I wrap this function separately? Because this function is actually very important, because my code is compatible with ordinary serial port receiving and idle interrupts, and different receiving types have different processing, it is better to encapsulate them directly, and choose the way to receive them through macro definition in the source code! More considering the compatibility of the operating system, I may use dma+ idle interrupts in the system, so the semaphore for the foreground query may be different and may need to be modified, so I encapsulated it. But it doesn't matter. It's all the same.
/ * @ brief Uart_DMA_Rx_Data * @ param NULL * @ return NULL * @ author jiejie * @ github https://github.com/jiejieTop * @ date 2018-xx-xx * @ version v1.0 * @ note function called when receiving using serial port DMA * * / # if USE_USART_DMA_RXvoid Receive_DataPack (void) {/ * length of received data * / uint32_t buff_length / * disable DMA to prevent interference * / DMA_Cmd (USART_RX_DMA_CHANNEL, DISABLE); / * temporarily disable dma, data has not been processed * / / * clear DMA flag bit * / DMA_ClearFlag (DMA1_FLAG_TC5) / * get the received data length in bytes * / buff_length = USART_RX_BUFF_SIZE-DMA_GetCurrDataCounter (USART_RX_DMA_CHANNEL); / * get the data length * / Usart_Rx_Sta = buff_length; PRINT_DEBUG ("buff_length =% d\ n", buff_length) / * re-assign the count value, which must be greater than or equal to the maximum number of data frames that may be received * / USART_RX_DMA_CHANNEL- > CNDTR = USART_RX_BUFF_SIZE; / * it should be opened after data processing, such as opening * / DMA_Cmd (USART_RX_DMA_CHANNEL, ENABLE) in DataPack_Process (). / * (OS) give a signal and send a new data flag for the foreground program to query the * / / * mark that the reception is completed and process it in DataPack_Handle * / Usart_Rx_Sta | = 0xC000; / * DMA opens and waits for data. Note that if the rate of interrupting the sending of data frames is very fast, and the MCU does not have time to process the data received this time, and if the data is interrupted and sent again, it cannot be turned on here, otherwise the data will be overwritten. There are two ways to solve the problem: 1. Before reopening the receive DMA channel, copy the data in the Rx_Buf buffer to another array, then turn on DMA, and then process the copied data immediately. two。 Establish a double buffer and reconfigure the buffer address of the DMA_MemoryBaseAddr, so that the next received data will be saved to the new buffer and will not be overwritten. * /}
At this point, the study of "introduction and functional usage of serial port DMA in STM32" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.