stm32AD single channel and multi-channel conversion (DMA)

Publisher:电子科技爱好者Latest update time:2016-12-20 Source: eefocusKeywords:stm32AD Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Chapter 3 AD Conversion

This chapter is divided into two parts. The first is the single channel conversion of AD, and the second is the multi-channel conversion of AD. First, convert the single channel.

The maximum conversion frequency of the AD built into STM32 is 14MHZ, with a total of 16 conversion channels.

ADC123_IN10 indicates that the PC0 pin can be used as the 10th channel of AD1, AD2, and AD3.

Next, we will take the example of configuring PC0 to be channel 10 of AD1.

3.1 First we should set PC0 as analog input:

#include "adc.h"

/*Why define ADC1_DR_Address as ((u32)0x40012400+0x4c)

, because the address of the register storing the AD conversion result is 0x4001244c*/

#define ADC1_DR_Address ((u32)0x40012400+0x4c)

/*Define variable ADC_ConvertedValue to store the converted data of AD1 channel 10*/

__IO uint16_t ADC_ConvertedValue;


static void ADC1_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable ADC1 and GPIOC clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1

RCC_APB2Periph_GPIOC,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

|

3.2 After setting the port, the next step is of course to initialize AD:

Here we need to add a knowledge point DMA. DMA is equivalent to a secretary of the CPU. Its role is to help the CPU reduce its burden. To be more specific, it helps the CPU to transfer data. We all know that after each AD conversion, the result of the conversion will be placed in a fixed register. In the past, if we want to assign the value in the register to a variable, we will use the assignment statement. If we do not use DMA, the assignment statement will be completed by the CPU. The CPU is already busy dealing with other things, and now it has to solve such a simple problem as the assignment statement. It will be painful. So we need DMA, the secretary, to help him solve this problem. Since DMA is just a secretary, it is relatively stupid. You can only complete the task well if you explain the task clearly. So how to give DMA a task? Smart people must have thought of it, of course, it is the "DMA_Init(DMA1_Channel1, &DMA_InitStructure)" function. Let's explain the task to DMA step by step.

/* Function name: ADC1_Mode_Config

* Description: Configure ADC1 to work in MDA mode

* Input: None

* Output: None

* Call: Internal call

*/

static void ADC1_Mode_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

ADC_InitTypeDef ADC_InitStructure;

/* Set the registers related to DMA to their initial values*/

DMA_DeInit(DMA1_Channel1);

/*Define the DMA peripheral base address. Here, ADC1_DR_Address is defined by the user, which is the register for storing conversion results. Its function is to tell DMA to fetch data from ADC1_DR_Address. */

DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address;

/*Define the memory base address, that is, tell DMA to put the number taken from AD into ADC_ConvertedValue*/

DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue;

/*Define AD peripheral as the source of data transmission, that is, tell DMA to take data from AD and put it into memory, not vice versa*/

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

/*Specify the size of the DMA buffer of the DMA channel, that is, tell the DMA to open up several memory spaces. Since we only take the AD data of channel 10, we only need to open up one memory space*/

DMA_InitStructure.DMA_BufferSize = 1;

/*Set the register address to be fixed, that is, tell DMA to only fetch data from a fixed location*/

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

/*Set the memory address to be fixed, that is, each time DMA is used, only the data is moved to the fixed memory*/

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

/*Set the peripheral data width, that is, tell DMA the size of the number to be taken*/

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;


/*Set the memory width*/

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

/*Set DMA to work in circular buffer mode, that is, tell DMA to keep moving data and not be lazy*/ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

/*Set the software priority of the channel selected by DMA*/

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

/* Enable DMA channel1. The CPU has several DMA secretaries. Now only DMA1_Channel1 is used.

This secretary*/

DMA_Cmd(DMA1_Channel1, ENABLE);

/*Set ADC to work in independent mode*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

/*Specify that the AD conversion works in single-shot mode, that is, sampling one channel*/

ADC_InitStructure.ADC_ScanConvMode = DISABLE ;

/*Set AD conversion in continuous mode*/

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

/*Do not use external trigger conversion*/

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; /*The collected data is stored in the register in a right-aligned manner*/

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

/*Set the number of AD channels to be converted*/

ADC_InitStructure.ADC_NbrOfChannel = 1;

ADC_Init(ADC1, &ADC_InitStructure);

/*Configure ADC clock to be 8-divided by PCLK2, i.e. 9MHz*/

RCC_ADCCLKConfig(RCC_PCLK2_Div8);

/*Configure ADC1 channel 11 to 55.5 sampling cycles*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */

ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

/*Reset calibration registers*/

ADC_ResetCalibration(ADC1);

/*Wait for calibration register reset to complete*/

while(ADC_GetResetCalibrationStatus(ADC1));

/* ADC calibration */

ADC_StartCalibration(ADC1);

/* Wait for calibration to complete */

while(ADC_GetCalibrationStatus(ADC1));

/* Since no external trigger is used, the ADC conversion is triggered by software*/

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

After configuring the above program, every time AD is converted, DMA will move the conversion result to the variable

ADC_ConvertedValue, instead of using assignment statements every time to get the AD converted value.


Part 2: AD Multi-channel Sampling

#include "adc.h"

#define ADC1_DR_Address ((u32)0x40012400+0x4c)

/*Define array variable ADC_ConvertedValue[2] to store the converted data of AD1 channels 10 and 11*/

__IO uint16_t ADC_ConvertedValue[2];

/*

* Function name: ADC1_GPIO_Config

* Description: Enable the clocks of ADC1 and DMA1, and set PC0 and PC1 as analog input

* Input: None

* Output: None

* Call: Internal call

*/

static void ADC1_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable DMA clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/* Enable ADC1 and GPIOC clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

/* Function name: ADC1_Mode_Config

* Description: Configure ADC1 to work in MDA mode

* Input: None

* Output: None

* Call: Internal call

*/

static void ADC1_Mode_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

ADC_InitTypeDef ADC_InitStructure;

/* DMA channel1 configuration */

DMA_DeInit(DMA1_Channel1);

/*Define the DMA peripheral base address, which is the register that stores the conversion result*/

DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address; /*Define memory base address*/

DMA_InitStructure.DMA_MemoryBaseAddr

=(u32)&ADC_ConvertedValue;

/*Define AD peripheral as the source of data transmission*/

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

/*Specify the size of the DMA buffer of the DMA channel, that is, how many memory spaces need to be opened. This experiment has two conversion channels, so two are opened*/

DMA_InitStructure.DMA_BufferSize = 2;

/*Set register address fixed*/

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /*Set the memory address to increment, that is, each DMA transfers the value in the peripheral register to two memory spaces*/

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /*Set peripheral data width*/

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

/*Set the memory width*/

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

/*Set DMA working recirculation buffer mode*/

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

/*Set the software priority of the channel selected by DMA*/

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel1, &DMA_InitStructure);

/* Enable DMA channel1 */

DMA_Cmd(DMA1_Channel1, ENABLE);

/*Set ADC to work in independent mode*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

/*Specify that the AD conversion works in scan mode, that is, sampling multiple channels*/ ADC_InitStructure.ADC_ScanConvMode = ENABLE;

/*Set AD conversion in continuous mode*/

ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

/*Do not use external trigger conversion*/

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

/*The collected data is stored in the register in a right-aligned manner*/

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

/*Set the number of AD channels to be converted*/

ADC_InitStructure.ADC_NbrOfChannel = 2;

ADC_Init(ADC1, &ADC_InitStructure);

/*Configure ADC clock to be 8-divided by PCLK2, i.e. 9MHz*/

RCC_ADCCLKConfig(RCC_PCLK2_Div8);

/*Configure the conversion order and sampling time of channels 10 and 11 of ADC1 to be 55.5 sampling cycles*/

ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);

/* Enable ADC1 DMA */

ADC_DMACmd(ADC1, ENABLE);

/* Enable ADC1 */

ADC_Cmd(ADC1, ENABLE);

/*Reset calibration registers*/

ADC_ResetCalibration(ADC1);

/*Wait for calibration register reset to complete*/

while(ADC_GetResetCalibrationStatus(ADC1));

/* ADC calibration */

ADC_StartCalibration(ADC1);

/* Wait for calibration to complete */

while(ADC_GetCalibrationStatus(ADC1));

/* Since no external trigger is used, the ADC conversion is triggered by software*/

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}


The differences between single-channel sampling and multi-channel sampling are

The second program is marked in red, pay attention to the comparison.

Summary: DMA is a selfless porter. If you want to put the value in the peripheral register into the memory, it originally needs the CPU to complete it. Now DMA helps the CPU to complete it, which liberates the CPU to a certain extent.


Keywords:stm32AD Reference address:stm32AD single channel and multi-channel conversion (DMA)

Previous article:How does the STM32 library read and write some pins of the same group of IO ports?
Next article:Detailed explanation of STM32 firmware library

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号