-
PICs: ADC is a "Tad" difficult
Posted by
PerranOak
on 31 May, 2018 15:51
-
In the 16F1827 datasheet it says:
"The time to complete one bit conversion is defined as TAD."
It talks about the time the PIC needs to make the conversion and that you must give it this time to work properly: it tells you how to calculate this.
However, it also gives a piece of sample code to get you started (extract):
BSF ADCON0,GO
BTFSC ADCON0,GO
GOTO $-1
Surely, this code will not be exited until the "GO" bit that tells you the conversion has ended has been cleared. Therefore, why do you need to know what the TAD is?
Also, someone told me that the capacitor in the ADC unit needs time to charge so you need code like this:
CALL chrgtime ;a delay of a few micro-seconds
BSF ADCON0,GO
I can't really see why as the PIC will be doing something before the ADC is "GO" so what difference does it make if it's engaged in a delay routine?
Thank you.
-
#1 Reply
Posted by
mikerj
on 31 May, 2018 17:09
-
You need to know TAD because the ADC conversion clock is derived from the main system oscillator Fosc via a programmable divider (or the internal RC oscillator can be used). You therefore need to set the divider correctly to ensure TAD lies within a suitable range. If you get this wrong, performance of the ADC will be degraded.
By the way you are posting in the wrong forum for microcontroller related topics, use the "Microcontroller and FPGA" sub-forum.
-
#2 Reply
Posted by
Simon
on 31 May, 2018 18:05
-
I have moved the topic.
The ADC typically works at a lower frequency than the CPU, as stated above you need to get the divider right. It may interest you to know how long the conversion will take. No I'm not sure why you need "cap charge" code. The cap will not see the input until you start a conversion. I am not familiar with PIC but on AVR the first 1.5 clock cycles is spent charging the cap.
Given that the CPU may be executing code at a much higher frequency than the ADC it is feasible to tell the ADC to get goinc and then go do something else and an interrupt tells you the conversion is over so you can go back to collect your result.
On AVR the ADC runs between 50 and 200KHz far slower than the 16+MHz of the CPU.
-
-
Also, someone told me that the capacitor in the ADC unit needs time to charge
That is called the acquisition time and it depends on the source impedance (ensure its in specification). You only need to worry about this if you are using multiple channels as it applies from the time of changing the channel to when you start the conversion. The PIC has a means of programming this so that it happens automagically
-
#4 Reply
Posted by
PerranOak
on 31 May, 2018 19:15
-
Thank you for the replies.
Sorry, I posted it in “Beginners” as I am a beginner (this is literally my first project not "out-of-a-book") and I thought it was probably a “numpty” question.
Mikerj:
By “suitable range” you mean for the parameters of a particular project, e.g. that you are not trying to convert it too quickly?
Simon:
I may have misunderstood the cap charge situation.
I see, the “do something else” scenario means you need to know the conversion time, thanks.
Fourtytwo42:
Do you mean that you never need to have a built-in delay because the PIC does it “automagically”? (I like that word
)
-
#5 Reply
Posted by
Simon
on 31 May, 2018 19:23
-
The ADC runs at KHz, the main clock can be a few hundred KHz up to 10's of MHz. You need to divide down the main clock frequency to the frequency required by the ADC. The pin could be a digital I/O and then be switched to analogue. The ADC has nothing to do with the pin until you start a conversion, the first clock or two is spent charging the sample and hold cap. So if you clock the ADC too fast it might not charge the cap to the full input value. If you run too slow the cap starts to discharge due to natural leakage so the conversion can be incorrect.
-
#6 Reply
Posted by
JPortici
on 31 May, 2018 20:45
-
Fourtytwo42:
Do you mean that you never need to have a built-in delay because the PIC does it “automagically”? (I like that word )
No.
When you are not converting, the sampling capacitor is connected to the analog input selected by [...] (i don't remember which register is in your particular pic that selects the current analog input)
when you set the "GO" bit the sampling capacitor is disconnected from the selected analog input and is connected to the rest of the ADC circuitry, for the number of TAD that it takes to complete the conversion.
The number of TADs that it takes to convert a value is fixed, while the value of TAD is not. TAD can be derived from the system clock (and must not exceed some value, tipically 1us in PIC16) or can be derived from a dedicated oscillator.
The sampling capacitor is a capacitor, so it needs to be charged to the input voltage. The best way to do so is by connecting a low impedance source to the analog pin (for example an opamp used as buffer with a small resistor in series).
The datasheet specifies a maximum recommended source impedance. if you exceed this two things may/will happen: The time to charge the capacitor is too big, you need to spend a lot of time on sampling the input, or the source impedance is too high and the parasitic currents inside the ADC input will affect the voltage, this is what he means by degradating the performance of the ADC.
knowing the source impedance, you can use the ADC input model to calculate an estimate of how much time you have to spend on sampling an input. And that's why you call the sampling delay, to charge the sampling capacitor.
On more recent and more evolved PICs you have the possibility to perform auto-sampling/auto converting (by using one timer to initiate the conversion, or by a dedicated timer in the ADC.. in which case the sampling time is STILL expressed as a number of TADs so Tsample + Tconvert = Tconversion -> then you have the sampling frequency of your ADC.
On more recent and more evolved PICs you can even have the possibility to SCAN the analog inputs, that's it: when channels are enabled for scan, the ADC acquire from channel A, then converts channel A and puts the result in the first location of a buffer. Then samples/convert channel B and puts it in the second location of the buffer. Then channel C and so on, then it restarts from channel A. The only thing you need to do is to take the data from the buffer before it gets overwritten
-
#7 Reply
Posted by
cv007
on 01 Jun, 2018 00:19
-
a simple summary-
Datasheet-
table 16.1
find your Fosc column
choose a Fosc/x row that is in white, which is what you use for your adc clock source
(or just use Frc as adc clock source if speed not needed)
16.2.6 a/d conversion procedure
step 2a-> adc conversion clock -> see table 16.1
step 4-> see 16.4
16.4 a/d acquisition requirements
needed after input channel selected or changed
example shows about 4-5us
new adc channel = need acquisition time to get charge cap happy
adc conversion = need conversion clock selected that gets tad >= 1us (choosing frc as adc clock always ok)
-
#8 Reply
Posted by
mikerj
on 01 Jun, 2018 08:20
-
Thank you for the replies.
Sorry, I posted it in “Beginners” as I am a beginner (this is literally my first project not "out-of-a-book") and I thought it was probably a “numpty” question.
Mikerj:
By “suitable range” you mean for the parameters of a particular project, e.g. that you are not trying to convert it too quickly?
No, I mean the range specified in the datasheet. Tad is determined by the ADC design, it is the same whatever your project. The issue here is that the ADC doesn't know what your main clock frequency is, since you this is by selection of crystal/resonator or internal RC. You therefore need to select the correct divider for your clock frequency to ensure that Tad meets the datasheet specifications.
-
#9 Reply
Posted by
PerranOak
on 01 Jun, 2018 14:12
-
Thank you all so very much, this is great!
I think that I was confusing and conflating some of the principles. Let me try to summarise my understanding.
The capacitor is disconnected from the analogue input when the GO bit is set and this is when it takes (in my case, using the 16F1827) 11.5 * TAD to make the conversion. At the end, presumably, the capacitor is reconnected to the analogue input and sits there waiting for the next GO setting?
The value of TAD is given in the datasheet based on FOSC and the “conversion clock select” bits (ADCS). In my case this is FOSC of 4MHz, ADCS of FOSC/8 so the table in the datasheet gives TAD of 2.0us. This means that conversion will take 23us. I can vary this within the parameters set in the datasheet but if I go outside the recommendations then the conversion could be unpredictable. It seems that, in my case, 1us<= TAD <=8us.
I need this figure of 23us if I intend to “do other stuff” while the conversion is happening and I must not try to use the reading until the 23us is up. However, if I simply wait in a simple loop for the GO bit the be cleared by the ADC then I can safely proceed. FRC can be used as a catchall that will always work (in relation to TAD requirements) but is this an external oscillator: I only use the internal one just now?
The sampling delay (acquisition time TACQ) is entirely separate from the TAD and is to do with the sampling capacitor having the correct amount of time to charge to the analogue input voltage. If the analogue input impedance is too high then the capacitor may not charge/discharge entirely to the analogue input voltage (classic RC circuit situation?); there is no lower limit? The datasheet has an equation to derive the TACQ and in the example given TACQ is 4.42us: I assume that this is a “typical” sort of time?
A delay of at least TACQ is needed on changing channels before taking a reading. Even when using only one channel, presumably, the delay is needed after setting the ADON bit and before starting the first conversion? As the capacitor is reconnected to the analogue input immediately after a conversion, presumably, a delay of at least TACQ must be observed before the next reading for the capacitor to charge to the “new” voltage? This delay may be a “delay routine” or it may simply happen as part of the main programme?
My “analogue input voltage” is from an LM35 and so I think that its impedance is not an applicable concept here. How can I determine the TACQ required for such a device?
Thank you all again.
-
#10 Reply
Posted by
JPortici
on 01 Jun, 2018 15:25
-
The capacitor is disconnected from the analogue input when the GO bit is set and this is when it takes (in my case, using the 16F1827) 11.5 * TAD to make the conversion. At the end, presumably, the capacitor is reconnected to the analogue input and sits there waiting for the next GO setting?
Correct.
The value of TAD is given in the datasheet based on FOSC and the “conversion clock select” bits (ADCS). In my case this is FOSC of 4MHz, ADCS of FOSC/8 so the table in the datasheet gives TAD of 2.0us. This means that conversion will take 23us. I can vary this within the parameters set in the datasheet but if I go outside the recommendations then the conversion could be unpredictable. It seems that, in my case, 1us<= TAD <=8us.
Correct
I need this figure of 23us if I intend to “do other stuff” while the conversion is happening and I must not try to use the reading until the 23us is up. However, if I simply wait in a simple loop for the GO bit the be cleared by the ADC then I can safely proceed. FRC can be used as a catchall that will always work (in relation to TAD requirements) but is this an external oscillator: I only use the internal one just now?
Well, the FRC is a dedicated oscillator for the ADC and as you can probably see from the datasheet it doesn't have a well defined period, since it can span a range of several microseconds (1 to 6 in your case). I would say use it if you don't have requirements for the sample rate.
The sampling delay (acquisition time TACQ) is entirely separate from the TAD and is to do with the sampling capacitor having the correct amount of time to charge to the analogue input voltage. If the analogue input impedance is too high then the capacitor may not charge/discharge entirely to the analogue input voltage (classic RC circuit situation?); there is no lower limit? The datasheet has an equation to derive the TACQ and in the example given TACQ is 4.42us: I assume that this is a “typical” sort of time?
correct, except for the last bit. TACQ is calculated using the analog input model. Did you take a look at EQUATION 16-1 and FIGURE 16-4 (datasheet DS41391D) ? i think they are almost self explanatory. The quation is commented and explain on HOW to calculate TACQ, the figure is the analog input model with typical values and curves for the various elements (switches resistance, parasitics, sample capacitor)
A delay of at least TACQ is needed on changing channels before taking a reading. Even when using only one channel, presumably, the delay is needed after setting the ADON bit and before starting the first conversion? As the capacitor is reconnected to the analogue input immediately after a conversion, presumably, a delay of at least TACQ must be observed before the next reading for the capacitor to charge to the “new” voltage? This delay may be a “delay routine” or it may simply happen as part of the main programme?
My “analogue input voltage” is from an LM35 and so I think that its impedance is not an applicable concept here. How can I determine the TACQ required for such a device?
as you are acquiring from only one channel, you don't need to care about that.
How to calculate TACQ: you have to know the output impedance of the LM35, then apply equation 16-1.
Or go by trial and error..
Or maybe you could use a timer interrupt: if you implement a systick of some sort (like, a timer that fires an interrupt at a fixed rate such as 1ms-10ms) you could set a flag "checkADC", in the main loop if the checkADC flag is set, get the value from the ADC and start a new conversion.
The idea is that this flag is set at a rate so that the sampling and converting requirets are met. You start the conversion, the converter converts and then start sampling until the next cycle.
-
-
My “analogue input voltage” is from an LM35 and so I think that its impedance is not an applicable concept here. How can I determine the TACQ required for such a device?
Assuming the LM35's output impedance is 0 compared with all the other junk already in the formula, I make the TACQ 2.5us. Page 149
http://ww1.microchip.com/downloads/en/DeviceDoc/41391D.pdfOne other thing you can do while waiting for an ADC conversion to complete is to read and save the previous ADC result!
-
#12 Reply
Posted by
mikerj
on 04 Jun, 2018 09:13
-
One other thing you can do while waiting for an ADC conversion to complete is to read and save the previous ADC result!
:yes: This facility is often ignored, and CPU cycles wasted whilst the ADC completes. At the higher clock rates there can be enough cycles to perform filtering functions between samples (if multiplies and divides are avoided).
-
#13 Reply
Posted by
PerranOak
on 04 Jun, 2018 16:46
-
Fantastic. Thank you for taking the time to reply in such great detail JPortici.
StillTrying: Right, thank you.
mikerj: I see, the ADC is completely separate and so doing other things will not affect it … unless you're silly and alter its parameter.
-
#14 Reply
Posted by
PerranOak
on 05 Jun, 2018 13:40
-
Now the problem is the first reading!
The programme sets up the registers then goes on to the ADC reading (temperature from the LM35). It the puts these into tens, units decimals and then displays the result on three 7-seg LEDs in a closed loop. The Timer1 interrupt then comes in and triggers a new ADC reading. This goes on every second forever. Now that I am using the interrupt properly, the accuracy has gone up! It is now only about 0.2 – 0.3degC out, so all was well.
The problem is every time I start the PIC the first reading is random. After that, the readings are always fine. I have tried “everything” to stop this. It doesn’t matter whether it is a power supply switch start or an MCLR. I disabled interrupts and obviously it only gives the first figure and waits but this first figure is random as before. I’ve fiddled with the code and put delays in here and there, nothing. I’ve cleared ADRESH/L and TMR1H/L ... maddening!
Is the ADC like pancakes: the first one is a “throw away”? If not, then could you please give me a few pointers as to how I might investigate the issue or any insight into likely causes?
Thank you.
-
-
As long as you're allowing some time for the power supply to stabilize 200ms ?, and the ADC is ON before the first TACQ and then GO, the first reading should be fine.
Are you doing it all in ASM.
-
#16 Reply
Posted by
mikerj
on 05 Jun, 2018 14:55
-
Post your initialisation code and your interrupt code. Does your interrupt set the ADC channel each time, or is that done just once in your init code?
-
#17 Reply
Posted by
PerranOak
on 05 Jun, 2018 15:54
-
StillTrying:I put a 5s delay at the start and it did just the same. Yes, I can only do assembly at the moment.
mikerj: (sorry for the formatting, I can't seem to do it without <tab> !
start: banksel TRISA ;Select bank1
movlw b'00000001' ;Set RA0 as input
movwf TRISA ;as input rest as outputs.
clrf TRISB ;Configure all port B as outputs.
movlw b'00000001' ;AN0 = RA0 i/p, GO low, ADC on.
movwf ADCON0
bsf PIE1,TMR1IE ;enable timer1 overflow interrupt
movlw b'10010011' ;Right just, Fosc/8, Vss, FVR.
movwf ADCON1
movlw b'01101000' ;sets int osc to 4MHz
movwf OSCCON
banksel ANSELA ;Select bank3
movlw b'00000001' ;Configure RA0 as analogue
movwf ANSELA ;input.
clrf ANSELB ;Config all port B as digital i/o.
banksel FVRCON ;Select bank2.
movlw b'11000001' ;FVR enable, 1.024V.
movwf FVRCON
banksel PORTB ;Select bank0
movlw b'00110101' ;Fosc/4, 1:8 pre-scale, ... timer on
movwf T1CON
bcf PIR1,TMR1IF ;clear timer1 interrupt flag
bsf INTCON,PEIE ;enable peripheral interrupts
bsf INTCON,GIE ;enable global interrupts
main: call chrgtime ;Tacq 8us (my assumption)
banksel ADCON0
bsf ADCON0,GO ;Set GO bit to start conversion.
wait: btfsc ADCON0,GO
goto wait ;Wait for GO bit to clear.
... rest of main loop ...
INTERRUPT
intrpt: bcf PIR1,TMR1IF ;clear timer1 interrupt flag
decfsz counti,F
retfie ;return to normal ops if counter not done
bsf flag,0 ;set flag bit to trigger new reading
movlw .4
movwf counti ;reset interrupt counter to 4.
Retfie
ADC channel set just once. Thank you for taking a look.
-
-
"I can only do assembly at the moment."Assembly is fine.
When the FVR is enabled it requires time for the reference and amplifier to stablize, unfortunately it doesn't tell how long this time is.
With no ORGs visible, have you got gotos to the right bits of code.
Something like
0000 goto start
0001
0002
0003
0004 goto isr
0005 start
-
#19 Reply
Posted by
PerranOak
on 05 Jun, 2018 17:30
-
I have this before the "start:" label:
#include p16f1827.inc ;Register and bit definitions.
centig equ 0x20
tens equ 0x21
ones equ 0x22
decs equ 0x23
org 0x0000
goto start
org 0x0004
goto intrpt
org 0x0005
dispdata: addwf PCL,F
retlw .126 ;digit 0
retlw .12 ;digit 1
retlw .182 ;digit 2
This is how I was shown.
Cheers.
-
-
Other than adding a few ms delay after movwf FVRCON I can't think of anything else.
banksel FVRCON ;Select bank2.
movlw b'10000001' ;FVR enable, 1.024V.
movwf FVRCON
btfss FVRCON, FVRRDY
goto $-1
should work. - in theory.
-
#21 Reply
Posted by
PerranOak
on 06 Jun, 2018 12:02
-
Thank you, I'll try that.
In the meantime, I wondered if it was an artifact of the LM35. So, I used a resistor divider to apply the voltage to the input instead of the LM35. I took 100k, 220k and 470k resistors in turn and used a series of resistors from 1k to 100k in the "pin-to-ground" section of the divider. I then noted the "temperature" difference between first and second readings for each pair. The accuracy of the "proper" reading from the PIC was the same as the voltage measured by the Fluke87V across the "pin-to-ground" resistor, i.e. the voltage at the input pin.
The results were that while the differences did vary somewhat by resistance (pin-to-ground side) the change looks like it depends most strongly on the actual voltage at the pin rather than the resistance. The difference was a reasonably consistent 0.8%.
I thought that the resistance would matter more at it should affect the charge time of the sampling capacitor.
I'll try StillTrying's solution now.
-
#22 Reply
Posted by
PerranOak
on 06 Jun, 2018 12:26
-
Tried that and it is still doing it but now the difference is higher on the second reading where is used to be lower!
I notice in the datasheet it says:
When the Fixed Voltage Reference module is enabled, it
requires time for the reference and amplifier circuits to
stabilize. Once the circuits stabilize and are ready for use,
the FVRRDY bit of the FVRCON register will be set. See
Section 30.0 “Electrical Specifications” for the
minimum delay requirement.
However, there is no mention of the requirement in that section!
Also, it says:
Note 1: FVRRDY is always ‘1’ on devices with LDO (PIC16F1826/27).
and mine is an 1827. Does this mean it's always ready?
-
-
I looked at the LM35 data sheet, with its 0.1R impedance and 25us start up time I don't think it could be that. And searching for FVR, FVRCON, and Fixed Voltage, I never did find the FVR stabilization time, so dunno.
But I've thought of a possible something else.
As I understand it in the code above you seem to be turning the ADC ON and setting it up while Fosc is only 500kHz, Page57. I suppose it's possible the very slow CLK and TAD could be putting the ADC into a strange state for a while. It might be an idea to set the Fosc to 4MHz and TAD time first, before turning the ADC ON, I've done that reversing below! Good luck.
;OSCCON: OSCILLATOR CONTROL REGISTER P65
;SPLLEN IRCF<3:0> --- SCS<1:0>
movlw b'01101000' ;sets int osc to 4MHz
movwf OSCCON
;ADCON1: A/D CONTROL REGISTER1 P146
;ADFM ADCS<2:0> --- ADNREF ADPREF<1:0>
movlw b'10010011' ;RightJust, Fosc/8, --- ref=Vss, ref=FVR.
movwf ADCON1
;ADCON0: A/D CONTROL REGISTER0 P145
; --- CHS<4:0> GO/DONE ADON
movlw b'00000001' ;AN0 = RA0 i/p, GO low, ADC on.
movwf ADCON0
-
#24 Reply
Posted by
PerranOak
on 06 Jun, 2018 20:08
-
That was well spotted!
I tried it but there was no discernible change. Thank you for trying.