The DMA part I used is relatively simple. Of course, maybe this is a new thing, and I can't use its complex functions for the time being. The following is a question and answer format to express my thoughts.
What is DMA used for?
Direct memory access is used to provide high-speed data transfer between peripherals and memory or between memory and memory. Data can be moved quickly through DMA without CPU intervention. This saves CPU resources for other operations.
How many DMA resources are there?
There are two DMA controllers, DMA1 has 7 channels and DMA2 has 5 channels.
Where is the data sent from and to?
Peripheral to SRAM (I2C/UART etc. get data and send it to SRAM);
Between the two regions of SRAM;
Peripheral to peripheral (ADC reads data and sends it to TIM1 to control it to generate different PWM duty cycles);
SRAM to peripherals (pre-stored data in SRAM is sent to DAC to generate various waveforms);
...There are some things that are still unclear.
How much data can DMA transfer?
The traditional concept of DMA is to transfer large amounts of data, but I understand that in STM32, its concept has been expanded, and perhaps more often speed is the focus of its application. The data can range from 1 to 65535.
Direct Memory Access (DMA) is a memory access technology in computer science. It allows certain hardware subsystems (computer peripherals) inside a computer to read and write system memory independently without bypassing the CPU. Under the same CPU load, DMA is a fast data transfer method. It allows hardware devices of different speeds to communicate without relying on a large number of interrupt requests from the CPU. [From Wikipedia]
Nowadays, more and more microcontrollers use DMA technology to provide high-speed data transfer between peripherals and memory or between memories. When the CPU initializes the transfer action, the transfer action itself is implemented and completed by the DMA controller. STM32 has a DMA controller with 7 channels, each of which is dedicated to managing one or more peripherals' requests for memory access, and an arbitrator to coordinate the priority of each DMA request.
The DMA controller and the Cortex-M3 core share the system data bus to perform direct memory data transfers. When the CPU and DMA access the same target (RAM or peripherals) at the same time, the DMA request may stop the CPU from accessing the system bus for several cycles, and the bus arbiter performs round-robin scheduling to ensure that the CPU can get at least half of the system bus (memory or peripherals) bandwidth.
After an event occurs, the peripheral sends a request signal to the DMA controller. The DMA controller processes the request according to the priority of the channel. When the DMA controller starts to access the peripheral, the DMA controller immediately sends an acknowledge signal to the peripheral. When receiving the acknowledge signal from the DMA controller, the peripheral immediately releases its request. Once the peripheral releases the request, the DMA controller also cancels the acknowledge signal. If more requests occur, the peripheral can start the next processing.
In summary, each DMA transfer consists of 3 operations:
1. Perform a load operation from a peripheral data register or from a memory location at the address specified by the DMA_CMARx register.
2. Store data into the peripheral data register or into the memory unit at the address specified by the DMA_CMARx register.
3. Perform a decrement of the DMA_CNDTRx register. This register contains the number of outstanding operations.
The arbiter initiates peripheral/memory access based on the priority of the channel request. The priority is divided into two levels: software (4 levels: highest, high, medium, low) and hardware (channels with lower numbers have higher priority than channels with higher numbers).
Interrupts can be generated when DMA transfer is halfway through, transfer is complete, and transfer errors occur.
Different DMA interrupts in STM32 (transfer complete, half transfer, transfer complete) are connected to NVIC via "wired OR" and need to be judged in the interrupt routine.
Before configuring DMA, do not forget to enable the DMA clock in the RCC settings. The DMA controller of STM32 is hung on the AHB bus.
DMA has a total of 7 channels, and the DMA mapping relationship of each channel is as follows:
The events of the peripherals are connected to the corresponding DMA channels. Each channel can be triggered by software to realize DMA data transfer within the memory (M2M mode)
Tips: In library 2.0, the parameter of the function RCC_AHBPeriphClockCmd is changed from "RCC_AHBPeriph_DMA" to "RCC_AHBPeriph_DMA1" (if it is a DMA1 controller).
The DMA transfer flags (CHTIFx, CTCIFx, CGIFx) are set to "1" by hardware, but need to be cleared by software and cleared in the interrupt service routine. When CGIFx (global interrupt flag) is cleared, CHTIFx and CTCIFx are also cleared.
Process: How to enable DMA? First of all, as we all know, initialization is required before any device is enabled. To initialize the module, you must first understand the corresponding structure and function of the module in order to set it correctly. Since DMA is relatively complex, I will only talk about the basic structure and common functions of DMA, which are provided by ST in the library function.
1. The following code is a standard DMA setting. Of course, it can be tailored according to the actual situation in actual application:
DMA_DeInit(DMA_Channel1);
The above sentence is to configure the channel for DMA. According to the information provided by ST, the DMA in STM3210Fx contains 7 channels (CH1~CH7), which means that 7 "bridges" can be provided for peripherals or memory (please allow me to use the word bridge, I think it is easier to understand, haha, don't "throw bricks"!);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
The DMA_InitStructure in the above statement is a DMA structure, which is declared in the library. Of course, it must be defined before use; DMA_PeripheralBaseAddr is a data member in the structure, giving DMA a starting address, just like a buffer starting address. The data flow is: peripheral register à DMA_PeripheralBaseAdd à memory variable space (or flash data space, etc.), ADC1_DR_Address is an address variable I defined;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
The above sentence is obviously the address of the variable in Memory that DMA wants to connect to. ADC_ConvertedValue is a variable I defined in memory myself.
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
The above sentence is to set the DMA transmission direction. As I said before, DMA can be bidirectional or unidirectional. Here it is set to unidirectional transmission. If bidirectional transmission is required, change DMA_DIR_PeripheralSRC to DMA_DIR_PeripheralDST.
DMA_InitStructure.DMA_BufferSize = 2;
The above sentence sets the length of the DMA buffer during transmission. The starting address of the buffer has been defined before: ADC1_DR_Address. For security and reliability, it is generally necessary to define a storage area for the buffer. There are three types of units for this parameter: Byte, HalfWord, and Word. I set 2 half-words (see the settings below); 1 half-word occupies 16 bits in a 32-bit MCU.
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
The above sentence sets the peripheral increment mode of DMA. If the channel (CHx) selected by DMA has multiple peripherals connected, you need to use the peripheral increment mode: DMA_PeripheralInc_Enable; in my example, DMA only establishes a connection with ADC1, so I choose DMA_PeripheralInc_Disable
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
The above sentence sets the memory increment mode of DMA. When DMA accesses multiple memory parameters, DMA_MemoryInc_Enable needs to be used. When DMA only accesses one memory parameter, it can be set to: DMA_MemoryInc_Disable.
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
The above sentence is to set the data length of each operation when DMA accesses. There are three types of data length, which have been mentioned before and will not be described here.
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
The same as above. No further explanation is given here.
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
The above sentence sets the DMA transfer mode: continuous loop mode. If you only want to access it once and then not access it (or ask it in reverse according to the instruction operation, that is, access it when you want it to access, and stop it when you don’t want it to access), you can set it to the general mode: DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
The above sentence is to set the DMA priority level: it can be divided into 4 levels: VeryHigh, High, Medium, Low.
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
The above sentence is to set the variables in the two memories of DMA to access each other.
DMA_Init(DMA_Channel1,&DMA_InitStructure);
The previous ones are settings for the DMA structure members. Now we will initialize the entire DMA module so that the DMA members are consistent with the above parameters.
/*DMA Enable*/
DMA_Cmd(DMA_Channel1,ENABLE);
Hahaha! I don’t think I’ll elaborate on this sentence, everyone will understand it at a glance.
At this point, the entire DMA is finally set up, but how is the DMA channel connected to the peripherals? Haha, this is also the thing I wanted to know the most at the beginning, don't worry! Let me have a cup of tea~~~~~~hahaha!
To establish an effective connection between DMA and peripherals, this is not the business of DMA itself, but the business of each peripheral. Each peripheral has a xxx_DMACmd(XXXx,Enable) function. If you want to establish an effective connection between DMA and ADC, use ADC_DMACmd(ADC1,Enable); (Here I enabled the ADC1 module in ADC).
A simple example transfer a word data buffer from FLASH memory to embedded SRAM memory.
In the V3.1.2 library location
STM32F10x_StdPeriph_Lib_V3.1.2\Project\STM32F10x_StdPeriph_Examples\DMA\FLASH_RAM
/* DMA1 channel6 configuration */
DMA_DeInit(DMA1_Channel6);
//peripheral base address
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SRC_Const_Buffer;
//memory base address
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DST_Buffer;
//data transfer direction Peripheral is source
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//buffer size Number of data to be transferred (0 up to 65535). Number of data transfers
DMA_InitStructure.DMA_BufferSize = BufferSize;
// the Peripheral address register is incremented
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
//the memory address register is incremented
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//the Peripheral data width
DMA_ InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//the DMAy Channelx will be used in memory-to-memory transfer
//DMA channel operation can be performed without peripheral request, this operation is memory to memory mode.
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);
/* Enable DMA1 Channel6 Transfer Complete interrupt */ DMA_ITConfig (
DMA1_Channel6, DMA_IT_TC, ENABLE);
/* Enable DMA1 Channel6 transfer */
DMA_Cmd(DMA1_Channel6, ENABLE); ===
... ) function, if DMA establishes a valid connection with ADC, use ADC_DMACmd (ADC1, Enable); (here I enabled the ADC1 module in ADC). /* DMA1 channel1 configuration ----------------------------------------------*/ DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value; //u16 AD_Value[2]; It should be OK without &. The array name represents the address DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 2; //############## Changed DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //############### Changed DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 channel 1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC1 configuration ------ ----------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None
; = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 2; //############## Changed
ADC_Init(ADC1, &ADC_InitStructure);
//Internal temperature sensor Add this sentence
/* Enable the temperature sensor and vref internal channel */
ADC_TempSensorVrefintCmd(ENABLE);
//############### changed
//################ Channel 10 (potentiometer )
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_13Cycles5);
//###### Internal temperature sensor Channel 16 ###################
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */Enable ADC1's DMA request image
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibaration register */ //Be sure to calibrate
ADC_ResetCalibration(ADC1) before use ;
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
Previous article:Create STM32L-DISCOVERY Project based on MDK-ARM
Next article:ARM learning notes 2 LED lighting program design
Recommended ReadingLatest update time:2024-11-15 13:43
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Why software-defined vehicles transform cars from tools into living spaces
- How Lucid is overtaking Tesla with smaller motors
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Wi-Fi 8 specification is on the way: 2.4/5/6GHz triple-band operation
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Vietnam's chip packaging and testing business is growing, and supply-side fragmentation is splitting the market
- Three steps to govern hybrid multicloud environments
- Three steps to govern hybrid multicloud environments
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Microchip Accelerates Real-Time Edge AI Deployment with NVIDIA Holoscan Platform
- Decoupling capacitors
- Summary of pspice circuit simulation
- Playing with Zynq Serial 40——[ex59] Binocular vision image acquisition and display example based on Zynq
- Summary and analysis of interference problems in circuit design
- Does the dummy pad have any impact on the electrical characteristics of the PCB?
- [HC32F460 Development Board Review] NO.2 Familiarity with the development process and different peripheral functions
- Classification of RFID readers and their advantages
- [Repost] Correctly select low noise amplifier
- NTC thermistor driver for MicroPython
- How does Cyclone2's ep2c8 provide clock to external ADC?