cancel
Showing results for 
Search instead for 
Did you mean: 

ADC multichannel using Interrupt

luke514
Senior

I have 3 potentiometers, one on each channel of the ADC, that vary 3V. The ADC reads the values and converts to voltage.

I have not been able by reading the datasheet and looking at some examples online to figure out how to get it to work using interrupts (with DMA it works).

I attach the entire project, can you kindly check it?

 

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions

Hello,

I looked at your software and indeed that's normal because you're in interrupt mode.

In each conversion you need to read ADC_DR register which common to all channels conversion. So every interrupt will be refreshed by the conversion of the next channel that will overwrite the previous one. Your implementation doesn't seem good.

In DMA mode, the DMA manages this automatically and it's triggered automatically by the ADC for each conversion and increments the memory (when configured by the user) to write to the correct memory location.

So in interrupt mode you need to select to trigger the ADC interrupt at each end of conversion not all channel conversions and in the callback (HAL_ADC_ConvCpltCallback) read the  ADC_DR register for each conversion to unsure that you are reading the correct channel.

I modified your example on which I read the 4 channels: 3 internal ADC channels and one external. I'm reading them one by one in this order:

  1. Temp sensor
  2. Vrefint
  3. VBAT
  4. CHANNEL1 (PA0)

SofLit_1-1711816121324.png

I used F4-Discovery board for this.

Hope it helps.

Please close this thread on this reply if it does answer your question.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

View solution in original post

12 REPLIES 12
SofLit
ST Employee

Hello,

I see in your code that the ADC trigger is set to TIM1 CC1 while TIM1 is not configured at all.

SofLit_0-1711733429539.png

SofLit_1-1711733494107.png

Could you please double check or at least test with "Conversion launched by Software"?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

You are right. By setting "Conversion launched by Software" all 3 channels read the same thing .. so I think the problem is with the code in the main.c

Being unfamiliar with ADC, if I use "Conversion launched by Software" what should I change in the main.c? What API should I use?

what do you mean by « all 3 channels read the same thing »?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

In all the three channels I read at the same time only the value of the potentiometer connected to channel three.

The other two potentiometers connected in the other two channels (first and second), when I turn them, it is as if they are not read.

luke514_0-1711739869222.png

If I haven't made myself clear obviously tell me so that I can explain myself better

Hello,

I looked at your software and indeed that's normal because you're in interrupt mode.

In each conversion you need to read ADC_DR register which common to all channels conversion. So every interrupt will be refreshed by the conversion of the next channel that will overwrite the previous one. Your implementation doesn't seem good.

In DMA mode, the DMA manages this automatically and it's triggered automatically by the ADC for each conversion and increments the memory (when configured by the user) to write to the correct memory location.

So in interrupt mode you need to select to trigger the ADC interrupt at each end of conversion not all channel conversions and in the callback (HAL_ADC_ConvCpltCallback) read the  ADC_DR register for each conversion to unsure that you are reading the correct channel.

I modified your example on which I read the 4 channels: 3 internal ADC channels and one external. I'm reading them one by one in this order:

  1. Temp sensor
  2. Vrefint
  3. VBAT
  4. CHANNEL1 (PA0)

SofLit_1-1711816121324.png

I used F4-Discovery board for this.

Hope it helps.

Please close this thread on this reply if it does answer your question.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Thank you! Your code works, I tested it with mine where I have the 3 potentiometers and it works.

Not knowing ADC in depth and not knowing english well I struggle a bit to understand, so I explicitly ask you these questions:

1) Reading through your code I understand that: when "HAL_ADC_ConvCpltCallback" triggers, the 1st channel is read by the ADC ... then when it triggers again the 2nd is read and finally on the third trigger the 3rd channel is read. Then this "cycle" repeats. So the ADC does not read all 3 channels at the same time but one at a time, in a row. Have I understood this correctly?

 

2) I tried to put the code you wrote in "HAL_ADC_ConvCpltCallback" into while(1) loop .. but the values read are completely crazy, i.e. they bounce from 2056 to 149 then 1800 etc. random values that seem to be noise. So I ask you, why is it that the few lines of code you wrote works written in "HAL_ADC_ConvCpltCallback" and not in while(1)?

luke514_0-1711831358269.png

 

3) To summarize, in DMA mode at each "HAL_ADC_ConvCpltCallback" the data read from the ADC are moved directly into memory ... while in interrupt at each "HAL_ADC_ConvCpltCallback" an interrupt is triggered?

 

 

 

 

 

Hello,


1) Reading through your code I understand that: when "HAL_ADC_ConvCpltCallback" triggers, the 1st channel is read by the ADC ... then when it triggers again the 2nd is read and finally on the third trigger the 3rd channel is read. Then this "cycle" repeats. So the ADC does not read all 3 channels at the same time but one at a time, in a row. Have I understood this correctly?


Your understanding is correct. There is only one DR register for regular conversion if a data conversion is available and you didn't read it, the next conversion will come and overwrites it. So you need to read it before the next conversion.


2) I tried to put the code you wrote in "HAL_ADC_ConvCpltCallback" into while(1) loop .. but the values read are completely crazy, i.e. they bounce from 2056 to 149 then 1800 etc. random values that seem to be noise. So I ask you, why is it that the few lines of code you wrote works written in "HAL_ADC_ConvCpltCallback" and not in while(1)?

luke514_0-1711831358269.png


As I said in point 1. You need to read the result of the conversion as soon as possible before the next conversion comes. Reading it in the callback will ensure that we are reading the data as soon as the conversion is available in the DR register. Reading the conversion in the while loop in main will let you losing the sequence of the conversion and get wrong data.


3) To summarize, in DMA mode at each "HAL_ADC_ConvCpltCallback" the data read from the ADC are moved directly into memory ... while in interrupt at each "HAL_ADC_ConvCpltCallback" an interrupt is triggered?


Yes.. and it's recommended to use DMA in continuous scan mode as the sequence is managed by HW to minimize the loss of data.

Hope it's clear for you.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Thanks!

I realized now that if in the code you sent me I try to change the "sampling time" of each channel (for example I change from 480 cycles to 84 cycles), as soon as I debug the code and turn one of the 3 potentiometers ... after a few correct readings all 3 values of "adc_value" in the Live Expession get stuck (they are prorpio immobilized!).ù

Is it always due to the fact that I need to read the conversion result as soon as possible before the next conversion? So by decreasing the number of cycles taken by the ADC (i.e. speeding up the reading on each channel) this does not happen..

Or is it a little "abnormal" behavior?