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 support@ccsinfo.com

PIC24F ADC Done function getting stuck?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PIC24F ADC Done function getting stuck?
PostPosted: Wed Jan 29, 2014 10:09 am     Reply with quote

Hi all,
I'm finding a strange issue with some code I wrote to take consecutive reads of the ADC on a PIC24FV32KA302. In this specific case I'm looping through this code:

Code:

unsigned int8 index = 0;
unsigned int16 reading = 0;
int1 done = 0;
for (index=0; index < 100; index++){
     restart_wdt();
     read_adc(ADC_START_ONLY);
     while (!done){
          done = adc_done();
     }
     reading = read_adc(ADC_READ_ONLY);
     VBrt[index] = reading;
}

What ends up happening with this code is every couple minutes it gets hung up inside the adc_done() function and causes a processor reset due to WDT timeout. I tried kicking the WDT within the while(!done) loop to see if it was just getting stuck in the loop rather than the adc_done() function but it still resulted in an eventual WDT reset. In the time between starting up and when it gets stuck (usually 3-4 minutes into execution) the ADC conversions come back perfectly fine.

I have a workaround which is simply a 50uS delay between when the ADC starts and when I read it (it should be ample time to do a conversion):
Code:

for (index = 0; index < NUM_ADC_INDEX; index++){
      restart_wdt();
      read_adc(ADC_START_ONLY);
      delay_us(50);
      reading = read_adc(ADC_READ_ONLY);
      VBrt[index] = reading;     
   }


This seems to work without any problems but I would much rather have it trigger the read immediately after the ADC raises the done bit if possible so I'm not having to guess when the ADC is finished.

Has anyone come across anything like this problem that might have a suggestion? I am on PCWHD 4.132.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Jan 29, 2014 3:05 pm     Reply with quote

What happens if you get rid of all that stuff and just do this ?
Code:
reading = read_adc();

This should be the equivalent of your multi-line code.


Also, you didn't post your ADC setup lines, which could have some error
that causes the problem.
Ttelmah



Joined: 11 Mar 2010
Posts: 19458

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 1:40 am     Reply with quote

Several of the other PIC's in this family have an errata on the ADC, where the 'done' bit cannot reliably be used to detect the end of the conversion.
The solution is to define the interrupt bit (with a #bit statement), and test this instead.
You are not alone in finding that other chips which do not list this as a problem, intermittently do this. Search the Microchip forums, and you will find quite a few threads which end up coming down to this. Slowly more chips are having this added to their errata list....
It is affected by the clock rate of the CPU, the clock selected for the ADC, and whether any acquisition time is programmed in the ADC setup.
If I remember correctly, if you program some acquisition time, the problem disappears.
However as PCM_programmer says, keep it simple.
The internal function, has a fix for this that can be enabled, if you have the IDE. Select the device editor, and in the 'Errata' box, tick the square marked 'ADC sticks'. This then adds code to avoid the problem, if you use the standard function.

You should simplify the code to a 'bare minimum', and then report it to MicroChip, since it looks as if you have found another chip with the problem...

Best Wishes
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 8:29 am     Reply with quote

PCM programmer wrote:
What happens if you get rid of all that stuff and just do this ?
Code:
reading = read_adc();

This should be the equivalent of your multi-line code.


Also, you didn't post your ADC setup lines, which could have some error
that causes the problem.


That was actually the first thing I tried, I should have mentioned that.

As far as ADC setup it's not terribly out of the ordinary.
Code:

/*In header file*/
#device ADC=10
#define ADC_POT_CHANNEL 1        /*ADC Channel for Vbr*/

/*On Startup*/
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN1);  //AN1 and AN5 analog.  VSS - VREF+ range (0-5v)
set_adc_channel(ADC_POT_CHANNEL);


Ttelmah wrote:
Several of the other PIC's in this family have an errata on the ADC, where the 'done' bit cannot reliably be used to detect the end of the conversion.
The solution is to define the interrupt bit (with a #bit statement), and test this instead.
You are not alone in finding that other chips which do not list this as a problem, intermittently do this. Search the Microchip forums, and you will find quite a few threads which end up coming down to this. Slowly more chips are having this added to their errata list....
It is affected by the clock rate of the CPU, the clock selected for the ADC, and whether any acquisition time is programmed in the ADC setup.
If I remember correctly, if you program some acquisition time, the problem disappears.
However as PCM_programmer says, keep it simple.
The internal function, has a fix for this that can be enabled, if you have the IDE. Select the device editor, and in the 'Errata' box, tick the square marked 'ADC sticks'. This then adds code to avoid the problem, if you use the standard function.

You should simplify the code to a 'bare minimum', and then report it to MicroChip, since it looks as if you have found another chip with the problem...


I'll give these a shot and see if it does anything. Thanks for the help!
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 9:34 am     Reply with quote

Also maybe try resetting the done bit. You reset it when entering the loop but then the test does not evaluate for the other 99 readings. Go straight from START to READ.

Regards
Ttelmah



Joined: 11 Mar 2010
Posts: 19458

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 9:36 am     Reply with quote

Simplest one to try is to add ADC_TAD_MUL_4 and see if anything improves.

Best Wishes
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 10:07 am     Reply with quote

Just an update to note what I've tried.

The first thing I tried was setting the ADC Stuck in the errata. I also added ADC_TAD_MUL_4 into the arguments of the setup_adc function. This didn't seem to do too much. Maybe caused it to be a bit less frequent but that could just be me.

Right now I'm using the following code and it seems to be stable. Looks like triggering off the ISR is the way to go:
*Note that ADC_Done is a enumerated type BOOLEAN I made 0=FALSE 1=TRUE
Code:

/*ADC DONE ISR*/
#int_ADC1
void ADC_ISR(void){
ADC_Done=TRUE;
}

/*ADC READ FUNCTION*/
   unsigned int8 index = 0;
   unsigned int16 reading = 0;
   for (index = 0; index < NUM_ADC_INDEX; index++){
      restart_wdt();
      read_adc(ADC_START_ONLY);
      while (!ADC_Done){
      restart_wdt();
      }
      reading = read_adc(ADC_READ_ONLY);
      ADC_Done = FALSE;
      VBrt[index] = reading;     
   }



alan wrote:

Also maybe try resetting the done bit. You reset it when entering the loop but then the test does not evaluate for the other 99 readings. Go straight from START to READ.

Regards


you're totally right I can't believe I didn't catch that. I'll give that a shot next build.
Ttelmah



Joined: 11 Mar 2010
Posts: 19458

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 3:58 pm     Reply with quote

Whoa a lot.....

The ADC interrupt triggers when the conversion is complete. You don't want multiple starts and reads inside the interrupt handler. One read only.

You don't even want an interrupt handler!....
Code:

   #bit ADIF=getenv("BIT:AD1IF")

   ADIF=FALSE;
   read_adc(ADC_START_ONLY);
   while (!ADIF) ;
   value=read_adc(ADC_READ_ONLY);


Use this as the entire read_adc replacement. Do _not_ enable INT_ADC.

Best Wishes
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 4:11 pm     Reply with quote

Ttelmah wrote:
Whoa a lot.....

The ADC interrupt triggers when the conversion is complete. You don't want multiple starts and reads inside the interrupt handler. One read only.

You don't even want an interrupt handler!....
Code:

   #bit ADIF=getenv("BIT:AD1IF")

   ADIF=FALSE;
   read_adc(ADC_START_ONLY);
   while (!ADIF) ;
   value=read_adc(ADC_READ_ONLY);


Use this as the entire read_adc replacement. Do _not_ enable INT_ADC.

Best Wishes


You misunderstand. That code for the read isn't inside the interrupt (gee give me SOME credit lol)
The only line of code in the ADC_ISR is ADC_Done = TRUE.
The actual application code starts the conversion and holds in the loop until the ISR fires and sets the flag high. The loop will then break and perform the read.
Ttelmah



Joined: 11 Mar 2010
Posts: 19458

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 4:15 pm     Reply with quote

Fair enough, but you are then wasting an age. The interrupt gets called when the interrupt flag gets set. You currently have:

Flag gets set.
Handler gets called (lots of overhead).
You set your indicator.
Handler exits
code sees your indicator.

You can just test the interrupt flag _directly_. You never need call an interrupt handler at all. You might as well add back your time delay with the current approach....

In fact some of the ADC's, recommend using a delay, and reading at a very specific time after triggering the conversion or they will hang (some of the PIC18's have this one....).

Best Wishes
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Thu Jan 30, 2014 4:20 pm     Reply with quote

Overhead isn't really a concern but yeah I'll end up going with your method just for good practice. One less interrupt.

I'll also try this on another PIC18 based design that exhibited the same issue.
Ttelmah



Joined: 11 Mar 2010
Posts: 19458

View user's profile Send private message

PostPosted: Fri Jan 31, 2014 2:11 am     Reply with quote

As a question/comment, what PIC18's are you having ADC problems with?.

This particular problem with the 'done' flag, is specific to the PIC24. There are other problems with some PIC18's, but they require a more complex solution (in fact some are so bad, that you really need to pick another chip....).

In particular there are a few PIC18's, where the ADC itself gets into problems unless it is read at a totally specific time, the cycle before the DONE/ADIF bits set. The 'fix' in the erratum, is to set the GO/DONE bit, wait an exact number of machine cycles (which means interrupts have to be off), then read the registers. A real 'mess'....

Best Wishes
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Fri Jan 31, 2014 8:29 am     Reply with quote

Ttelmah wrote:
As a question/comment, what PIC18's are you having ADC problems with?.

This particular problem with the 'done' flag, is specific to the PIC24. There are other problems with some PIC18's, but they require a more complex solution (in fact some are so bad, that you really need to pick another chip....).

In particular there are a few PIC18's, where the ADC itself gets into problems unless it is read at a totally specific time, the cycle before the DONE/ADIF bits set. The 'fix' in the erratum, is to set the GO/DONE bit, wait an exact number of machine cycles (which means interrupts have to be off), then read the registers. A real 'mess'....

Best Wishes


Oh wow that's brutal. Some of these microchip errata are unreal.

I looked up the code I was thinking of and it turns out it's another PIC24F, not a PIC18. Same series at the one I created this thread about actually (a PIC24FV32KA304). Next time I have to test one of them I'll try this fix.
KTrenholm



Joined: 19 Dec 2012
Posts: 43
Location: Connecticut, USA

View user's profile Send private message

PostPosted: Fri Jan 31, 2014 9:58 am     Reply with quote

Ttelmah wrote:
Whoa a lot.....

The ADC interrupt triggers when the conversion is complete. You don't want multiple starts and reads inside the interrupt handler. One read only.

You don't even want an interrupt handler!....
Code:

   #bit ADIF=getenv("BIT:AD1IF")

   ADIF=FALSE;
   read_adc(ADC_START_ONLY);
   while (!ADIF) ;
   value=read_adc(ADC_READ_ONLY);


Use this as the entire read_adc replacement. Do _not_ enable INT_ADC.

Best Wishes


So I went ahead and tested this and I get an issue with the PIC restarting every few minutes with an "unknown" cause. I tried throwing a restart_wdt() into the while(!ADIF) loop just for laughs to see if anything would change and it now it just locks up after a while rather than rebooting. Thoughts/Ideas? It's almost like it's getting a WDT timeout but it's not showing up when I check the reset cause.
jeremiah



Joined: 20 Jul 2010
Posts: 1340

View user's profile Send private message

PostPosted: Fri Jan 31, 2014 3:19 pm     Reply with quote

What is the frequency of your oscillator/crystal or if not an oscillator/crystal, what clock settings are you using? Ideally, I would like to see your full list of FUSES and your #use delay() statement.

I know it seems like a weird question, but I work with the F version of these chips a lot, so I am curious if it is a similar problem I ran into.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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