STM32F103, DMA data transfer and two methods for use with AD multi-channel

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
}
}