cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F100 Multi-Channel ADC assitance?

Joe Grisso
Associate II
Posted on December 24, 2013 at 08:25

Hello all,

Long time lurker, first time poster. I've spent the past couple days working on a board designed aroumd a STM32F100RB processor, attempting to use ADC1 to scan a group of channels via DMA. I've followed the Standard Peripherals example and expanded it to handle multiple channels, but when I read the array that the DMA destination is set to, I am only able to read the output of the first channel converted. The rest of the array reads back as zero.

Here's the following init code blocks, in the order they are called from my main() function. I hopefully included all globals and defines so you can see the types I've set up for each system.

If it makes any difference, I'm building with a GCC toolchain.

&sharpdefine ADC1_DR_Address     ((uint32_t)0x4001244C)

&sharpdefine ADC_NUMCHANS 13

volatile unsigned short ADCValues[ADC_NUMCHANS];

void RCC_Configuration()

{

RCC_ADCCLKConfig(RCC_PCLK2_Div2);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);

}

void GPIO_Configuration()

{

GPIO_InitTypeDef GPIO_InitStructure;

/**************************************

* Configure PORTA GPIO 

*************************************/

/* ADC Inputs for Port A. */

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/**************************************

* Configure PORTC GPIO 

*************************************/

/* ADC Inputs */

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOC, &GPIO_InitStructure);

}

void ADC_Configuration()

{

ADC_InitTypeDef ADC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

/* Initialize ADC DMA Channel */

DMA_DeInit(DMA1_Channel1);

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCValues[0];

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_BufferSize = ADC_NUMCHANS;

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_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel1, ENABLE);

/* Initialize ADC */

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 = ADC_NUMCHANS;

ADC_Init(ADC1, &ADC_InitStructure);

/* ADC Channel Configuration */

ADC_RegularChannelConfig(ADC1, ADC_Channel_1,   1, ADC_SampleTime_55Cycles5);

ADC_RegularChannelConfig(ADC1, ADC_Channel_2,   2, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_3,   3, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_6,   4, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_7,   5, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_8,   6, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_9,   7, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_10,  8, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_11,  9, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 10, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 11, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 12, ADC_SampleTime_55Cycles5); 

ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 13, ADC_SampleTime_55Cycles5); 

ADC_DMACmd(ADC1, ENABLE);

ADC_Cmd(ADC1, ENABLE);

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1));

ADC_SoftwareStartConvCmd(ADC1, ENABLE);

}

/* Main execution loop */

int main()

{

/* Initialize the ARM System */

RCC_Configuration();

GPIO_Configuration();

ADC_Configuration();

/* Main execution loop - we should never exit from this */

while(1) {

/* ADC Test Code */

if(ADCValues[0] > 2048) {

ledOn(0);

} else {

ledOff(0);

}

if(ADCValues[1] > 2048) {

ledOn(1);

} else {

ledOff(1);

}

if(ADCValues[2 > 2048) {

ledOn(2);

} else {

ledOff(2);

}

}

}

The ledOn/ledOff function turns on GPIO mapped LEDs, which give me a quick pass/fail on ADC results. Once the quick validation failed I used a debugger to verify that the only element being updated in the ADCValues array was the first one.

If I didn't provide enough data to provide a proper analysis, please let me know what more I can provide.

Thanks in advance!

#stm32f1-adc-dma
4 REPLIES 4
Posted on December 24, 2013 at 13:49

Doesn't look too unreasonable, I might move the DMA enable after the calibration. Sorry don't have hardware to hand to dig further.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Joe Grisso
Associate II
Posted on December 24, 2013 at 17:28

Hi Clive,

Thanks for the prompt reply, and on a holiday no less! I moved the ADC_DMACmd enable after the calibration function, and didn't see a difference.

I will be away from my workbench until the weekend, so have a happy holiday and thanks again!

raptorhal2
Lead
Posted on December 24, 2013 at 21:39

Sometimes not initializing all structure members can cause problems. Try adding the following:

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

Cheers, Hal

Joe Grisso
Associate II
Posted on December 30, 2013 at 18:06

Hi Hal,

I initialized the DMA_M2M member of the structure, but that didn't change the result.

However, I can report success over the weekend. The ADC code was indeed correct, what was throwing me off was the LED timer interrupt - I've got multiplexed LEDs, and the interrupt frequency was about 6.5kHz. While that update rate isn't super-fast, it caused some irregularity when using DMA and the panel LEDs would not update reliably. Once I reduced the interrupt down to a more appropriate frequency, everything fell into place.

Sorry for the goose chase, and thanks for all the wonderful support!