View previous topic :: View next topic |
Author |
Message |
addthebadd
Joined: 20 Dec 2005 Posts: 4 Location: Bristol, UK
|
How can I improve ADC accuracy? |
Posted: Fri Dec 30, 2005 4:04 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 4:10 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 4:30 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 5:41 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 9:07 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 9:07 am |
|
|
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
|
|
Posted: Fri Dec 30, 2005 12:35 pm |
|
|
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
|
|
Posted: Fri Dec 30, 2005 6:23 pm |
|
|
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
|
ADC disable USB module? |
Posted: Thu Mar 10, 2011 10:31 pm |
|
|
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: 19518
|
|
Posted: Fri Mar 11, 2011 3:33 am |
|
|
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
|
|
Posted: Fri Mar 11, 2011 6:57 pm |
|
|
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
|
|
Posted: Fri Mar 11, 2011 11:40 pm |
|
|
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
|
|
Posted: Sat Mar 12, 2011 1:55 am |
|
|
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: 9229 Location: Greensville,Ontario
|
|
Posted: Sat Mar 12, 2011 6:45 am |
|
|
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: 19518
|
|
Posted: Sat Mar 12, 2011 8:34 am |
|
|
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 |
|
|
|