cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple Channel ADC on STM32 L1 Discovery with CooCox

cht35
Associate II
Posted on January 29, 2016 at 13:46

Hello STM users,

I have been thrown in 'at the deep' using an STM32L152 in a commercial product design. I have inherited some code which uses the CooCox CooIDE for development and an STM32 L1 discovery board which uses the same IC. I am trying to get 4 channels of ADC acquisition working, either polled or ideally DMA/Interrupt driven. I've been through a few days of trawling the web now but can't seem to find an example which works in this environment. Most of my problems stem from differences in target IC for the examples I have found online. This si my first outing with STM, I'm used to Microchip.

Does anyone have a straight up example of multiple channel ADC on the L1 discovery board that may be compiled under CooCox?

Warmest regards from cold Mid Wales,

Peter

my CoIDE version is Version: 1.7.8

#discovery-l1-adc-multiple
15 REPLIES 15
Posted on January 29, 2016 at 14:41

This is a single up example, to do multiple, you select scan mode, tell it the number of channels, enumerate them with ranking.

[DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32%20ADC%20DMA%20Circular%20Mode&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=225]https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/STM32Discovery/STM32%20ADC%20DMA%20Circular%20Mode&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F¤tviews=225 CooCox has historically not called SystemInit() properly, in CMSIS implementations it is normally called before main() and the runtime initialization. For things that expect clocks to be working as expected you might need to call SystemInit() as you enter main(), to use more general examples. I might well have other examples, but the stuff is reasonable portable. You'd have to address the pin configuration and channels, but something like this

/* ADC Configuration */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // Multiple channels
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Continuously back-to-back
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 4;
ADC_Init(ADC1,&ADC_InitStructure);
/* ADC1 regular channel 1 for PA1 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_192Cycles);
/* ADC1 regular channel 2 for PA2 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_192Cycles);
/* ADC1 regular channel 3 for PA3 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_192Cycles);
/* ADC1 regular channel 4 for PA4 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_192Cycles);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
qwer.asdf
Senior
Posted on January 29, 2016 at 14:45

What library are you/they using? Standard Peripherals Library (

http://www.st.com/web/en/catalog/tools/PF257913

) or

http://www.st.com/web/en/catalog/tools/PF260821

or maybe something other? You can say it from the library file names, i.e. if it's stm32l1xx_adc.c then it's StdPeriph, if the filenames are like stm32l1xx_hal_adc.c then it's HAL.

In any case, you can find examples in the official packages of those libraries (linked above).

cht35
Associate II
Posted on January 29, 2016 at 14:54

Thanks Clive I shall have a gander at this and see what gives.

cht35
Associate II
Posted on January 29, 2016 at 14:56

The libraries I am using are the Std Periph ones. I'll take a look at the links you suggest thank you. Peter

cht35
Associate II
Posted on January 29, 2016 at 16:17

Hello Clive,

I am having progress, I can see values changing when I ground each of the pins however the grounded pin doesn't always match the indicated value on my output.

Its very possible that I haven't got my head round the GPIO to Analog channel mapping.

From the STM32L15x datasheet I found mappings of ADC_IN10 to PC0 etc. and am attempting to acquire the analog values on PC0 - 3.

I can see where GPIO Pin number is mapped but am unclear as to whether the initial 

line in GPIO_Init:

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

is where the Pin number is connected with the PCx ports rather than PAx for example.

Am I getting this part wrong?

Many thanks for your suggestions so far, I had the single acquire going already and had tried the multiple but neglected this line:

 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;

which seems to have sprung the multiple convert into life.

Here's my code so far in the quest:

#include ''stm32l1xx.h''

#include ''stm32l1xx_gpio.h''

#include ''stm32l1xx_rcc.h''

#include ''stm32l1xx_exti.h''

#include ''stm32l1xx_syscfg.h''

#include ''stm32l1xx_adc.h''

ADC_InitTypeDef ADC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

__IO uint16_t ADCdata[4] = { 0, 0, 0, 0};

void GPIO_Config(void);

void ADC_Config(void);

int main()

{

 GPIO_Config();

      ADC_Config();

 while(1)

 {

 ADCdata[0] = ADC_GetConversionValue(ADC1);

 printf(''ADC0 IS %d   '',ADCdata[0]);

 ADCdata[1] = ADC_GetConversionValue(ADC1);

 printf(''ADC1 IS %d   '',ADCdata[1]);

 ADCdata[2] = ADC_GetConversionValue(ADC1);

 printf(''ADC2 IS %d   '',ADCdata[2]);

 ADCdata[3] = ADC_GetConversionValue(ADC1);

 printf(''ADC3 IS %d \n'',ADCdata[3]);

}

}

void GPIO_Config(void)

{

 /* Enable The HSI (16Mhz) */

 RCC_HSICmd(ENABLE);

 /* Enable the GPIOC Clock */

 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

 /* Configure GPIO pins to Analog mode */

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

 GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;

 GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;

 GPIO_Init(GPIOA, &GPIO_InitStructure);

 /* Check that HSI oscillator is ready */

 while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);

}

void ADC_Config(void)

{

  /* ADC1 Configuration ------------------------------------------------------*/

  /* Enable ADC1 clock */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

  /* Setup ADC Structure */

  ADC_StructInit(&ADC_InitStructure);

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;

  ADC_InitStructure.ADC_ScanConvMode = ENABLE;

  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;

  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;

  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

  ADC_InitStructure.ADC_NbrOfConversion = 4;

  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC channels configuration */

  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_192Cycles);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_192Cycles);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_192Cycles);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_192Cycles);

  /* Enable ADC1 */

  ADC_Cmd(ADC1, ENABLE);

  /* Wait until ADC1 ON status */

  while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET)

  {

  }

  /* Start ADC1 Software Conversion */

  ADC_SoftwareStartConv(ADC1);

  /* Wait until ADC end of conversion */

  while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)

  {

  }

}

cht35
Associate II
Posted on January 29, 2016 at 16:41

duh!  Guess who just spotted where the connection is - in the GPIO Init of couirse where I haveGPIOA should be GPIOC.

onward...
cht35
Associate II
Posted on January 29, 2016 at 16:45

Here is the output I am getting at present with PC0 only grounded and the other pins floating, almost seems like the number of channels being converted isn't correct, or I am not interpreting the acquired data correctly, or my GPIO setup is still wrong.

ADC0 IS 2088   ADC1 IS 1809   ADC2 IS 1813   ADC3 IS 1204 

ADC0 IS 1191   ADC1 IS 1626   ADC2 IS 1822   ADC3 IS 1621 

ADC0 IS 0   ADC1 IS 1206   ADC2 IS 1219   ADC3 IS 0 

ADC0 IS 1   ADC1 IS 1622   ADC2 IS 0   ADC3 IS 1802 

ADC0 IS 1198   ADC1 IS 1816   ADC2 IS 1209   ADC3 IS 0 

ADC0 IS 1798   ADC1 IS 0   ADC2 IS 1625   ADC3 IS 1824 

ADC0 IS 1635   ADC1 IS 1   ADC2 IS 1213   ADC3 IS 1625 

ADC0 IS 0   ADC1 IS 1211   ADC2 IS 1213   ADC3 IS 1 

ADC0 IS 8   ADC1 IS 1214   ADC2 IS 1621   ADC3 IS 1621

Posted on January 29, 2016 at 17:23

You can't do this, you have to use DMA for multiple channels

ADCdata[0] = ADC_GetConversionValue(ADC1);
printf(''ADC0 IS %d '',ADCdata[0]);
ADCdata[1] = ADC_GetConversionValue(ADC1);
printf(''ADC1 IS %d '',ADCdata[1]);
ADCdata[2] = ADC_GetConversionValue(ADC1);
printf(''ADC2 IS %d '',ADCdata[2]);
ADCdata[3] = ADC_GetConversionValue(ADC1);
printf(''ADC3 IS %d 
'',ADCdata[3]);

And use the DMA interrupts to provide EOC, also the data is going to change faster than you can print it to a terminal. So you'd need to take a snap shot of the measurements, and then print them. Now if you need 4 measurements in a polled loop, don't use continuous mode, leave the DMA in circular, and then trigger the set of 4 conversions, and wait for DMA TC to flag (vs ADC EOC)
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on January 29, 2016 at 17:25

See the complete example in the thread I cited, and merge in the second fragment in place of the single up configuration, along with the pin configurations.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..