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

How can I improve ADC accuracy?
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
addthebadd



Joined: 20 Dec 2005
Posts: 4
Location: Bristol, UK

View user's profile Send private message

How can I improve ADC accuracy?
PostPosted: Fri Dec 30, 2005 4:04 am     Reply with quote

I am trying to get a reasonably accurate measurment from a potentiometer. I am using a 18F4550 which in theory has 10bit ADC. The stability of the reading is 7bit at most the remaining 3 bits are constantly changing. I have tried using the start sleep read method but the accuracy did not improve. This was admittedly using the internal 8Mhz oscillator. I am now using an external 20Mhz crystal, but like this, I have net been able to use the start sleep read method as the chip wont wake up. I am using the standard setup_interrupts(INT_AD) and setup_interrupts(GLOBAL) but the chip completes everything upto the sleep, then it's off to the land of nod! The only way I have been able to get a stable reading is to average a sequence of conversions. Currently I am reading 128 times to get a stable result. Overkill I know!!!!!

Sorry if this is a bit of a basic request. I am very new to PIC programming and CCS.
_________________
Adam Walker
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Fri Dec 30, 2005 4:10 am     Reply with quote

It looks like a noise problem rather then an accuracy problem. Add a capacitor (0.1uF of bigger) between the A/D pin and ground. This will reduce the noise. Also make sure that your power supplies are decoupled with 0.1uF and 10uF cpacitors. Another question is: what's the total resistance of your pot. To get accurate readings, it should be below 2.5k.
addthebadd



Joined: 20 Dec 2005
Posts: 4
Location: Bristol, UK

View user's profile Send private message

PostPosted: Fri Dec 30, 2005 4:30 am     Reply with quote

I'll get onto the capacitors immediately! The pot is a 10k and it's currently running straight from the ground to +5v. Do I need to get a new pot or can I tweak the circuit?
_________________
Adam Walker
addthebadd



Joined: 20 Dec 2005
Posts: 4
Location: Bristol, UK

View user's profile Send private message

PostPosted: Fri Dec 30, 2005 5:41 am     Reply with quote

0.1uF capaictor now in the circuit and the stability has improved. It now sits at 8 to 9 bits accuracy. Thank you very much!

I'm not sure how to 'decouple the power supply' I'll have to read my electronics books!!!

I'm still having problems with putting the chip to sleep and getting it to wake up when the ADC completes. The code looks like this:-

setup_adc_ports(AN0|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_16);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
setup_low_volt_detect(FALSE);
setup_oscillator(OSC_8MHZ || OSC_INTRC);

while(true)
{
set_adc_channel(0);
read_adc(ADC_START_ONLY);
enable_interrupts(INT_AD);
sleep();
s0_value = read_adc(ADC_READ_ONLY);
...

As you can see I even put an enable_interrupts just before the sleep. I can't even get it to wake up using the internal oscillator, I must have changed something but I can't see what.
_________________
Adam Walker
Ttelmah
Guest







PostPosted: Fri Dec 30, 2005 9:07 am     Reply with quote

Don't enable the interrupt, unless you have an interrupt handler present. Doing so, is a sure problem. You should _disable_, the global interrupt enable, and enable the devices interrupt, which will then result in sleep 'waking', but no interrupt handler being called.
Clear the interrupt, before starting the ADC (otherwise, if the flag is already set, the sleep will not execute). The ADC, should be running off _its_ clock, since the processor's clock will stop, when the sleep begins.

So:
Code:

setup_adc_ports(AN0|VSS_VREF);
setup_adc(ADC_CLOCK_INTERNAL);
//Must use the internal clock for the ADC
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_AD);
//enable_interrupts(GLOBAL);
//Do not enable global interrupts.
setup_low_volt_detect(FALSE);
setup_oscillator(OSC_8MHZ || OSC_INTRC);

while(true)
{
set_adc_channel(0);
/Clear the interrupt to ensure the sleep executes
clear_interrupts(INT_AD);
read_adc(ADC_START_ONLY);
sleep();
//The next instruction is 'prefetched' ensure it is a nop
delay_cycles(1);
s0_value = read_adc(ADC_READ_ONLY);


Best Wishes
Humberto



Joined: 08 Sep 2003
Posts: 1215
Location: Buenos Aires, La Reina del Plata

View user's profile Send private message

PostPosted: Fri Dec 30, 2005 9:07 am     Reply with quote

Quote:

I am trying to get a reasonably accurate measurment from a potentiometer. I am using a 18F4550 which in theory has 10bit ADC. The stability of the reading is 7bit at most the remaining 3 bits are constantly changing. I have tried using the start sleep read method but the accuracy did not improve.


You have two separate miss understanding problems:

1) If you can't get a stable 10 bit AD conversion reading from a 10K pot surelly you
have a basic hardware + code problem.
To get rid of this, make a short test for AD conversion ONLY that loop forever and
print out the result while you fix the hardware.
The 18F4550 can deliver a stable 10 bit result when it's done in a benchtest
according with spec.

2) The PIC generate an interrupt at the end of conversion setting bit 6 (ADIF)
in Register PIR1, but this for any reason means that will wake up the PIC.
RCON Register has the control flags to wake up the microcontroller.

Humberto
addthebadd



Joined: 20 Dec 2005
Posts: 4
Location: Bristol, UK

View user's profile Send private message

PostPosted: Fri Dec 30, 2005 12:35 pm     Reply with quote

Many thanks, I now have sleep mode working perfectly! I still need to polish my analogue circuits but with the capacitor the results are much much better.

Again many many thanks.
_________________
Adam Walker
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Fri Dec 30, 2005 6:23 pm     Reply with quote

addthebadd wrote:
The pot is a 10k and it's currently running straight from the ground to +5v. Do I need to get a new pot or can I tweak the circuit?


Getting the new pot with a smaller value is the simpliest solution to the problem. (Unless you have a battery powered application, in which case the small-valued pot might be draining your batery.) Alternatively, you can put a op-amp buffer between the pot and the A/D.
hawking1122



Joined: 10 Mar 2011
Posts: 11

View user's profile Send private message

ADC disable USB module?
PostPosted: Thu Mar 10, 2011 10:31 pm     Reply with quote

When I use sleep() to get more stable value from ADC, the USB module is disabled and I can not send data over USB cable anymore. I've tried adding enable_interrupts(GLOBAL) as well as usb_init_cs() and usb_task() after adc read code but it did not work.
Can you suggest any solution?
Ttelmah



Joined: 11 Mar 2010
Posts: 19509

View user's profile Send private message

PostPosted: Fri Mar 11, 2011 3:33 am     Reply with quote

It should work _but_ you need to ensure you disable all other interrupts before starting the conversion, and re-enable them afterwards. Just save all the interrupt registers, and rewrite them after the conversion.
The ADC, only takes a maximum of about 22uSec to do the conversion. USB requires interrupts to not be disabled for more than a very few mSec, but uSec, are perfectly acceptable.
However, the improvement from using the sleep conversion, is small, _provided your PCB is well designed. You show a separate reference being used. How is this generated?. Grounding round your processor, and in particular round the analog components, is crucial.
Sleeping the processor, _only_ reduces noise from the processor components themselves. It is up to your design, to reduce the others....

Best Wishes
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Fri Mar 11, 2011 6:57 pm     Reply with quote

I don't remember off hand on that chip - does it have an internal reference available or is the reference derived from the supply (or external ref of some kind) ? Some of the chips (I have been using the 18F14K22 which does have an internal precision reference available). If the supply is fluctuating at all and you are not using a good reference, your readings will wander (although in this case, it gets more complicated since the pot is dividing the supply down and may have a phase delay due to the filter caps). Basically, you need to verify the reference and supply lines are stable as well as bypass the various signal lines with ceramic caps to clean the signal up. Any hum or noise pickup will give strange readings.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
hawking1122



Joined: 10 Mar 2011
Posts: 11

View user's profile Send private message

PostPosted: Fri Mar 11, 2011 11:40 pm     Reply with quote

Thanks for your quick advice. I'm using LM317 to generate Vref at 2V. I've checked Vref with voltmeter and see it is stable (but not sure at time the chip take sample because it is too short). Do you think I should check with an oscilloscope?
About hardware, I don't understand what you mean by "grounding round the microprocessor", does it mean to isolate it from other noise making components?
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Sat Mar 12, 2011 1:55 am     Reply with quote

You should have a good ground plane - there are grounds then there are "almost grounds" - if you run a wire from the "ground side" of the reference to somewhere else and there is any current in that wire, you are not at ground by some value that is a function of the current. Switching transients are notorious problems which is why it is very important that the processor and any other chips that are doing any switching have good bypass capacitors between the power and ground pins on the chip - as close to the chip as possible. Any current through your ground system will generate a differential voltage that will affect the readings. If you look at a well designed multi-layer board, you will often find data/address/etc lines on the top and bottom layers, a power and ground layer that only has holes in it for signals to go through and in the middle of that the analog low level signals. The power and ground planes are then bypassed together with lots of caps so the analog low level signals are well shielded. That is a bit of an extreme case using 5 layers, but you have to do significant shielding sometimes to get good results with A/D signals.

As far as a scope goes, I would look at the reference signal with a scope - a voltmeter will often not tell you if there is noise on the line. Make sure the reference signal is also bypassed to ground with ceramic bypass caps. Also make sure that the negative side of your reference really is at ground, not with noise on it at 10mv above ground. Look at the 5 volt supply both with the scope on DC as well as low level AC coupling looking for noise.

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Mar 12, 2011 6:45 am     Reply with quote

I see you're using an LM317 for the ref. It's best to use a pair of 1% resistors and not a pot to make the voltage divider.Pots are really 'noisey',more prone to selfadjusting with heat,humidity,shock,etc.
Also add a 1 or 10 mfd cap as well as .001 ceramic on the output to reduce noise.
Using a proper voltage reference chip is the best way but $$$,remember having a stable ADC input is good BUT you must have a GREAT stable reference to compare it too,especially while in 10 bit mode.
If you have the time, sample 64 times then get the average using int16. If you need more speed, sample 8,16, or 32 times. Try not to rely on just 1 reading.
As as been previouly said, add several bypass caps 'around' the board,at each chip, power inputs,etc.Properly done you can get 16 bit ADCs to read correctly in high EMI areas, been there done that, decades ago.
Ttelmah



Joined: 11 Mar 2010
Posts: 19509

View user's profile Send private message

PostPosted: Sat Mar 12, 2011 8:34 am     Reply with quote

An LM317, is a voltage regulator, rather than a reference. What else are you running off this?.
If you are just using this as the voltage reference, then 'think again'. It will become unstable, at the low currents needed for the Vref. A typical DVM, will not 'see' instabilities at the frequency this will produce, and this could be your entire problem. It is the wrong tool for the job of providing a Vref. It is a better solution for providing the entire main supply rail, giving better stability, and accuracy than most fixed regulators. For this 'great'. For supplying a Vref, look at a bandgap diode instead. Something like an AD780.

Best Wishes
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