1. Process of configuring MDA:
1. Turn on the RCC clock
2. Initialize DMA: configure the starting address of its peripherals and memory, data width, whether the address is incremented, their direction, how many channels there are, the cycle mode of DMA, configure the trigger mode, priority, and the last step is to enable DMA .
3. DMA transfer: First clear the counter, call the special function, enable the counter, which starts to decrement from the last sequence, determine whether the transfer is completed, and clear the flag.
2. Function module code and usage
1. This only has the DMA module
#include "stm32f10x.h" // Device header uint16_t MyDMA_Size; void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size) { MyDMA_Size=Size; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //Turn on the DMA clock \t DMA_InitTypeDef DMA_InitStructrue; DMA_InitStructrue.DMA_PeripheralBaseAddr=AddrA; DMA_InitStructrue.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte; //Data width 8 bits DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Enable; //Address increases automatically DMA_InitStructrue.DMA_MemoryBaseAddr=AddrB; DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte; DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable; //Address increases automatically DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC; //Direction A->B DMA_InitStructrue.DMA_BufferSize=Size; //How many channels DMA_InitStructrue.DMA_Mode=DMA_Mode_Normal; //DMA loop mode, single DMA_InitStructrue.DMA_M2M=DMA_M2M_Enable; //Software trigger DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium; //Medium priority DMA_Init(DMA1_Channel1, & DMA_InitStructrue); \t DMA_Cmd(DMA1_Channel1,DISABLE); //Open DMA } void MyMDA_Transfer(void) { DMA_Cmd(DMA1_Channel1,DISABLE); //Clear counter DMA_SetCurrDataCounter(DMA1_Channel1,MyDMA_Size); //Set to start transfer DMA_Cmd(DMA1_Channel1,ENABLE); //Enable counter, in reverse order from the last one, 4->1 while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET); //The transfer completion flag bit, the transfer completion flag position is 1 DMA_ClearFlag(DMA1_FLAG_TC1); //Clear the flag bit }
#include "stm32f10x.h" // Device header #include"OLED.h" #include"Delay.h" #include"MyDMA.h" uint8_t DataA[]={0x01,0x02,0x03,0x04}; uint8_t DataB[]={0,0,0,0}; int main(void) { OLED_Init(); MyDMA_Init((uint32_t)DataA,(uint32_t)DataB,4); \t OLED_ShowString(1,1,"DataA:"); OLED_ShowHexNum(1,9,(uint32_t)DataA,8); OLED_ShowString(3,1,"DataB:"); OLED_ShowHexNum(3,9,(uint32_t)DataB,8); while(1) { DataA[0] + + ; DataA[1] + + ; DataA[2] + + ; DataA[3] + + ; OLED_ShowHexNum(2,1,DataA[0],2); OLED_ShowHexNum(2,4,DataA[1],2); OLED_ShowHexNum(2,7,DataA[2],2); OLED_ShowHexNum(2,10,DataA[3],2); \t\t // OLED_ShowHexNum(4,1,DataB[0],2); // OLED_ShowHexNum(4,4,DataB[1],2); // OLED_ShowHexNum(4,7,DataB[2],2); // OLED_ShowHexNum(4,10,DataB[3],2); //Delay_ms(1000); MyMDA_Transfer(); \t\t // OLED_ShowHexNum(2,1,DataA[0],2); // OLED_ShowHexNum(2,4,DataA[1],2); // OLED_ShowHexNum(2,7,DataA[2],2); // OLED_ShowHexNum(2,10,DataA[3],2); \t\t OLED_ShowHexNum(4,1,DataB[0],2); OLED_ShowHexNum(4,4,DataB[1],2); OLED_ShowHexNum(4,7,DataB[2],2); OLED_ShowHexNum(4,10,DataB[3],2); Delay_ms(1000); \t\t } }
2. The first method of DMA and AD multi-channel
#include "stm32f10x.h" // Device header uint16_t AD_Values[4]; void AD_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //Turn on the ADC clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //6 frequency division, corresponding to 72MHZ/6=12MHZ \t GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //Initialize GPIO to input mode, other levels are inactive state GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); \t ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //Data right aligned ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //Trigger source select software trigger ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; //Conversion mode discontinuous conversion mode ADC_InitStructure.ADC_NbrOfChannel=4; //Specify how many sequences there are ADC_InitStructure.ADC_ScanConvMode=ENABLE; //Conversion mode continuous scan mode ADC_Init(ADC1, & amp;ADC_InitStructure); /*Configure ADC channels and sequences*/ ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5); /*Initialize DMA*/ DMA_InitTypeDef DMA_InitStructrue; DMA_InitStructrue.DMA_PeripheralBaseAddr=(uint32_t) & amp;ADC1->DR; //Peripheral starting address DMA_InitStructrue.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //Sixteen-bit half-word mode DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //The address does not increase automatically DMA_InitStructrue.DMA_MemoryBaseAddr=(uint32_t)AD_Values; //Memory starting address DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable; //Address increases automatically DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC; //Direction: Peripheral->Memory DMA_InitStructrue.DMA_BufferSize=4; DMA_InitStructrue.DMA_Mode=DMA_Mode_Normal; //DMA loop mode, single DMA_InitStructrue.DMA_M2M=DMA_M2M_Disable; //Trigger, do not use software trigger, use hardware trigger DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium; //Priority, medium priority DMA_Init(DMA1_Channel1, & DMA_InitStructrue); DMA_Cmd(DMA1_Channel1,ENABLE); //Enable DMA ADC_Cmd(ADC1,ENABLE); //Enable ADC ADC_DMACmd(ADC1,ENABLE); //ADC enables DMA \t ADC_ResetCalibration(ADC1); //Reset calibration while(ADC_GetResetCalibrationStatus(ADC1)==SET); //Wait for the reset calibration to be completed. When the reset calibration is completed (0), jump out of the loop. ADC_StartCalibration(ADC1); //Start calibration while(ADC_GetCalibrationStatus(ADC1)==SET); //Wait for calibration to complete } /* Calling this function triggers the transfer counter, the software triggers DMA transfer, and waits for the transfer to complete. After the transfer is completed, the obtained data is automatically transferred to the AD_Values array */ void AD_GetValues(void) { DMA_Cmd(DMA1_Channel1,DISABLE); DMA_SetCurrDataCounter(DMA1_Channel1,4); //Set to start transfer DMA_Cmd(DMA1_Channel1,ENABLE); \t ADC_SoftwareStartConvCmd(ADC1,ENABLE); //Use software trigger function while (DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET); DMA_ClearFlag(DMA1_FLAG_TC1); }
#include "stm32f10x.h" // Device header #include"OLED.h" #include"AD.h" #include"Delay.h" uint16_t AD0,AD1,AD2,AD3; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"AD0:"); OLED_ShowString(2,1,"AD1:"); OLED_ShowString(3,1,"AD2:"); OLED_ShowString(4,1,"AD3:"); \t while(1) { AD_GetValues(); OLED_ShowNum(1,5,AD_Values[0],4); OLED_ShowNum(2,5,AD_Values[1],4); OLED_ShowNum(3,5,AD_Values[2],4); OLED_ShowNum(4,5,AD_Values[3],4); Delay_ms(200); \t\t } }
3. The second way to use DMA and AD multi-channel is to write the function AD_GetValues(); which has one less return value than the previous one.
#include "stm32f10x.h" // Device header uint16_t AD_Values[4]; void AD_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); //Turn on the ADC clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //6 frequency division, corresponding to 72MHZ/6=12MHZ \t GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //Initialize GPIO to input mode, other levels are inactive state GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); \t ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; //Data right aligned ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //Trigger source select software trigger ADC_InitStructure.ADC_ContinuousConvMode=ENABLE; //Conversion mode continuous conversion mode ADC_InitStructure.ADC_NbrOfChannel=4; //How many sequences are specified? ADC_InitStructure.ADC_ScanConvMode=ENABLE; //Conversion mode continuous scan mode ADC_Init(ADC1, & amp;ADC_InitStructure); /*Configure ADC channels and sequences*/ ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5); /*Initialize DMA*/ DMA_InitTypeDef DMA_InitStructrue; DMA_InitStructrue.DMA_PeripheralBaseAddr=(uint32_t) & amp;ADC1->DR; //Peripheral starting address DMA_InitStructrue.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //Sixteen-bit half-word mode DMA_InitStructrue.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //The address does not increase automatically DMA_InitStructrue.DMA_MemoryBaseAddr=(uint32_t)AD_Values; //Memory starting address DMA_InitStructrue.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord; DMA_InitStructrue.DMA_MemoryInc=DMA_MemoryInc_Enable; //Address increases automatically DMA_InitStructrue.DMA_DIR=DMA_DIR_PeripheralSRC; //Direction: Peripheral->Memory DMA_InitStructrue.DMA_BufferSize=4; DMA_InitStructrue.DMA_Mode=DMA_Mode_Circular; //DMA circular mode, open DMA_InitStructrue.DMA_M2M=DMA_M2M_Disable; //Trigger, do not use software trigger, use hardware trigger DMA_InitStructrue.DMA_Priority=DMA_Priority_Medium; //Priority, medium priority DMA_Init(DMA1_Channel1, & DMA_InitStructrue); DMA_Cmd(DMA1_Channel1,ENABLE); //Enable DMA ADC_Cmd(ADC1,ENABLE); //Enable ADC ADC_DMACmd(ADC1,ENABLE); //ADC enables DMA \t ADC_ResetCalibration(ADC1); //Reset calibration while(ADC_GetResetCalibrationStatus(ADC1)==SET); //Wait for the reset calibration to be completed. When the reset calibration is completed (0), jump out of the loop. ADC_StartCalibration(ADC1); //Start calibration while(ADC_GetCalibrationStatus(ADC1)==SET); //Wait for calibration to complete \t ADC_SoftwareStartConvCmd(ADC1,ENABLE); //Use software trigger function }
#include "stm32f10x.h" // Device header #include"OLED.h" #include"AD.h" #include"Delay.h" uint16_t AD0,AD1,AD2,AD3; int main(void) { OLED_Init(); AD_Init(); OLED_ShowString(1,1,"AD0:"); OLED_ShowString(2,1,"AD1:"); OLED_ShowString(3,1,"AD2:"); OLED_ShowString(4,1,"AD3:"); \t while(1) { OLED_ShowNum(1,5,AD_Values[0],4); OLED_ShowNum(2,5,AD_Values[1],4); OLED_ShowNum(3,5,AD_Values[2],4); OLED_ShowNum(4,5,AD_Values[3],4); Delay_ms(200); \t\t } }