Brief Introduction to DMA
DMA: Direct Memory Access. In simple terms, it allows direct data interaction between RAM and other devices (peripherals) without CPU intervention.
DMA allows hardware devices operating at different speeds to communicate without relying on a heavy interrupt load on the CPU. Otherwise, the CPU would need to copy each piece of data from the source to a buffer and then write it back to a new location, during which the CPU cannot perform other tasks.
Advantages of DMA
The role of DMA in a system is akin to that of an employee in a company, with the CPU being the company owner.
The owner wants to send a package to Beijing and only needs to give a command to arrange for an employee to handle all the details, such as filling out the tracking number, logistics, and delivery. Finally, once the package is received, the employee notifies the owner.
Example Code: DMA Transmission Configuration
This article will briefly explain the configuration using the STM32F4 MCU and the standard peripheral library.
1. USART Configuration
USART (COM) macro definitions:
/* COMM communication */#define COMM_COM USART2#define COMM_COM_CLK RCC_APB1Periph_USART2#define COMM_COM_TX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART TX#define COMM_COM_TX_PIN GPIO_Pin_5#define COMM_COM_TX_GPIO_PORT GPIOD#define COMM_COM_TX_SOURCE GPIO_PinSource5#define COMM_COM_TX_AF GPIO_AF_USART2#define COMM_COM_RX_GPIO_CLK RCC_AHB1Periph_GPIOD //UART RX#define COMM_COM_RX_PIN GPIO_Pin_6#define COMM_COM_RX_GPIO_PORT GPIOD#define COMM_COM_RX_SOURCE GPIO_PinSource6#define COMM_COM_RX_AF GPIO_AF_USART2#define COMM_COM_IRQn USART2_IRQn#define COMM_COM_Priority 9 //Priority#define COMM_COM_BaudRate 115200 //Baud rate#define COMM_COM_IRQHandler USART2_IRQHandler //Interrupt function interface (see stm32f4xx_it.c)
USART Configuration:
/************************************************Function Name: USART_COMM_ConfigurationFunction: Communication port configurationParameters: NoneReturn Value: NoneAuthor: strongerHuang*************************************************/void USART_COMM_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Clock configuration */ RCC_AHB1PeriphClockCmd(COMM_COM_TX_GPIO_CLK | COMM_COM_RX_GPIO_CLK, ENABLE); if((USART1 == COMM_COM) || (USART6 == COMM_COM)) RCC_APB2PeriphClockCmd(COMM_COM_CLK, ENABLE); else RCC_APB1PeriphClockCmd(COMM_COM_CLK, ENABLE); /* Multiplexing configuration */ GPIO_PinAFConfig(COMM_COM_TX_GPIO_PORT, COMM_COM_TX_SOURCE, COMM_COM_TX_AF); GPIO_PinAFConfig(COMM_COM_RX_GPIO_PORT, COMM_COM_RX_SOURCE, COMM_COM_RX_AF); /* Pin configuration */ GPIO_InitStructure.GPIO_Pin = COMM_COM_TX_PIN; //USART Tx GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //Multiplexing mode GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(COMM_COM_TX_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = COMM_COM_RX_PIN; //USART Rx GPIO_Init(COMM_COM_RX_GPIO_PORT, &GPIO_InitStructure); /* NVIC configuration */ NVIC_InitStructure.NVIC_IRQChannel = COMM_COM_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_COM_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* USART configuration */ USART_InitStructure.USART_BaudRate = COMM_COM_BaudRate; //Baud rate USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Data bits USART_InitStructure.USART_StopBits = USART_StopBits_1; //Stop bits USART_InitStructure.USART_Parity = USART_Parity_No ; //Parity USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Receive and transmit function USART_Init(COMM_COM, &USART_InitStructure); USART_ClearFlag(COMM_COM, USART_FLAG_RXNE | USART_FLAG_TC); USART_ITConfig(COMM_COM, USART_IT_RXNE, ENABLE); //Enable receive interrupt USART_DMACmd(COMM_COM, USART_DMAReq_Tx, ENABLE); //Enable DMA USART_Cmd(COMM_COM, ENABLE); //Enable USART}
2. DMA Configuration
/* COMM_DMA */#define COMM_DR_ADDRESS ((uint32_t)USART2 + 0x04)#define COMM_DMA DMA1#define COMM_DMA_CLK RCC_AHB1Periph_DMA1#define COMM_TX_DMA_CHANNEL DMA_Channel_4#define COMM_TX_DMA_STREAM DMA1_Stream6#define COMM_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF6#define COMM_TX_DMA_IRQn DMA1_Stream6_IRQn#define COMM_TX_DMA_Priority 8 //Priority#define COMM_TX_DMA_IRQHandler DMA1_Stream6_IRQHandler //Interrupt function interface (see stm32f4xx_it.c)#define COMM_TX_DMA_IT_TCIF DMA_IT_TCIF6
/************************************************Function Name: USART_COMM_DMA_ConfigurationFunction: Communication port DMA configurationParameters: NoneReturn Value: NoneAuthor: strongerHuang*************************************************/void USART_COMM_DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Enable clock */ RCC_AHB1PeriphClockCmd(COMM_DMA_CLK, ENABLE); /* NVIC configuration */ NVIC_InitStructure.NVIC_IRQChannel = COMM_TX_DMA_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = COMM_TX_DMA_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* DMA configuration */ DMA_DeInit(COMM_TX_DMA_STREAM); DMA_InitStructure.DMA_Channel = COMM_TX_DMA_CHANNEL; //DMA channel DMA_InitStructure.DMA_PeripheralBaseAddr = COMM_DR_ADDRESS; //Peripheral address DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0; //Memory address (to be passed in) DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //Transfer direction DMA_InitStructure.DMA_BufferSize = 0; //Transfer length (to be passed in) DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Peripheral increment DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Memory increment DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //Data width DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //Normal mode DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //Priority DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(COMM_TX_DMA_STREAM, &DMA_InitStructure); DMA_ClearFlag(COMM_TX_DMA_STREAM, COMM_TX_DMA_FLAG_TCIF); DMA_ITConfig(COMM_TX_DMA_STREAM, DMA_IT_TC, ENABLE); //Enable DMA transfer complete interrupt DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //Initialize disable}
/************************************************Function Name: COMM_SendBufByDMAFunction: Send data via communication port through DMAParameters: Buf ------ Data (address) Length --- Data length (bytes)Return Value: NoneAuthor: strongerHuang*************************************************/void COMM_SendBufByDMA(uint8_t *Buf, uint16_t Length){ DMA_Cmd(COMM_TX_DMA_STREAM, DISABLE); //Disable DMA //Memory address DMA_MemoryTargetConfig(COMM_TX_DMA_STREAM, (uint32_t)Buf, DMA_Memory_0); DMA_SetCurrDataCounter(COMM_TX_DMA_STREAM, Length); //Set DMA transfer length DMA_Cmd(COMM_TX_DMA_STREAM, ENABLE); //Enable DMA}
Careful readers will notice that this send function is quite simple. Of course, this example uses the STM32F4 chip, but other chips are similar, and the principles are alike. The HAL library can also accomplish this.
Regarding the DMA transmission complete interrupt, depending on the actual situation, if using RTOS, the data transmission is generally a task that the OS waits (detects) for the transmission completion signal (i.e., DMA transmission complete interrupt).
Source: strongerHuang
Due to recent changes in the WeChat public platform push rules, many readers have reported not seeing updated articles in a timely manner. According to the latest rules, it is recommended to click on “Recommended Reading, Share, Favorite,” etc., to become a regular reader.
Recommended Reading:
-
“Chip Olympics” paper included, China ranks first in the world
-
All employees dismissed! Another electronic giant in Shenzhen announces closure
-
A Tesla in Shanghai allegedly caught fire, causing 12 luxury cars including Rolls Royce to be burned, with losses up to 50 million!
Please click 【View】 to give the author a thumbs up
