Jump to content

STM32 Discovery ADC with DMA

Recommended Posts

There was a commenter on an earlier posted post explaining just this. He does say he's using a Discovery kit. Hopefully this helps you. All credit goes to "Tony":


* Test code for the Discovery Board. In this version we use the DMA to store the information
* of two converted channels (channel 14 and channel 15) into a pre-defined variable. The method
* is continuous and the value of the ADC are continuously stored in the variable.

#include "stm32f10x.h"
#include "STM32vldiscovery.h"

#define ADC1_DR_Address ((uint32_t)0x4001244C)

//==Global Variable declerations==
uint16_t ADC_Val; //Stores the calculated ADC value
double voltage1; //Used to store the actual voltage calculated by ADC for the 1st channel
double voltage2; //Used to store the actual voltage calculated by ADC for the 2nd channel

__IO uint16_t ADCConvertedValue[2]; //Array that is used to store the calculated DMA values for ADC1

* This function sets up the pins connected to the LED's as outputs; the blue LED
* is connected to pin 8 (Port C) and the green LED is connected to pin 9 (Port C).
void Configure_LED_Pins() {

//==Configure the pins connected to the LED's to be outputs==
//Blue LED is on pin 8 of Port C and Green LED is on pin 9 of Port C

//Enable the clock for the port, by default this is off i.e. Enable GPIOC Clock
RCC->APB2ENR |= RCC_APB2Periph_GPIOC; //APB2 indicates we dealing with the high speed bus
//ENR means we want to enable the register

//Specify the pins as either inputs or outputs
GPIOC->CRL = 0x11111111; //This is definition for pins 0 - 7; each pin is configured with respect to CONTROL:MODE
//All pins set to output mode (general purpose output push-pull)
GPIOC->CRH = 0x44444433; //This is definition for pins 8 - 15; pin 8 and 9 set as output (50Mhz), general purpose output

//Set all pins to 0V
GPIOC->ODR = 0x0000; //The output port only uses the first 16 bits; the last 16 isn't used...
//Here we are turning off all the pins...

}//end Configure_LED_Pins

* Sets up Pin.C4 (Channel 14) and Pin.C5 (Channel 15) to be used as analog inputs. The first channel
* of the DMA is also setup to be used with ADC1. ADC1 is setup to continuously output data to the
* array "ADCConvertedValue"
void ADC_DMA_Configuration() {
GPIO_InitTypeDef GPIO_InitStructure; //Variable used to setup the GPIO pins
DMA_InitTypeDef DMA_InitStructure; //Variable used to setup the DMA
ADC_InitTypeDef ADC_InitStructure; //Variable used to setup the ADC

//==Configure the systems clocks for the ADC and DMA==
//ADCCLK = PCLK2 / 4
RCC_ADCCLKConfig(RCC_PCLK2_Div4); //Defines the ADC clock divider. This clock is derived from the APB2 clock (PCLK2). The
//ADCs are clocked by the clock of the high speed domian (APB2) dibivied by 2/4/6/8. The
//frequency can never be bigger than 14MHz!!!!

//--Enable DMA1 clock--
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

//--Enable ADC1 and GPIOC--
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);

//==Configure ADC pins (PC.04 -> Channel 14 and PC.05 -> Channel 15) as analog inputs==
GPIO_StructInit(&GPIO_InitStructure); // Reset init structure, if not it can cause issues...
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);

//==Configure DMA1 - Channel1==
DMA_DeInit(DMA1_Channel1); //Set DMA registers to default values
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //Address of peripheral the DMA must map to
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) & ADCConvertedValue; //Variable to which ADC values will be stored
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 2; //Buffer size (2 because we using two channels)
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
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); //Initialise the DMA
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable the DMA1 - Channel1

//==Configure ADC1 - Channel 14 and Channel 15==
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_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 2; //We using two channels

ADC_Init(ADC1, &ADC_InitStructure); //Initialise ADC1

//Setup order in which the Channels are sampled....
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 2, ADC_SampleTime_55Cycles5);

ADC_Cmd(ADC1, ENABLE); //Enable ADC1

//==Calibrate ADC1==

//Enable ADC1 reset calibaration register
while (ADC_GetResetCalibrationStatus(ADC1)); //Check the end of ADC1 reset calibration register

//Start ADC1 calibaration
while (ADC_GetCalibrationStatus(ADC1)); //Check the end of ADC1 calibration

}//end ADC_Configuration

* Simple program that reads our AD port, in this case pin 4 on port C. The following program does the following:
* The converted voltage is stored in the global variable 'voltage'; the following things are done when the voltage value is
* obtained:
* 0.000 < = V No LEDs on
* 0.825 <= V Green LED on; Blue LED off
* 1.650 <= V Blue LED on; Green LED off
* 2.475 <= V Green LED on; Blue LED on
* Since the variable 'voltage' is a global variable, its value can be checked when debugging the code....
void ADC_DMA_Test_Program() {
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

while (1) {
 //==Get the ADC value of channel 14==
 ADC_Val = ADCConvertedValue[0];
 voltage1 = (2.984 * ADC_Val) / 4096;
 //==Get the ADC value of channel 15==
 ADC_Val = ADCConvertedValue[1];
 voltage2 = (2.984 * ADC_Val) / 4096;

 if ((voltage1 >= 0) && (voltage1 < 0.825)) {
	 ODR = 0b0000000000000000; //Turn off both LED's
 } else if ((voltage1 >= 0.825) && (voltage1 < 1.65)) {
	 ODR = 0b0000001000000000; //Turn on the green LED
 } else if ((voltage1 >= 1.65) && (voltage1 < 2.475)) {
	 ODR = 0b0000000100000000; //Turn on the blue LED
 } else {//voltage1 >= 2.475 && voltage
	 ODR = 0b0000001100000000; //Turn on both LED's
}//end while(1)
}//end ADC_Test_Program

* Main program start
int main(void) {
//**Micro clock settings**
//Done by default from startup_stm32f10x_xx.s before coming to main! You can edit SystemInit() in system_stm32f10x.c


return 0;
}//end main

Read more: http://www.micromouseonline.com/2009/05/26/simple-adc-use-on-the-stm32/#ixzz1z6KvzrLv

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...