View previous topic :: View next topic |
Author |
Message |
vever001
Joined: 15 May 2010 Posts: 21
|
Analysis of the ADC converter of the 18F458 |
Posted: Wed Dec 08, 2010 12:15 pm |
|
|
Hello all,
I need to test the ADC of a 18F458.
So I will put an analog signal on the AN0 pin, then the ADC will convert it, and then I use a MCP4921 or so to get an analog signal.
So I can compare the original analog signal and the result (the output of the MCP4921) to see what happens when I increase the frequency.
But I have a problem to understand the read_adc() function...
So the function start the conversion, wait the conversion to finish (so I don't have to put a delay between 2 conversions ?) and store the value in a variable.
But then the conversion time will fluctuate...right?
So what do I need to do if I want a stable sampling rate ?
I saw the ADC_START_ONLY and ADC_READ_ONLY parameters...Can I use this ?
Thanks a lot for your help |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Dec 08, 2010 12:34 pm |
|
|
Quote: | But then the conversion time will fluctuate...right? |
The 18F458 data sheet says:
Quote: |
The A/D conversion time per bit is defined as TAD. The
A/D conversion requires 12 TAD per 10-bit conversion.
3. Wait the required acquisition time.
4. Start conversion:
• Set GO/DONE bit (ADCON0)
5. Wait for A/D conversion to complete, by either:
• Polling for the GO/DONE bit to be cleared
OR
• Waiting for the A/D interrupt
|
I don't see any time period that fluctuates.
The following diagram in the 18F458 data sheet shows the A/D timing.
I don't see any variable latency time period in it:
Quote: | FIGURE 27-23: A/D CONVERSION TIMING |
|
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Wed Dec 08, 2010 1:21 pm |
|
|
ok. Sorry I thought the read_adc() function was waiting until the conversion is finished (so the time of 2 conversion woudn't be the same as it is a successive approximation ADC) but in fact it always waits 12 Tad. Right ?
So I need to do like this :
Code: | setup_adc_ports(AN0);
set_adc_channel(0);
setup_adc(ADC_CLOCK_DIV_32);
while(1)
{
delay_us(20); //wait for the acquisition time
value=read_adc();
delay_us(4); //A minimum wait of 2 TAD(=1,6µs) is
//required before next acquisition starts.
} |
Is it correct ?
Thanks a lot |
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Wed Dec 08, 2010 2:15 pm |
|
|
Also I would like to see, if it's possible, the assembly code for the read_adc() function.
I searched in the folders of PICC but without success...
Thanks |
|
|
gpsmikey
Joined: 16 Nov 2010 Posts: 588 Location: Kirkland, WA
|
|
Posted: Wed Dec 08, 2010 2:39 pm |
|
|
There may be a better way, but you can compile a code sample with the read_adc() function in it then view the .lst file generated by the compiler to see what it was generating for that function (at least that is the way I have done it in the past).
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 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Dec 08, 2010 4:07 pm |
|
|
A 'successive approximation' ADC, still has to handle all ten bits. You start with the high bit. Is the signal above or below half range. then halve the half range, and so on. Ten bits takes ten clocks, whatever the value of the signal. The 12 clocks includes the first that disconnects the capacitor from the input signal, and the last that reconnects this, and latches the result. There is not a 'have I got there already' test to abort the scan if the value is already 'right' earlier in the cycle.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Dec 08, 2010 4:10 pm |
|
|
Read Robert Scott's (CCS forum member) explanation of Acquisition Time
here:
http://www.microchip.com/forums/tm.aspx?m=201318
I made a test program (shown below) to test the effect of changing
the acquisition time. This program reads 10 consequtive A/D samples
and stores them in an array. When that's done, it displays the samples.
I run the PIC at 40 MHz to keep the loop overhead time as low as possible
so it doesn't add very much to the acquisition time by itself. I have a
delay_us() statement to do the acquisition time.
To provide the input voltage to the A/D, I connect pin B0 to pin A1 (AN1)
with a jumper wire. I don't use pin A0 for analog input because my
PicDem2-Plus board has a trimpot on that pin. So I use pin A1 instead.
I then toggle pin B0 after each A/D reading is taken. So basically, the
input capacitor inside the A/D must charge or discharge fully each time
a new A/D reading is taken. This allows me to test the extreme case of
a large scale change in the A/D input voltage for each reading. Probably
a real A/D example would have a more slowly changing input voltage.
Also, the output impedance of pin B0 must be considered to be very low
compared to a more "normal" (unbuffered) A/D input signal source.
The results are:
For no A/D acquisition time (except the loop overhead):
Quote: |
0
451
0
451
0
451
0
451
0
451
|
For 1us acquisition time:
Quote: |
0
564
0
563
0
564
0
564
0
564
|
5us acquisition time:
Quote: |
0
1005
0
1005
0
1005
0
1005
0
1005
|
6us acquisition time. Note that we are now getting full-scale readings.
Based on the forumula in the 18F452 data sheet, it should take 7.3us
to do this (assuming Pin B0 has 0 output impedance). The loop overhead
basically accounts for the 1.3us difference.
Quote: |
0
1023
0
1023
0
1023
0
1023
0
1023 |
Here is the test program:
Code: |
#include <18F452.h>
#device adc=10
#fuses H4,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=40000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#define SAMPLES 10
//======================================
void main(void)
{
int8 i;
int16 results[SAMPLES];
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_64);
set_adc_channel(1);
output_low(PIN_B0);
// Take several consecutive A/D readings.
// Store them in an array.
for(i = 0; i < SAMPLES; i++)
{
delay_us(1); // Set acquisition time delay here
results[i] = read_adc();
output_toggle(PIN_B0);
}
// Now display the results.
for(i = 0; i < SAMPLES; i++)
{
printf("%lu \n\r", results[i]);
}
printf("\n\r");
while(1);
} |
|
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Thu Dec 09, 2010 9:24 am |
|
|
Thanks a lot PCM Programmer !
You're a genius and your explanations and examples are always amazing.
I understand much better now.
Thanks |
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Thu Dec 09, 2010 1:30 pm |
|
|
Just one more question:
Why are you using 64 for the divider of the adc clock ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Dec 09, 2010 1:44 pm |
|
|
It's right out of the PIC data sheet. For 40 MHz operation, use div by 64.
Code: | TABLE 17-1: TAD vs. DEVICE OPERATING FREQUENCIES
AD Clock Source (TAD) Maximum Device Frequency
Operation ADCS2:ADCS0 PIC18FXX2 PIC18LFXX2
2 TOSC 000 1.25 MHz 666 kHz
4 TOSC 100 2.50 MHz 1.33 MHz
8 TOSC 001 5.00 MHz 2.67 MHz
16 TOSC 101 10.00 MHz 5.33 MHz
32 TOSC 010 20.00 MHz 10.67 MHz
64 TOSC 110 40.00 MHz 21.33 MHz
RC 011 - - |
|
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Thu Dec 09, 2010 5:42 pm |
|
|
Omg sorry I forgot you were using a 40Mhz ocillator
Sorry for the inconvenience
Anyway thanks a lot ! |
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Tue Dec 14, 2010 12:21 pm |
|
|
Hi,
I read the assembler code in the lst file and I have this:
Code: | .................... valeur_adc=read_adc();
0182: BSF FC2.2
0184: BTFSC FC2.2
0186: BRA 0184
0188: MOVFF FC3,05
018C: MOVFF FC4,06
|
So there are no delays in this function except the time for the conversion (12*Tad) right ?
Someone told me the read_adc function have already the acquisition time but I suppose he was mistaken ? But apparently his conversion works...that's strange...how is it possible ?
Also the datasheet of the 18F458 says that there has to be a delay of 2*Tad before the next acquisition...but I don't see it in your code. Is this delay really necessary ?
Thanks a lot |
|
|
vever001
Joined: 15 May 2010 Posts: 21
|
|
Posted: Tue Dec 14, 2010 2:44 pm |
|
|
Sorry I forgot to say that he's using the adc_done interruption...
But this doesn't change anything I think...He doesn't have the acquisition delay.
But apparently the conversion is correct till 13KHz...? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Dec 14, 2010 3:48 pm |
|
|
According to the data sheet, the 2ad wait time is necessary. But it doesn't
have to be in two separate delay_us() statements. It can all be summed
up together in one delay statement. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Tue Dec 14, 2010 3:53 pm |
|
|
If you use the ADC interrupt, you will get enough delay 'by accident'....
Since it takes some 30+ instruction times to get into the int handler, and this will only happen when the actual conversion has completed, and the capacitor is re-connected to the outside world, then another 30+ instructions to get out of the handler, you will probably get the time needed at all but the fastest clock rates.
Tacq, _can_ be programmed into the chips on the latter PICs.
Best Wishes |
|
|
|