CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

read_adc ADC_START_ONLY versus ADC_START_AND_READ versus...

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 656
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

read_adc ADC_START_ONLY versus ADC_START_AND_READ versus...
PostPosted: Tue Feb 03, 2026 4:19 pm     Reply with quote

I have been inspecting our PIC24 code lately trying to identify anything happening in an interrupt service routine which might conflict with things happening in the main loop.

During this, I came across this:

Code:
read_adc (ADC_START_ONLY);


We have two boards that initialize the ADC like this (instructing it to to one sample):

Quote:
adc_start_and_read (continually takes readings, this is the default)

adc_start_only (starts the conversion and returns)

adc_read_only (reads last conversion result)


Inside a timer interrupt service routine, we read the detector like this:

Code:
// Read the ADC value.
adc_buffer[g_indexADC++] = read_adc (ADC_READ_ONLY);

// Set the ADC start the next read.
read_adc (ADC_START_ONLY);


We are reading the last conversion from when the ISR happened last, then telling it to read again.

If I understand the help file, this means our samples are always behind, based on how fast this interrupt service routine is. If we have a 10ms timer, then every reading is what the ADC had 10 ms ago.

That is probably good enough, but wouldn't this be better:

Init with - read_adc (adc_start_and_read )

...then in the timer ISR just do "read_adc (ADC_READ_ONLY)"?

Would this work? Is there a downside, other than maybe using more power (which might be important if this was a battery-powered device)?
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202, 24FJ64GA002 and 24FJ1024GA606.
newguy



Joined: 24 Jun 2004
Posts: 1927

View user's profile Send private message

PostPosted: Tue Feb 03, 2026 10:57 pm     Reply with quote

Been a while since I've dealt with dsPIC A/D conversion, but if your PIC24 device is similar, from memory the only special quality that the dsPICs had over the PIC18s I normally use was the ability to automatically scan & convert one or more channels and use DMA to grab the samples. Some 8 bit PICs may have that capability now, but I haven't used it.

Given what you describe of the code it appears as though the A/D is being used in a conventional manner: do a conversion when asked. If you look at the A/D settings you'll be able to work out precisely how long a conversion actually takes to complete, and it's likely on the order of us or 10s of us. Depending on how fast you're running your processor this may be only a few clock cycles or may be a relative eternity. I suspect that the code has been structured to avoid the read_adc() function from blocking while a conversion is performed.

Again, from what you've described the code as structured seems "inefficient" from a sample gathering standpoint if the samples are 10ms "out of date" by the time they are actually read and subsequently acted upon. But in the grand scheme of things, does that 10ms matter? I suspect it doesn't.

If, however, it kind of does matter OR you're like me and want to ensure that a sample isn't 10ms old when it's finally acted upon, there's a simple solution: use the INT_AD interrupt. Inside your 10ms timer tick you leave the read_adc(ADC_START_ONLY); command. This ensures that your samples will be absolutely rock solid in the time domain.

Then in your INT_AD isr, you go ahead and read the value of the last conversion and do whatever calculations are necessary, and are presently in the 10ms timer isr.

This approach will only be effective if the number of instruction cycles the A/D actually takes is significant. If it's only a handful there's little downside in blocking while the A/D conversion is performed.
Ttelmah



Joined: 11 Mar 2010
Posts: 20030

View user's profile Send private message

PostPosted: Wed Feb 04, 2026 5:25 am     Reply with quote

No.
The default value is to start the ADC, _wait for the ADC to complete it's
reading_, and then return this. So if you used the default value, your ADC
would delay the exit from the timer routine by the time it takes the
ADC to perform a an acquisition and conversion.
The current approach means it starts the reading and immediately exits
the ISR, leaving the ADC getting on with it's acquisition and reading.
Now a lot depends on how fast the particular ADC is. A lot of the older
ADC's take quite a few mSec to actually do a acquisition, and then perform
the ADC sample. So on these triggering the ADC as you exit the routine,
saves having to wait for this time, and your ADC reading is not 10mSec
ago, but only 10 - (Tacq) ago.
As Jay says, the way to not have to wait for the acquisition and conversion
is to use INT_AD. Trigger the conversion when you want and then perform
the reading when INT_AD triggers. Where this gets really great is that
you could consider triggering the ADC off the timer (a lot of chips allow
this), and then do your current timer interrupt code in the INT_AD routine
with just READ_ONLY, letting the timer then trigger the next reading.
This way you arrive at the ADC handler when the reading is ready for you
with no extra overhead.
allenhuffman



Joined: 17 Jun 2019
Posts: 656
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Feb 04, 2026 8:19 am     Reply with quote

What about the continuous mode? Doesn't that solve this by having the ADC constantly sampling, so there is always the most recent value available?

Or am I misunderstanding the description -- that call, perhaps, just means "sample and read one time, now"?
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202, 24FJ64GA002 and 24FJ1024GA606.
newguy



Joined: 24 Jun 2004
Posts: 1927

View user's profile Send private message

PostPosted: Wed Feb 04, 2026 8:36 pm     Reply with quote

The ordinary read_adc() command is for one sample. The continuous modes require DMA and a deep read of the data sheet. Then often some experimentation too in order to get correct. Out of the realm of read_adc() territory.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group