|
|
View previous topic :: View next topic |
Author |
Message |
ac34856
Joined: 14 Dec 2009 Posts: 33 Location: Wales
|
AD7705 Reading 26922 at Zero volts ??? |
Posted: Thu Feb 04, 2010 10:43 am |
|
|
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
|
|
Posted: Thu Feb 04, 2010 2:28 pm |
|
|
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:
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
|
|
Posted: Thu Feb 04, 2010 4:55 pm |
|
|
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. |
|
|
|
|
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
|