|
|
View previous topic :: View next topic |
Author |
Message |
mshearer
Joined: 12 Jan 2009 Posts: 33
|
external ADC AD7476 |
Posted: Thu Mar 19, 2009 7:28 am |
|
|
Hi, Im having a bit of trouble with my ADC. I do get results, and they are very close to what they should be. however they shift about an awful lot with each reading.
i.e. with a 4volt input i should read 0xCCC, but instead get 1.CFC 2.CFD 3.D03
Code: |
uint8_t adc_val1 = 0x00;
uint8_t adc_val2 = 0x00;
uint16_t adc_result = 0x0000;
LATA5 = 0; //select ADC
LATA5 = 1; //de-select ADC
LATA5 = 0; //select ADC
Delay10TCYx(2); //wait for 20
SSPBUF = 0xFF; //send dummy data
while(!bit_BF){} //wait for buffer to fill
adc_val1 = SSPBUF; //read first byte
SSPBUF = 0xFF; //send dummy data
while(!bit_BF){} //wait for buffer to fill
adc_val2 = SSPBUF; //read second byte
LATA5 = TRUE; //de-select ADC
adc_result = adc_val1;
adc_result = adc_result<<8;
adc_result = adc_result^adc_val2;
|
any advice would be great as i really need this to be much more accurate.
matt |
|
|
Ttelmah Guest
|
|
Posted: Thu Mar 19, 2009 9:46 am |
|
|
Some questions/comments apply:
1) Show your SPI setup.
2) What clock rate are you using on the chip?.
3) What are you using as Vdd to the chip?.
4) Why not use the CCS functions?.
Best Wishes |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Thu Mar 19, 2009 9:49 am |
|
|
the variation from reading to reading is basically usually NOISE
and the cure is to loop and take say 16 readings and then average ,
by adding them together as you get them - and since they are 10 bit a single long integer ( int16) will serve as he accumulator
then at the end , perform a >>4 to average the 16 readings to ONE value
i think you will be happy with the result |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 19, 2009 12:36 pm |
|
|
You have a 5v input range, with a 12-bit A/D. This is 4096 steps.
5v/4096 steps = 1.22 mv/step.
Quote: |
with a 4volt input i should read 0xCCC, but instead get 1.CFC 2.CFD 3.D03 |
You have an offset, and also you have a variation. The offset is probably
caused by your reference voltage not being exactly 5.000 volts. Or, your
input voltage may not be exactly 4.000 volts.
Your input variation is +/- 3 or 4 steps, centered around 0xD00, and
is about 4 to 5 millivolts. That's actually pretty good, given the amount
of noise that's in a normal digital system. |
|
|
mshearer
Joined: 12 Jan 2009 Posts: 33
|
|
Posted: Fri Mar 20, 2009 2:34 am |
|
|
1)
Code: |
SSPSTAT = 0x00; /* SPI status Register */
SSPCON1 = 0x21; /* SPI control Register 1 */
|
2) 10Mhz Crystal through HSPLL to 40Mhz
3) Should be 5V, comes in just above so using 5.01/4096
4) need it to be easily transferable away from ccs :S
Thanks for all the replies btw.
A loop to take an average seems a sensible option, I think i'm stuck with a ridiculously small amount of clock cycles for this function however :(
matt |
|
|
Ttelmah Guest
|
|
Posted: Fri Mar 20, 2009 3:42 am |
|
|
If you are just using the PIC 5v, then this is your problem.
Look at the data sheet, and how to run the ADC, from a low noise Vref. A typical 5v regulator, will only manage stability in the short term, as loads vary inside the processor, of around 1% _at best_. You are seeing variations, well below this. I'd say the circuit was performing better than expected...
I was asking what you were clocking the _ADC_ off, not the PIC. The noise performance of the ADC, varies with it's clock rate.
Realistically, if you are writing the code in CCS, use the CCS functions. It is never going to be possible to port embedded code, without a fairly major 'rewrite', so why make things more likely to be wrong?. Basically, using the internal functions makes it much easier to port to another chip (all register changes are then done for you), which in normal use, is the more 'likely' change to be needed.
You can generate a 'rolling' average, very efficiently, with something like:
Code: |
static int32 sum;
int16 reading
reading=get_adc_reading(); //read the ADC here
sum+=reading;
reading=sum/8; //Use a _binary_ division here, for efficiency
sum-=reading;
|
Best Wishes |
|
|
Guest
|
|
Posted: Fri Mar 20, 2009 3:47 am |
|
|
thanks Ttelmah
very much appreciated |
|
|
mshearer
Joined: 12 Jan 2009 Posts: 33
|
|
Posted: Sat Mar 21, 2009 10:22 am |
|
|
actually, one more quick thing. Any idea why my first result is always something way off. Think it used to be always 0xFFF but not sure what it is now.
matt |
|
|
Ttelmah Guest
|
|
Posted: Sat Mar 21, 2009 10:28 am |
|
|
OK.
As written, it'll take several cycles, for the 'sum' to build to the required value.
If you want 'instant lock' on the first reading, then modify as follows:
Code: |
static int32 sum;
int16 reading;
int1 live=false;
reading=get_adc_reading(); //read the ADC here
if (live)
sum+=reading;
else {
sum=reading*8;
live=true;
}
reading=sum/8; //Use a _binary_ division here, for efficiency
sum-=reading;
|
Best Wishes |
|
|
mshearer
Joined: 12 Jan 2009 Posts: 33
|
|
Posted: Tue Mar 24, 2009 9:56 am |
|
|
great results seem a bit more solid now, as in I'm always getting the same thing.
I think this is probably going to be more down to how I'm providing/measuring my inputs but I seem to get increased inaccuracy the higher the voltage
for example
0.5030V through adc should give 410.923 but gives 410.333 meaning a differnce of 0.590117941. which is pretty acceptable
however this gradually increases up to
4.5023V through adc should give 3678.132 but gives 3695.666 meaning a difference of -17.53415241. which ain't great.
thanks again Ttelmah,
matt |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Tue Mar 24, 2009 10:39 am |
|
|
Instead of looking on measurements of arbitrary input voltages, you should rather do a complete transfer function. It will reveal what's wrong with your circuit. |
|
|
Ttelmah Guest
|
|
Posted: Tue Mar 24, 2009 10:47 am |
|
|
The 'odds' are that the voltage inside the chip, and possibly on your input, are not what you think they are.
First, what is the actual 'accuracy of you DVM. When was it last calibrated?. What does it use as it's sample 'basis' (depending on how a DVM is designed, for a voltage carrying noise, some will return the peak voltage, while others return the average..). Beware also, that DVM accuracies, are usually quoted as a percentage of 'full scale'.
It actually sounds as if your DVM, may be recording some noise on the 5v rail, to give a higher voltage, than is being seen by the chip.
If the reference 'seen' by the chip, was actually 4.99v, then for 4.5023v, the expected reading would be 3695.67.....
Best Wishes |
|
|
Ttelmah Guest
|
|
Posted: Tue Mar 24, 2009 11:05 am |
|
|
Amend that.
You need always with ADC's to look carefully at the transfer function specified by the manufacturer. Look carefully at figure 12. Note that the top of the transfer function, is _not_ Vdd.
The chip actually gives it's maximum reading, 1.5 bits 'above' Vdd, and gives a count of '1', at Vdd/4096. So, the best transfer function, is:
(Reading * (Vdd/4096)) -( Vdd/8192).
So, for a reading of 3695.66, wth a Vin, of 4.5023, the Vref being seen by the chip, is 4.9907v. Remarkably close to 5v!.....
Best Wishes |
|
|
|
|
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
|