cancel
Showing results for 
Search instead for 
Did you mean: 

How to get data from ADC with STM32F7

Vera Berns
Associate II
Posted on February 03, 2018 at 23:02

So I wanted to read out multiple channels from adc3 on my stm32f7 discovery. I have been able to read out one channel and set up for multiple ones, but I can't figure out how to read out per channel. I wanted to read them out by interrupt so i set the adc up like this:

hadc3.Instance = ADC3;

hadc3.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;

hadc3.Init.Resolution = ADC_RESOLUTION_12B;

hadc3.Init.ScanConvMode = ENABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */

hadc3.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */

hadc3.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */

hadc3.Init.NbrOfDiscConversion = 0;

hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start trigged at each external event */

hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;

hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc3.Init.NbrOfConversion = 2;

hadc3.Init.DMAContinuousRequests = DISABLE;

hadc3.Init.EOCSelection = DISABLE;

if (HAL_ADC_Init(&hadc3) != HAL_OK)

{

/* ADC initialization Error */

Error_Handler();

}

/*♯♯-2- Configure ADC regular channel ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

sConfig.Channel = ADC_CHANNEL_8;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)

{

/* Channel Configuration Error */

Error_Handler();

}

/*♯♯-2- Configure ADC regular channel ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

sConfig.Channel = ADC_CHANNEL_0;

sConfig.Rank = 2;

sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)

{

/* Channel Configuration Error */

Error_Handler();

}

/*♯♯-3- Start the conversion process ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

if(HAL_ADC_Start_IT(&hadc3) != HAL_OK)

{

/* Start Conversation Error */

Error_Handler();

}

and then I have a callback where it will go when end of conversion, here i wanted to read the data out but I dont know how to read out per channel.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)

{

/* Get the converted value of regular channel */

ADC3ConvertedValue[0] = HAL_ADC_GetValue(AdcHandle);

ADC3ConvertedValue[1] = HAL_ADC_GetValue(AdcHandle);

char disp[50];

sprintf(disp, '%d%%', ADC3ConvertedValue[0]);

BSP_LCD_DisplayStringAtLine(1, (uint8_t*) disp);

char disp1[50];

sprintf(disp1, '%d%%', ADC3ConvertedValue[1]);

BSP_LCD_DisplayStringAtLine(2, (uint8_t*) disp1);

}

can anyone help me with reading this out. I dont want to use the dma because it conflicts with the lcd. Thank you.

#stm32 #stm32f7 #adc
8 REPLIES 8
Joerg Wagner
Senior III
Posted on February 04, 2018 at 11:05

You have to start multiple instances:

if(HAL_ADC_Start_IT(&hadc3) != HAL_OK) ...

if(HAL_ADC_Start_IT(&hadc0) != HAL_OK) ...

-------------------------------------------------------------------------------------

You started the reading for one channel only:

if(HAL_ADC_Start_IT(&hadc3) != HAL_OK) ...

In your case Channel 0, because it's the latest setting:

sConfig.Channel = ADC_CHANNEL_0;

I would define two variables hadc0 and hadc3 instead of one.

Posted on February 04, 2018 at 12:04

Thanks for your reply.

If you make two instances how do you read them out with the it handler, can i select which intance im reading or is there a way to see which instance im reading? With how I have it now i have in my it.c file the handler like this:

void ADC_IRQHandler(void)

{

HAL_ADC_IRQHandler(&hadc3);

}

how do I modify this for multiple instances?

Also in my implementation in my original code i ranked the channels as i read somewhere that this will help with reading out multiple channels, so the ranking method doesnt work when using interrupt?

Posted on February 04, 2018 at 13:53

It's not ADC specific and works for every IP, like Timer, UART, etc.

You can check which instance called the callback handler because the handle parameter is passed :

I used your function from above:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)

{

   if (AdcHandle==&hadc0) {

         ...

   }

   if (AdcHandle==&hadc3) {

         ...

   }

}

Posted on February 04, 2018 at 14:21

Thanks for the help. I still have some questions it is still not quite working. It is still reading out just one channel and not the other one, probably doing something wrong in the it.c file. 

I set the ADC's up like this:

hadc3.Instance = ADC3;

hadc3.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;

hadc3.Init.Resolution = ADC_RESOLUTION_12B;

hadc3.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */

hadc3.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */

hadc3.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */

hadc3.Init.NbrOfDiscConversion = 0;

hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start trigged at each external event */

hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;

hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc3.Init.NbrOfConversion = 1;

hadc3.Init.DMAContinuousRequests = DISABLE;

hadc3.Init.EOCSelection = DISABLE;

hadc3_0.Instance = ADC3;

hadc3_0.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;

hadc3_0.Init.Resolution = ADC_RESOLUTION_12B;

hadc3_0.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */

hadc3_0.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */

hadc3_0.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */

hadc3_0.Init.NbrOfDiscConversion = 0;

hadc3_0.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start trigged at each external event */

hadc3_0.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;

hadc3_0.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc3_0.Init.NbrOfConversion = 1;

hadc3_0.Init.DMAContinuousRequests = DISABLE;

hadc3_0.Init.EOCSelection = DISABLE;

if (HAL_ADC_Init(&hadc3_0) != HAL_OK)

{

/* ADC initialization Error */

Error_Handler();

}

if (HAL_ADC_Init(&hadc3) != HAL_OK)

{

/* ADC initialization Error */

Error_Handler();

}

/*♯♯-2- Configure ADC regular channel ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

sConfig.Channel = ADC_CHANNEL_8;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)

{

/* Channel Configuration Error */

Error_Handler();

}

/*♯♯-3- Start the conversion process ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

if(HAL_ADC_Start_IT(&hadc3) != HAL_OK)

{

/* Start Conversation Error */

Error_Handler();

}

/*♯♯-2- Configure ADC regular channel ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

sConfig.Channel = ADC_CHANNEL_0;

sConfig.Rank = 1;

sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;

sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&hadc3_0, &sConfig) != HAL_OK)

{

/* Channel Configuration Error */

Error_Handler();

}

/*♯♯-3- Start the conversion process ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

if(HAL_ADC_Start_IT(&hadc3_0) != HAL_OK)

{

/* Start Conversation Error */

Error_Handler();

}

in the interrupt file I put it now like this(guess this is wrong?)

   void ADC_IRQHandler(void)

   {

      HAL_ADC_IRQHandler(&hadc3);

      HAL_ADC_IRQHandler(&hadc3_0);

   }

And then i did the callback like you said:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)

{

if(AdcHandle == &hadc3)

{

BSP_LCD_DisplayStringAtLine(4, (uint8_t*) 'hadc3');

ADC3ConvertedValue[0] = HAL_ADC_GetValue(AdcHandle);

char disp[50];

sprintf(disp, '%d%%', ADC3ConvertedValue[0]);

BSP_LCD_DisplayStringAtLine(1, (uint8_t*) disp);

}

if(AdcHandle == &hadc3_0)

{

BSP_LCD_DisplayStringAtLine(5, (uint8_t*) 'hadc3_0');

ADC3ConvertedValue[1] = HAL_ADC_GetValue(AdcHandle);

char disp1[50];

sprintf(disp1, '%d%%', ADC3ConvertedValue[1]);

BSP_LCD_DisplayStringAtLine(2, (uint8_t*) disp1);

}

}

but im still getting for both channels the same value so do you know what im doing wrong?

I really appreciate your help.

Joerg Wagner
Senior III
Posted on February 05, 2018 at 00:54

I'm confused. You have 3 ADC's available. Which pins are connected?

Does the two channels share one ADC instance only?

It's good to know how your MSP_Init() looks like.

S.Ma
Principal
Posted on February 05, 2018 at 05:11

Find a close matching example from a nucleo or discovery board to get started. I've seen some post about ADC multiple channel conversion previously.

Sebastian K.
Associate II
Posted on February 06, 2018 at 21:54

I am pretty sure you want to setup one single ADC handle with

hadc3.Init.NbrOfConversion = 2;

and then assign Rank=1 and Rank=2 to each channel, because the way you do it it seems that there are two identical handles reading the same channels from the same ADC. Of course the values will be the same. I guess it's the one from ADC_CHANNEL_0 since it is configured last.

Vera Berns
Associate II
Posted on February 06, 2018 at 22:05

Thanks all for your reply.

I did start out with a example from the ADC but none of them show how to read out multiple channels from one ADC.

I also did try to set the numberofconversions to two but that didn't help even when I set te ranks of the channels. I also found another topic about it but can't find it anymore to link it. In that topic someone had the similar problem and fixed it used the EOC_FLAG. In the callback function of the ADC it looked if the EOC flag was set and if it was then they read out the data and started the IT handler again. I tried it that way but still the same values. Think I am going to try to just poll them as the interrupt doesn't seem to work.