2024-03-29 07:55 AM
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!
Solved! Go to Solution.
2024-03-30 09:33 AM
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:
I used F4-Discovery board for this.
Hope it helps.
Please close this thread on this reply if it does answer your question.
2024-03-29 10:31 AM - edited 2024-03-29 10:33 AM
Hello,
I see in your code that the ADC trigger is set to TIM1 CC1 while TIM1 is not configured at all.
Could you please double check or at least test with "Conversion launched by Software"?
2024-03-29 11:25 AM
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?
2024-03-29 11:55 AM - edited 2024-03-29 11:55 AM
what do you mean by « all 3 channels read the same thing »?
2024-03-29 12:18 PM - edited 2024-03-29 12:20 PM
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.
If I haven't made myself clear obviously tell me so that I can explain myself better
2024-03-30 09:33 AM
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:
I used F4-Discovery board for this.
Hope it helps.
Please close this thread on this reply if it does answer your question.
2024-03-30 01:56 PM
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)?
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?
2024-03-31 08:53 AM
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)?
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.
2024-04-02 03:24 AM - edited 2024-04-04 01:01 PM
Thanks!
2024-04-04 01:02 PM
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?