CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

ADC issues on the PIC16f1947

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
RckRllRfg



Joined: 20 Jul 2011
Posts: 60

View user's profile Send private message

ADC issues on the PIC16f1947
PostPosted: Fri Nov 11, 2011 3:37 pm     Reply with quote

Hello All -
I need a bit of assistance with the ADC on the PIC16F1947. I have poured over the examples in the CCS manual, I have read through forum posts with examples and I have played with the CCS development kits for the 16F1937 with its ADC and had it up and running 5 minutes. But, I am not able to get the ADC to play on my 16F1947.

Using CCS compiler 4.124.

For the purposes of test, I am feeding the result of a DAC on another chip to the PIC16F1947. The signal is being fed to the PIC through an external differential amplifier. I am using the external references for both the AVSS and AVDD (and have attempted to interchange it with the FVR). All of the VSS (of this and other signals) are tied to the AVSS. The end purpose of the ADC is to monitor temperature.

Here's the code that I am using. Due to my lack of success with ADC using the CCS provided functions, I attempted to control it by manually controlling the registers.

I have 2 ways of looking at the results -

1) The 8 LED on my board should increment (or decrement) since the DACs are simply performing a "stair case" function (ie, I am feeding the DACs a count value, ChA incrementing, and ChB decrementing)

2) I am sending the result via serial port to RealTerm.

Any guidance on this would be greatly appreciated. If any clarifications are needed, let me know.


Code:

#include <16F1947.h>
#device ICD = TRUE;
#Device ADC=10;
#fuses HS,PLL_SW, NOWDT,NOPROTECT,NOLVP
#use delay( clock=20000000 )

// Function to set data from the PIC to the DAC via SPI
//#include <C:\Users\4thPoint\Desktop\ROS\Project244\Firmware\Project244_SPI2DAC.c> 

// Serial communications

#define RXEN             PIN_D4
#define TXEN             PIN_D7
#define XCEIVER_ENABLE   PIN_D5
#define RS485            PIN_D6

// LED lighting

#define LIGHT1           PIN_D0
#define LIGHT2           PIN_D1
#define LIGHT3           PIN_D2
#define LIGHT4           PIN_D3
#define LIGHT5           PIN_G0
#define LIGHT6           PIN_G1
#define LIGHT7           PIN_G2
#define LIGHT8           PIN_G3

// For this project the E0,E1 and E2 are set to analog input by default
// These need to be changed to digital inputs:

#byte ANSELE = getenv("sfr:ANSELE")

// FVR for the ADC.  Enabling for option 4.096V

#byte FVRCON = getenv("sfr:FVRCON")

//  For ADC, we will need to clarify the role of the ports

#byte ANSELF = getenv("sfr:ANSELF")
#byte ANSELA = getenv("sfr:ANSELA")

#byte TRISF  = getenv("sfr:TRISF")
#byte TRISA  = getenv("sfr:TRISA")

#byte ADCON0 = getenv("sfr:ADCON0")
#byte ADCON1 = getenv("sfr:ADCON1")

#byte ADRESH = getenv("sfr:ADRESH")
#byte ADRESL = getenv("sfr:ADRESL")


// HARDWARE SPI

#define SPI_DO     PIN_C5
#define SPI_DI     PIN_C4
#define SPI_CLK    PIN_C3
#define SPI_CS     PIN_C2
#define SPI_LOAD   PIN_A5

//====================================
void main()
{
 unsigned int16 xcount   = 0;  //counter
 unsigned int16 ycount   = 0;  //counter
 unsigned int8  lobyte   = 0; 
 unsigned int8  lobyte2  = 0;
 unsigned int8  hibyte   = 0;
 unsigned int8  hibyte2  = 0;
 unsigned int16 ADCch1   = 0;
 unsigned int8  ADCch1lo = 0;
 unsigned int8  ADCch1hi = 0;

 // For the 16F1947 Transceiver on my board I have to establish a few signals:
 // using Linear LTC1387.

 // Activate the Transceiver (IN-ON)
 output_high(XCEIVER_ENABLE);
 // Establish protocol mode on Pin RE2:  RS-232 is low
 output_low(RS485);
 // Ensure the TX mode is ENABLED (DXEN)
 output_high(TXEN);
 // Ensure the RX mode is DISABLED (RXEN)
 output_low(RXEN);
 #use rs232( baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, UART1, errors) //outbound
 

 printf("Start \n\r");
 delay_ms(10);
 output_low(TXEN);   //Disable TX
 output_high(RXEN);  //Enable  RX

 // NOTE - THIS CODE WAS USED WHEN INITIALLY ATTEMPTING TO USE THE CCS FUNCTIONS

 /*  CCS functions for ADC
 //  The VREF_VREF is reference to the external reference pins 19 AVDD and 20 AVSS
     setup_adc_ports (sAN0|sAN1|sAN2|sAN3|sAN5|sAN6|sAN7|sAN8|sAN9|VREF_VREF);

     setup_adc( ADC_CLOCK_DIV_32 );  // equates to 1.6us sampling rate.
                                  // might be able to use DIV_16, but
                                  // not recommended per 16F1947 spec,
                                  // Page 162, section 16.1.3

*/

// ADC functions based on register useage

// Based upon 16.1 of the 1947 spec

// Step 1a Port Configuration:  TRIS the ports to inputs

 TRISF = 0xFF; // Set all of port A to inputs
 TRISA = 0x0F; // Set bit 3-0 of port A to inputs; the remaining to be outputs

// Step 1b Port configuration:  Declare the ports to be analog

 ANSELF = 0x9E;   // 1001_1110, which conforms to port F of the schematic
 ANSELA = 0x0F;   // 0000_1111, which conforms to port A of the schematic

// Step 2 channel section and enable the ADC - ADCON0

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 //  N/A    |--  Analog Channel Selection CHS --|  GO/DONEn  ADON
 //   0       0      0        0       0      0        0        1

 ADCON0 = 0x01;   // For now, channel 0 will be selected, ADON is enabled

// Step 3 Voltage References - ADCON1

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 // ADFM    |--Conversion CLK --|    N/A    -VRef   |-  +VRef  -|
 //  0        0      1        0       0       1       1      1
 // Left         FOSC/32                    External     FVR

  ADCON1 = 0x26; 

 // Step 4:  FVR (Fixed Voltage Reference) for the ADC.
 // Bit 7   Bit 6    Bit 5    Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 // FVREN   FVRRDY   TSEN     TSRNG   |- CDAFVR -|    |-  ADFVR  -|
 //   1       x       0         x      0      0        1        1
 //  Enable         Temperature OFF  DAC/CPS off    ADC on at 4.096
   FVRCON = 0x83;

// SPI setup

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H);

output_low(SPI_LOAD);  //Keep low.  No reason to toggle

//for now, leave in the TX mode

output_low(RXEN);   // Turn off the Receive
output_high(TXEN);  // Turn on the Transmit

 while(1)
  {

// Using the SPI commands found in the CCS library

lobyte  = xcount;
lobyte2 = ycount;
hibyte  = xcount>>8;     // Push the high byte of xcount into hibyte   
hibyte2 = ycount>>8;     // Push the high byte of ycount into hibyte   


hibyte  = hibyte & 0x0F;   // Clear the upper nibble   
hibyte  = hibyte | 0x10;   // Write command '1' to enable DACa, 2x Voltage
                           // and preserve the rest of the word
hibyte2 = hibyte2 & 0x0F;  // Clear the upper nibble   
hibyte2 = hibyte2 | 0x90;  // Write command '1' to enable DACb, 2x Voltage


output_low(SPI_CS);
spi_write(hibyte);
spi_write(lobyte);
output_high(SPI_CS);  // CS needs to be toggle for Channel B to work
output_low(SPI_CS);
spi_write(hibyte2);
spi_write(lobyte2);
output_high(SPI_CS);

xcount++;
ycount--;

// set_adc_channel(sAN6);
// delay_us(2);
// ADCch1 = read_adc();

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 //  N/A    |--  Analog Channel Selection CHS --|  GO/DONEn  ADON
 //   0       0      0        1       1      0        1        1

 ADCON0 = 0x19;   // Channel 6 will be selected, ADON is enabled
 delay_us(2);     // Delay the response
 ADCON0 = 0x1B;   // Channel 6 will be selected, ADON is enabled, Go!
 delay_us(2);     // Bit one will automatically turn itself off when done

 ADCch1lo = ADRESL;
 ADCch1hi = ADRESH;
 ADCch1   = make16(ADRESH, ADRESL);

 printf("A/D ch6 = %2x\r\n", ADCch1);

output_bit(LIGHT1,ADCch1&0x0001);
output_bit(LIGHT2,ADCch1&0x0002);
output_bit(LIGHT3,ADCch1&0x0004);
output_bit(LIGHT4,ADCch1&0x0008);
output_bit(LIGHT5,ADCch1&0x0010);
output_bit(LIGHT6,ADCch1&0x0020);
output_bit(LIGHT7,ADCch1&0x0040);
output_bit(LIGHT8,ADCch1&0x0080);
//output_bit(LIGHT7,ADCch1&0x0100);
//output_bit(LIGHT8,ADCch1&0x0200);
//output_bit(LIGHT7,ADCch1&0x0400);
//output_bit(LIGHT8,ADCch1&0x0800);
//delay_ms(50);


  }
}


Note: Made a modification to the LED code after posting - rckrllrfg
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 11, 2011 4:21 pm     Reply with quote

Quote:
ADCON0 = 0x19; // Channel 6 will be selected, ADON is enabled
delay_us(2); // Delay the response
ADCON0 = 0x1B; // Channel 6 will be selected, ADON is enabled, Go!
delay_us(2); // Bit one will automatically turn itself off when done

// *** Missing the loop to poll the GO/DONE bit here ***

ADCch1lo = ADRESL;
ADCch1hi = ADRESH;

Where's your loop to wait for the GO/DONE bit to go low after you start
the conversion ? A 2us fixed delay isn't enough.

The PIC data sheet says:
Quote:

16.1.4 CONVERSION CLOCK

The time to complete one bit conversion is defined as
TAD. One full 10-bit conversion requires 11.5 TAD periods
as shown in Figure 16-2.


This table says that one TAD period with a clock divisor of 32, at 20 MHz
is 1.6us.
Quote:

TABLE 16-1: ADC CLOCK PERIOD (TAD) VS. DEVICE OPERATING FREQUENCIES

So 11.5 * 1.6us = 18.4us conversion time. You have only a 2us delay.
That's why it says to poll the GO/DONE bit until it goes to 0.


Also, this section says you must wait at least 4.42us after changing the
A/D channel, before you can begin the conversion.
Quote:

EQUATION 16-1: ACQUISITION TIME EXAMPLE

TACQ = 4.42μs

But your code only waits for 2us.

I didn't review the rest of your program.
RckRllRfg



Joined: 20 Jul 2011
Posts: 60

View user's profile Send private message

This is a good start
PostPosted: Fri Nov 11, 2011 4:42 pm     Reply with quote

Hi PCM programmer -

This timing is a good place to start. I will add in the loop.

Regards -

Paul T.
RckRllRfg



Joined: 20 Jul 2011
Posts: 60

View user's profile Send private message

Update... we're up and running
PostPosted: Fri Nov 11, 2011 10:57 pm     Reply with quote

After a few modifications to timing and the voltage reference, I am up and running.

Enclosed is my code below. It contains both the SPI and ADC. As mentioned in the prior post, I am using my SPI to DAC chip to feed directly into the ADC of the PIC. The DAC is producing a staircase pattern.

This code also makes use of the FVRCON for the internal voltage

Code:



#include <16F1947.h>
#device ICD = TRUE;
#Device ADC=10;
#fuses HS,PLL_SW, NOWDT,NOPROTECT,NOLVP
#use delay( clock=20000000 )

// Function to set data from the PIC to the DAC via SPI
//#include <C:\Users\4thPoint\Desktop\ROS\Project244\Firmware\Project244_SPI2DAC.c> 

// Serial communications

#define RXEN             PIN_D4
#define TXEN             PIN_D7
#define XCEIVER_ENABLE   PIN_D5
#define RS485            PIN_D6

// LED lighting

#define LIGHT1           PIN_D0
#define LIGHT2           PIN_D1
#define LIGHT3           PIN_D2
#define LIGHT4           PIN_D3
#define LIGHT5           PIN_G0
#define LIGHT6           PIN_G1
#define LIGHT7           PIN_G2
#define LIGHT8           PIN_G3

// For this project the E0,E1 and E2 are set to analog input by default
// These need to be changed to digital inputs:

#byte ANSELE = getenv("sfr:ANSELE")

// FVR for the ADC.  Enabling for option 4.096V

#byte FVRCON = getenv("sfr:FVRCON")

//  For ADC, we will need to clarify the role of the ports

#byte ANSELF = getenv("sfr:ANSELF")
#byte ANSELA = getenv("sfr:ANSELA")

#byte TRISF  = getenv("sfr:TRISF")
#byte TRISA  = getenv("sfr:TRISA")

#byte ADCON0 = getenv("sfr:ADCON0")
#byte ADCON1 = getenv("sfr:ADCON1")

#byte ADRESH = getenv("sfr:ADRESH")
#byte ADRESL = getenv("sfr:ADRESL")


// HARDWARE SPI

#define SPI_DO     PIN_C5
#define SPI_DI     PIN_C4
#define SPI_CLK    PIN_C3
#define SPI_CS     PIN_C2
#define SPI_LOAD   PIN_A5

//====================================
void main()
{
 unsigned int16 xcount   = 0;  //counter
 unsigned int16 ycount   = 0;  //counter
 unsigned int8  lobyte   = 0; 
 unsigned int8  lobyte2  = 0;
 unsigned int8  hibyte   = 0;
 unsigned int8  hibyte2  = 0;
 unsigned int16 ADCch1   = 0;
 unsigned int8  ADCch1lo = 0;
 unsigned int8  ADCch1hi = 0;

 // For the 16F1947 Transceiver on my board I have to establish a few signals:
 // using Linear LTC1387.

 // Activate the Transceiver (IN-ON)
 output_high(XCEIVER_ENABLE);
 // Establish protocol mode on Pin RE2:  RS-232 is low
 output_low(RS485);
 // Ensure the TX mode is ENABLED (DXEN)
 output_high(TXEN);
 // Ensure the RX mode is DISABLED (RXEN)
 output_low(RXEN);
 #use rs232( baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, UART1, errors) //outbound
 

 printf("Start \n\r");
 delay_ms(10);


 // NOTE - THIS CODE WAS USED WHEN INITIALLY ATTEMPTING TO USE THE CCS FUNCTIONS

 /*  CCS functions for ADC
 //  The VREF_VREF is reference to the external reference pins 19 AVDD and 20 AVSS
     setup_adc_ports (sAN0|sAN1|sAN2|sAN3|sAN5|sAN6|sAN7|sAN8|sAN9|VREF_VREF);

     setup_adc( ADC_CLOCK_DIV_32 );  // equates to 1.6us sampling rate.
                                  // might be able to use DIV_16, but
                                  // not recommended per 16F1947 spec,
                                  // Page 162, section 16.1.3

*/

// ADC functions based on register useage

// Based upon 16.1 of the 1947 spec

// Step 1a Port Configuration:  TRIS the ports to inputs

 TRISF = 0xFF; // Set all of port A to inputs
 TRISA = 0x0F; // Set bit 3-0 of port A to inputs; the remaining to be outputs

// Step 1b Port configuration:  Declare the ports to be analog

 ANSELF = 0x9E;   // 1001_1110, which conforms to port F of the schematic
 ANSELA = 0x0F;   // 0000_1111, which conforms to port A of the schematic

// Step 2 channel section and enable the ADC - ADCON0

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 //  N/A    |--  Analog Channel Selection CHS --|  GO/DONEn  ADON
 //   0       0      0        0       0      0        0        1

 ADCON0 = 0x01;   // For now, channel 0 will be selected, ADON is enabled

// Step 3 Voltage References - ADCON1

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 // ADFM    |--Conversion CLK --|    N/A    -VRef   |-  +VRef  -|
 //  1        0      1        0       0        0       1      1
 // Right         FOSC/32                    Internal     VDD

//  ADCON1 = 0xA0;  //  with VDD
    ADCON1 = 0xA3; //   with FVR

 // Step 4:  FVR (Fixed Voltage Reference) for the ADC.
 // Bit 7   Bit 6    Bit 5    Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 // FVREN   FVRRDY   TSEN     TSRNG   |- CDAFVR -|    |-  ADFVR  -|
 //   1       x       0         x      0      0        1        1
 //  Enable         Temperature OFF  DAC/CPS off    ADC on at 4.096
   FVRCON = 0x83;

// SPI setup

setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H);

output_low(SPI_LOAD);  //Keep low.  No reason to toggle

//for now, leave in the TX mode

output_low(RXEN);   // Turn off the Receive
output_high(TXEN);  // Turn on the Transmit

 while(1)
  {

// Using the SPI commands found in the CCS library

lobyte  = xcount;
lobyte2 = ycount;
hibyte  = xcount>>8;     // Push the high byte of xcount into hibyte   
hibyte2 = ycount>>8;     // Push the high byte of ycount into hibyte   


hibyte  = hibyte & 0x0F;   // Clear the upper nibble   
hibyte  = hibyte | 0x10;   // Write command '1' to enable DACa, 2x Voltage
                           // and preserve the rest of the word
hibyte2 = hibyte2 & 0x0F;  // Clear the upper nibble   
hibyte2 = hibyte2 | 0x90;  // Write command '1' to enable DACb, 2x Voltage


output_low(SPI_CS);
spi_write(hibyte);
spi_write(lobyte);
output_high(SPI_CS);  // CS needs to be toggle for Channel B to work
output_low(SPI_CS);
spi_write(hibyte2);
spi_write(lobyte2);
output_high(SPI_CS);

xcount++;
ycount--;

// set_adc_channel(sAN6);
// delay_us(2);
// ADCch1 = read_adc();

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 //  N/A    |--  Analog Channel Selection CHS --|  GO/DONEn  ADON
 //   0       0      0        1       1      0        1        1

 ADCON0 = 0x19;   // Channel 6 will be selected, ADON is enabled
 delay_us(3);     // Delay for the response (the mux needs to be switched and settled)
 ADCON0 = 0x1B;   // Channel 6 will be selected, ADON is enabled, Go!

 while (bit_test(ADCON0, 1)==1){    //Wait for the DONEn to complete
 delay_us(1);
 }

 ADCch1lo = ADRESL;
 ADCch1hi = ADRESH;
 ADCch1   = make16(ADRESH, ADRESL);

 printf("A/D ch6 = %2x", ADCch1hi);
 printf("%2x          ", ADCch1lo);

// Display the count on the 8 LEDS

output_bit(LIGHT1,~ADCch1&0x0001);
output_bit(LIGHT2,~ADCch1&0x0002);
output_bit(LIGHT3,~ADCch1&0x0004);
output_bit(LIGHT4,~ADCch1&0x0008);
output_bit(LIGHT5,~ADCch1&0x0010);
output_bit(LIGHT6,~ADCch1&0x0020);
output_bit(LIGHT7,~ADCch1&0x0040);
output_bit(LIGHT8,~ADCch1&0x0080);

 // Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
 //  N/A    |--  Analog Channel Selection CHS --|  GO/DONEn  ADON
 //   0       1      1        1       1      1        1        1

 ADCON0 = 0x7D;   // Channel 6 will be selected, ADON is enabled
 delay_us(3);     // Delay for the response (the mux needs to be switched and settled)
 ADCON0 = 0x7F;   // Channel 6 will be selected, ADON is enabled, Go!

 while (bit_test(ADCON0, 1)==1){    //Wait for the DONEn to complete
 delay_us(1);
}

 ADCch1lo = ADRESL;
 ADCch1hi = ADRESH;
 ADCch1   = make16(ADRESH, ADRESL);

 printf("A/D FVR = %2x", ADCch1hi);
 printf("%2x\r\n", ADCch1lo);

  }
}


Recommend any other mods or tweaks to the code? Please post.

RckRllRfg
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Nov 14, 2011 3:01 am     Reply with quote

Any more tips?

Yes, now you've got it to work with your own - totally non-portable - code, change it to work with the CCS ADC support code. read_adc() will do all the waiting for you and won't be PIC or clock dependant. It does the same thing, but it just handles everything for you so your code will still work if you change clock rate.

You are still not meeting the acquisition time requirement. The ADC on many PICS can be set to do that wait for you, unfortunately the PIC16F1947 isn't one of them. Confused If you are only ever sampling the one channel then only set the channel once before your main while() loop. You then don't need to change it, and the acquisition time is no longer a problem: you can ignore it and sample at will. The acquisition wait is only required when changing from one channel to another, to allow the hardware to "catch up".

If you are sampling one channel you can also convert asynchronously. By that I mean use read_adc(START_ONLY) and read_adc(READ_ONLY) to trigger ADC conversions and read them at some other time. I have a main loop that loops at a little over the ADC conversion time by reading the ADC result with read_adc(READ_ONLY) then immediately triggering the next conversion by read_adc(START_ONLY). The code then goes about its business, processing the ADC result. by the time the loop comes round again the ADC has almost finished its conversion so the read_adc(READ_ONLY) only waits for a short time for the result. You can only easily do this with a single channel. If you need more than one then you may be able to:

read adc result (waits for conversion to finish)
select a channel
do some stuff that takes at least the acq time
trigger a conversion
do some more stuff
loop back

but I've never tried that. It should work.

Another minor point, if(bit_test(ADCON0, 1)==1) is doing the same thing twice (I have seen it done three times by someone!). bit_test() returns a boolean result, 0 or 1 which is what if () is looking for. There's no need to test that against 1. So if (bit_test(ADCON0)) will do the same thing. The optimiser is canny enough to know that and will optimise to the same code in both cases. if((bit_test(ADCON0, 1)==1) == TRUE) even optimises down as well.

Oh yes, and there's no point in delaying while in the while loop waiting for the ADC conversion to finish. Simply have the while without the delay:

while (bit_test(ADCON0, 1));

That's syntactically correct. Some folk like to include a empty block as it is arguably clearer. It also acts as a place holder in case you decide you really wanted to have some code in there after all:

while (bit_test(ADCON0, 1)) {};

but it's not essential. The delay simply means you will wait just a little bit longer than you really need to. The CCS routines do the same but in assembler which is probably shorter and faster

If you really want this loop to fly then there's no way you have enough time for printf(). They will have to go. I'm assuming they are there at the moment purely for debug.

RF Developer
Ttelmah



Joined: 11 Mar 2010
Posts: 19515

View user's profile Send private message

PostPosted: Mon Nov 14, 2011 3:48 am     Reply with quote

Not quite RF_Developer.
The acquisition time is also needed between successive samples on the same channel.
When the ADC is read, the sample capacitor is disconnected from the incoming signal. It needs to re-acquire between samples.

Best Wishes
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Nov 14, 2011 5:14 am     Reply with quote

Ttelmah wrote:
Not quite RF_Developer.
The acquisition time is also needed between successive samples on the same channel.
When the ADC is read, the sample capacitor is disconnected from the incoming signal. It needs to re-acquire between samples.

Best Wishes


Yes, the hold cap is disconnected from the incoming signal. Yes, it does need to charge to the level of the incoming signal, i.e. reacquire. The ADC conversion is non-destructive as far as the hold cap voltage is concerned. However the re-acquisition time ON THE SAME CHANNEL starts the moment the ADC finishes the previous conversion. It can start the moment the ADC has made its LSB decision (its a successive approximation ADC). Whether it actually does depends on the precise implementation. This means that by the time you get to trigger another a few processor cycles have already gone by, allowing faster effective re-acquisition. When changing channels, the acq obviously starts from the channel change. You can get better results faster on one channel only. You'll only get problems in practise if the signal is pretty rapidly changing.

The full acq time is only actually required at worst case, i.e. from one extreme of the ADC range to the other. This is why most of the time folk don't think acq time is even an issue: if they are changing from one channel to another with roughly similar voltage it settles far faster than say, sampling 0.1V then 4.9V on successive samples and thus can't see much improvement from increasing acq time.

Another aspect to this is source impedance, as the time to charge the hold cap is, of course, dependant not just on the PIC input circuitry but also the driving circuit. This is why resistive dividers cause inaccuracy. The acq time calculations tend to assume a source impedance of less than 2K.

Really what you'd want to do is change the channel ready for the next conversion immediately you finish the previous.

Its all a matter of trading off time with accuracy. For fastest conversion rate single channel works significantly better than multiple. But then I really wish the PIC ADC subsystem would do self-scanning, autonomous conversions with buffering, but it doesn't. Does it on the dsPICs? I've never worked with those?

RF Developer.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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