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

AD7705 Reading 26922 at Zero volts ???

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



Joined: 14 Dec 2009
Posts: 33
Location: Wales

View user's profile Send private message

AD7705 Reading 26922 at Zero volts ???
PostPosted: Thu Feb 04, 2010 10:43 am     Reply with quote

I've been testing an AD7705 and it works but value read at zero
volts wont display as zero but has an offset of around 26922.

I've tried the UNIPOLAR and BIPOLAR configurations with no
success. Is there a way to zero the input in software - I note
that there is a register for offset but no documentation.

Some test code is below. It cant be anything obvious although I
guess if you know this chip it probably is.

The Reference is +2.5V and 0V with AIN(+) and AIN(-) shorted.
Code:

//**********************************************************//
//  File:      Combined-Driver-PID-Control-V1.c         
//**********************************************************//
#include    <18F4620.h>
#device     PASS_STRINGS=IN_RAM
#fuses    HS, WDT, WDT256, NOPROTECT, BROWNOUT, PUT, NOLVP
#use    DELAY(CLOCK=20MHz, RESTART_WDT) // , OSC=10000000)
#use      RS232(BAUD=115200, PARITY=N, XMIT=PIN_C6,    RCV=PIN_C7, ERRORS, STREAM=USB, RESTART_WDT)
#use       SPI(MASTER, DO=PIN_C5, DI=PIN_C4, CLK=PIN_C3, MSB_FIRST, MODE=0, BITS=16, STREAM=SPI_0)
//   #use    FAST_IO(D)
//   Unused Inputs
//   A0 to A5
//   E0 to E3
//  B0 to B7
// #include   "PID.h"
#define      LED            PIN_D0
#define      ADC_RESET      PIN_D1
#define      ADC_DRDY      PIN_D2

// Pin D2
// Pin D2
#define      AD7705_CS      PIN_D5
#define      AD7243_CS      PIN_D6

// Pin D7   Space for MAX186 Chip Sel
#define      RS232_TXD      PIN_C0
#define      CCP1_IN         PIN_C1
#define      CPP2_IN         PIN_C2
#define      ADC_CLK         PIN_C3
#define      ADC_DI         PIN_C4
#define      ADC_D0         PIN_C5
#define      TXD            PIN_C6
#define      RXD            PIN_C7

//   D3      Not allocated
//   D4      Not allocated
//   D5       Not allocated
#define      AD7705_CS      PIN_D5   // This is the DAC Output
#define      AD7243_CS      PIN_D6   // This is the ADC Output
//   D7      Space chip select
#define      RS232_TXD      PIN_C0
#define      CCP1_IN         PIN_C1   // Used for velocity encoder
#define      CPP2_IN         PIN_C2   // Used for velocity encoder
#define      ADC_CLK         PIN_C3
#define      ADC_DI         PIN_C4
#define      ADC_DO         PIN_C5
#define      TXD            PIN_C6
#define      RXD            PIN_C7

// AD7705 Calibration Mode Settings
#define      ADC_NORMAL      0x00   //
#define      ADC_SELF      0x40
#define      ADC_ZERO_SCALE   0x80
#define      ADC_FULL_SCALE   0xC0

// AD7705 Gain Settings
#define      ADC_GAIN_1      0x00
#define      ADC_GAIN_2      0x08
#define      ADC_GAIN_4      0x10
#define      ADC_GAIN_8      0x18
#define      ADC_GAIN_16      0x20
#define      ADC_GAIN_32      0x28
#define      ADC_GAIN_64      0x30
#define      ADC_GAIN_128     0x38

// AD7705 Polar Operations
#define      ADC_BIPOLAR      0x04
#define      ADC_UNIPOLAR   0x00

// AD7705 Update rates
#define      ADC_50         0x04
#define      ADC_60         0x05
#define      ADC_250         0x06
#define      ADC_500         0x07

// float integral[5][5];
long int read_adc_value(int1);
long int read_adc_word(void);
float    get_dac_volts(float mv, float sp, float pb);
float    absolutef(float a, float b);
int16    get_valid_adc_data(int1);
void    read_checked_adc_data(void);
int16    absolute(int16, int16);
void    exercise_dac(void);
void    write_dac(int16);
void    init_adc(void);
void    write_adc_byte(BYTE);

void    setup_adc_device(int, int, int, int);
int16    get_valid_adc_data(int1);
int16    get_dac_bits(float vout);

float    get_mpa(int16);
float    Kp=5;
float    Ki=1;
float    Kd=10;

//***********************************************************

void      main(void)
{
int8      count        ;
int8      reset = 5    ;
int8      cause        ;         //   Number of counter
int16      dac          ;
int16      adc          ;
float      mvnew        ;
float      mvlast    ;
float      sp = 220     ;
float      pb = 50      ;
float      dacv         ;         // DAC voltage level
float      roc            ;         // Rate of change
float      volts       ;   

fprintf(USB, "\r\n Initialising AD7705 (3 seconds)");
init_adc();
setup_wdt(WDT_ON);

while(1)
   {   output_toggle(LED);
      adc     =   get_valid_adc_data(0);
      if (adc > 0xfff0) init_adc();
      if (count++ % reset == 0)
         {
         count = 0;
         mvlast = mvnew;
         }
      mvnew   =   get_mpa(adc);
      if (count == 0)   
         {
         roc=absolutef(mvlast, mvnew);   ///reset;            
         // fprintf(USB, "\r\n Rate of change: %f", roc);
         }
      dacv   =   get_dac_volts(mvnew, sp, pb);
      volts    =   (Kp*dacv)+(Ki/Ki)+(Kd*roc);
      if (volts > 5) volts = 5;
      dac      =   get_dac_bits(volts);
      fprintf(USB, "\r\nSP:%f, MV:%f, ADC:%Lu, DAC:%f(V), Rate:%f, ERR:%f ",sp, mvnew,adc,volts,roc,sp-mvnew);
      fprintf(USB, "(PID %f V)", volts);
      delay_ms(200);
   }
}     
//***********************************************************

float      absolutef(float a, float b)
{
// fprintf(USB1, "\r\n A : %Lu, B : %Lu", a, b);
if (a > b) return(a-b);
if (b > a) return(b-a);
return(0);
}

//***********************************************************

int16   get_valid_adc_data(int1 verb)
{   //  verb is for verbose mode.
static int16 last;
static int16 new;
static int16 diff;
int16  retries = 0;

while(1)   {   restart_wdt();
            new  = read_adc_value(1);
            diff = absolute(new, last);
            if ((diff > 500) && (retries == 0))
               {   // if (verb)   
                  //   fprintf(USB, "\r\n Bad Value : %Lu", absolute(new,last));
                  if (verb)   fprintf(USB, "!");
                  retries++;            
                  //fprintf(USB, "!");
                  // delay_ms(200);
                  continue;
               }
            //   diff=absolute(new, last);
            if (diff < 500)
               {   retries = 0;
                  if (verb)
                     {   fprintf(USB, "\r\n Reading AD7705 %Lu %Lu (Diff : %Lu)", new, last, diff);
                     }
                  return(new);
               }   last = new;
            if (retries++ > 3)
               {   if (verb)   fprintf(USB, "\r\n **[ TOO MANY ERRORS ]** \r\n");
                  return(0xffff);
               }
         }
}
//***********************************************************

long int   read_adc_value(int1 ch)
{
long long   retries=0;
long int    value;
int8      restarts=0;

while (input(ADC_DRDY))
   {   restart_wdt();
      delay_us(100);
      if (retries++ > 0xfff)
         {   // fprintf(USB, "\r\n ADC Timed Out !");
            break;
         }
   };
if (ch)   write_adc_byte(0x39);
else   write_adc_byte(0x38);
if (retries >= 0xfff) return(0xffff);
value = read_adc_word();
return(value);
}
//***********************************************************

long int read_adc_word()
{       BYTE   i;
       long   data;

      output_low(AD7705_CS);
      for (i=1;i<=16;++i)   {   output_low(ADC_CLK);
                     output_high(ADC_CLK);
                     shift_left(&data,2, input(ADC_D0));
                  }   output_high(AD7705_CS);
      return(data);
}
//***********************************************************

void   init_adc(void)
{
fprintf(USB, "\r\n Initialising ADC : \r\n");
output_low(ADC_RESET);
output_high(ADC_CLK);
output_high(AD7705_CS);
output_high(ADC_RESET);
setup_adc_device(ADC_NORMAL, ADC_GAIN_1, ADC_BIPOLAR, ADC_50);
delay_ms(500);   restart_wdt(); fprintf(USB, "\r Reset ADC (3 Seconds)");
delay_ms(500);   restart_wdt(); fprintf(USB, "\r Reset ADC (2 Seconds)");
delay_ms(500);   restart_wdt(); fprintf(USB, "\r Reset ADC (1 Second)");
}
//***********************************************************

void   setup_adc_device(int calmode, int gainsetting, int operation, int rate)
{
      write_adc_byte(0x20);
      write_adc_byte(rate);
      write_adc_byte(0x10);
      write_adc_byte(calmode);
}
//***********************************************************
// And now the functions for the ADC AD7705

void   write_adc_byte(BYTE data)
{      BYTE   i;

      output_low(AD7705_CS);

      for (i=1; i<=8;++i)
         {   output_low(ADC_CLK);
            output_bit(ADC_DI, shift_left(&data,1,0));
            output_high(ADC_CLK);
         }   output_high(AD7705_CS);
}
//***********************************************************

float   get_dac_volts(float mv, float sp, float pb)
{
//    The error within proportional band must be scaled
//   from 0 to 1 using the following formula
//   Error = Kp * (Sp - Mv)/Pb.
//
float   volts;
if (mv >= sp+pb) return(-1);
if (mv <= sp-pb) return(1)  ;
volts = (sp-mv)/pb;
if (mv > sp) return(+1 * volts);
else       return(-1 * volts);
}
//***********************************************************

int16   get_dac_bits(float vout)
{
#define   VOLTS_PER_BIT    10/0xfff
//   This assumes the minimum Vout is -5V
float   v;
int16   bits;
v      =   5+vout;
bits   =   (int16)(v/VOLTS_PER_BIT);
return(bits);
}
//***********************************************************

float   get_mpa(int16 adc)
{   
float   MAX_MPA   =   300 ;
float   MAX_BITS=   50000;
float   mpa;

mpa    =    (float)(MAX_MPA / MAX_BITS)*adc;
return(mpa);
}
//***********************************************************

int16   absolute(int16 a, int16 b)
{
// fprintf(USB1, "\r\n A : %Lu, B : %Lu", a, b);
if (a > b) return(a-b);
if (b > a) return(b-a);
return(0);
}
//***********************************************************
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Feb 04, 2010 2:28 pm     Reply with quote

Your code is somewhat incoherent because you are using software
SPI (in code) to talk to the AD7705 chip, but then you have stuck in the
#use spi() statement which would use the spi_xfer() function to
send/receive data. You also have tons and tons of code, which makes it
difficult to easily detect the problem.

I suggest the following: Use the CCS driver,
Quote:
c:\program files\picc\drivers\ad7705.c

and #include the driver in your test program. Don't copy and paste
the driver into your program. Leave it as an #include file.
Edit the pin list at the top of the ad7705.c file so it fits the connections
on your board.

Then write a very short test program. Call these two routines:
Code:

adc_init();

and then
Code:

int16 result;

result = read_adc_value(0);

Then use printf to display the result from the read_adc_value() function.

Also post your compiler version, because CCS made some modifications
to improve the read_adc_value() routine on Jan 16, 2007. This is marked
in the comments in the routine.
ac34856



Joined: 14 Dec 2009
Posts: 33
Location: Wales

View user's profile Send private message

PostPosted: Thu Feb 04, 2010 4:55 pm     Reply with quote

Thanks again, I stuck the code in the program rather than as a separate
file as I read there were errors in the driver and I wanted to make sure it
wasnt loading a file from somewhere I didnt expect - which can be a problem
when debugging.

However, in the end I got it working. The problems I had were initialising via the command register too soon after a the reset was low on the ADC and
now it reads zero - although with a slight offset still.

The problem I do see and *dont* understand is when I change the update
rate the output cant be zeroed again when I move from an update of 50 or 60 to 250 or 500.

This relates to the internal clock and increasing the clock speed would likely
decrease the integration time so I would have expected the voltage to in bits decrease ... instead it increases.

Oh well all day will be spent until I'm done - and hopefully someone will
post some useful suggestions on how to increase the update rate and
still be able to zero the AD7705.

For anyone reading this post there is a better version (pin compatible
etc) of the AD7705 from Maxim ... well it sounds better on paper.
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