The acquisition time is always relevant even in the case where there is only one ADC channel used, as the holding capacitor is disconnected from the ADC input channel whilst the conversion is being made. At the end of the conversion, the holding capacitor is reconnected. Granted that in most cases there will be a rather long interval (in terms of the normal acquisition time) after the ADC read is completed, so charging can proceed even at a leisurely pace.
To make this post most useful to someone who may read it a year from now and is not as conversant with ADC issues, let's first summarize how the PIC's ADC works.
At some time t=0, the analog input pin is connected to a small value capacitor Chold (120 pF in the 18F458). That analog voltage to be measured charges the capacitor through the series resistance associated with the PIC's multiplexing switch and the voltage source's internal resistance. In the 18F458, the internal resistance is spec'd at "less than 1Kohm."
When the ADC conversion starts, Chold is disconnected from the input pin and its value is read by the conversion stage.
From elementary circuit theory, we know that the voltage across Chold cannot change instantaneously, and in fact we have a classical RC network, where the series R consists of the PIC's internal resistance in series with the resistance of the external voltage source connected to the analog input pin.
Assuming we know the effective external resistance, and if we neglect some of the PIC's internal leakage, it is relatively simple to determine how many time constants the analog input must be connected to the source so that Chold charges to approximate the voltage being measured. Since the 18F458 has a 10-bit ADC, it is reasonable to want the RC changing time to be sufficiently long enough that the acquisition time error is less than 1/1024, or 0.1%, or 1 LSB. (Most would take the desired error budget as 1/2 LSB or even 1/4 LSB, but we'll keep it at 1 LSB for simplicity.)
After one time constant Chold = 63.2...% of the final value, after two time constants it has reached 86.4% etc. We can determine that after seven time constants, the voltage is within 0.1% of the ultimate value.
If the 18F458's internal resistance is at the high side of the spec, 1K, and if the external resistance is, for example, 2K, the total R in our RC network is 3K, and one RC time constant is 3*10^3*120*10^-12 = 0.36 microseconds. Seven time constants is thus about 2.5 microseconds.
So, we need to ensure that our voltage source with an internal resistance of 2K is connected to Chold at least 2.5 microseconds before we start the actual AD conversion process. If we are not pressed for time, longer is better and we can stretch the acquisition time to 10 or 20 usec or more.
Now we are in a position to consider the second part of the process--how long it takes the PIC to convert the voltage on Chold to an accurate digital value. It takes 12 "ticks" for this process. The duration of one "tick" is is governed by the conversion clock setting and the correct parameter can be determined by Table 20-1 and 20-2 in the 18Fxx8 data sheet. The data sheet states that for the 18Fxx8, the minimum acquisition time step (tick length) is 1.6us. For a 40 MHz clock we can determine that this time interval requires the clock to be divided by 64. (40000000/64 = 625000 ticks/sec. 1/625000 = 1.6 us.)
The total conversion process, once the ADC has been initiated, is 12 * 1.6 us, or 19.2 us.
The overall time is:
2.5 us acquisition time for Chold to reach 0.1% of final value
19.2us conversion time
Total time = 21.7 microseconds.
There are some overheads associated with Swordfish that mean this time will not exactly be reached.
All this can be found in the 18Fxx8 Data Sheet, but in my opinion, Microchip's ADC chapter is difficult for a beginner to understand.
To address the question of whether Swordfish's ADC module should stop the ADC module after each read and restart it for the next read...reasonable persons could reach different conclusions in this regard. There is some slight overhead added by starting and stopping the PIC's ADC module, but that is rather modest. There is some additional acquisition time added as has been pointed out, but the acquisition time is generally not that much, compared with the conversion time, at least assuming the ADC is being driven by a lowish impedance source. And if it is not, then the error analysis must be extended to consider errors resulting from the protective diode leakage and other factors. As a general proposition, Microchip recommends ADC driving impedance < 2.5 K and I agree with that.
As far as setting the conversion clock, yes, it absolutely is necessary to select the conversion division ratio based on the 1.6 us interval and the PIC's clock rate. It's not a big deal for me to remember to set it, but I can see that Swordfish would be more beginner friendly if the conversion clock were automatically defaulted to the correct divisor. However, I would not recommend that Dave move that to the top of the priority queue, as I am sure there are many more important things to be added to Swordfish.
I apologize if this discussion is (a) too long or (b) too simplistic, but I hope that it will be of benefit when stumbled across by a beginner next year or the year after.
Jack
Here is a quick mod on the original code that works for me. I don't have an LCD connected to the test board, so I have the output routed to the serial port. I arbitrarily doubled the 2.5 us acquisition time to 5us.
Code: Select all
Device = 18f458
Clock = 40
Config osc = hspll
// LCD options...
#option LCD_DATA = PORTD.0
#option LCD_RS = PORTD.4
#option LCD_EN = PORTD.5
// uses LCD and AD libraries...
Include "LCD.bas"
Include "ADC.bas"
Include "usart.bas"
Include "convert.bas"
// initialise and clear LCD...
ADCON1 = %10000010'$07 // PORTE as digital (LCD)
TRISA.0 = 1 // configure AN0 as an input
ADCON1.7 = 1 // set analogue input on PORTA.0
DelayMS (500)
LCD.Cls
// main program loop...
TRISC.0 = 0
USART.SetBaudrate(br115200)
USART.Write("Init OK",$0A,$0D)
ADC.SetConvTime(FOSC_64)
ADC.SetAcqTime(5)
DelayMS(1000)
While true
'LCD.WriteAt(1,1,"CH0 = ", DecToStr(ADC.Read(0)), " ")
USART.Write("CH0 = ", DecToStr(ADC.Read(0)),$0A,$0D)
DelayMS(100)
Wend