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 support@ccsinfo.com

Stuck with LTC1854 ADC Driver

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



Joined: 23 Sep 2010
Posts: 3

View user's profile Send private message

Stuck with LTC1854 ADC Driver
PostPosted: Thu Sep 23, 2010 4:16 am     Reply with quote

I am trying to interface two LTC1854 12bit ADC devices over SPI bus to a PIC18F8680 device. The constraint here is that SPI must be used in hardware mode (not software bit banging) and SPI mode has to be mode 0 or mode 3. I am using ADCs in single ended acquisition

The ADCs seem to be working fine if configured for SPI mode 3, but for channel 0 only. It seems the ADC device is unable to configure itself for acquisition of other channels. Code returned for +5 input on channel 0 gives 0x7DE0 code, ~= 4.91 V, but still garbage result for other channels.

If configured for mode 0,0 the value returned is not correct at all. For +5 input on channel 0 0x1DE0 code is returned ~= 1.16 V

Can someone help after looking at the LTC1854 datasheet.

Code:

//Program to acquire analog data from 2x LTC1854
#include <18F8680.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES MCLR                     //Master Clear pin enabled

#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1  (SPI_L_TO_H)
#define SPI_MODE_1_0  (SPI_H_TO_L)
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

#define TRISTC  0xf94
#define SSPSTAT 0xfc7
#define SSPCON1 0xfc6
#define SSPCON2 0xfc5

#define ADC1START PIN_E5  //75
#define _ADC1RD   PIN_E6  //74
#define ADC2START PIN_E3  //77
#define _ADC2RD   PIN_E4  //76

//Local Functions
void Initialize_ADCs(void);
void ReadLTC1854_1(int8 channel, unsigned int8* dataoutm, unsigned int8* dataoutl);
void ReadLTC1854_2(int8 channel, unsigned int8* dataoutm, unsigned int8* dataoutl);

unsigned int8 ChannelSelect[8]=
{
//for single ended acquisition
//SGL  ODD  SELECT1   SELECT0  x  x  NAP  Sleep
0b10000000,//80
0b11000000,//c0
0b10010000,//90
0b11010000,//d0
0b10100000,//a0
0b11100000,//e0
0b10110000,//b0
0b11110000 //f0
};

void main()
{
   int8 i;
   unsigned int16  adc2smagnitude;//unsigned magnitude
   unsigned int8 adcvaluem,adcvaluel;//conversion result
   int1 adc2ssign;//sign bit
   float adcresult;//floating point value for user printed as string

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_MASTER|SPI_MODE_0_0|SPI_CLK_DIV_4|SPI_SAMPLE_AT_END);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   //Setup_Oscillator parameter not selected from Intr Oscillator Config tab

   printf("Testing SPI Port for ADC (LTC1854). Uart setting 9600-8-N-1.\n");     
   Initialize_ADCs();   
   
   printf("TRISC = %X\n", *TRISTC);
   printf("SSPSTAT = %X\n", *SSPSTAT);
   printf("SSPCON1 = %X\n", *SSPCON1);
   printf("SSPCON2 = %X\n", *SSPCON2);   
   
  while(TRUE)
  {
   //Acquiring ADC 1 channels
   printf("\nAcquiring ADC 1 channels.\n");
   for(i=0;i<8;i++)
   {     
     ReadLTC1854_1(i, &adcvaluem, &adcvaluel);//Using third diagram in figure 7 in datasheet
     adc2smagnitude = (adcvaluem & 0x7F)<<8; //sign not needed
     adc2smagnitude += adcvaluel;     
     adc2smagnitude = adc2smagnitude >> 4;//4 unused nibbles for 12 bit device
     adc2ssign = bit_test(adcvaluem,7);
     
     if(adc2ssign==1)
       adcresult = -5.0f; // span is -5 to +5 volts, MSB = 1 means -5v weight here
     else
       adcresult = 0;
     
     adcresult += adc2smagnitude*0.00244140625;// magnitude *  10v / 2^12 (12 bit device)
               
      printf("ADC1-Channel %d, MSB = %X, LSB = %X, Result in Volts = %f\n",i,adcvaluem,adcvaluel,adcresult);
      delay_ms(10);//test to settle adc pins
   }
   
   delay_ms(400);
   printf("\n");   
   
   //Acquiring ADC 2 channels
   printf("\nAcquiring ADC 2 channels.\n"); 
   for(i=0;i<8;i++)
   {     
     ReadLTC1854_2(i, &adcvaluem, &adcvaluel);
     adc2smagnitude = (adcvaluem & 0x7F)<<8; //sign not needed
     adc2smagnitude += adcvaluel;     
     adc2smagnitude = adc2smagnitude >> 4;//4 unused nibbles for 12 bit device
     adc2ssign = bit_test(adcvaluem,7);
     
     if(adc2ssign==1)
       adcresult = -5.0f; // span is -5 to +5 volts, MSB = 1 means -5v weight here
     else
       adcresult = 0;
     
     adcresult += adc2smagnitude*0.00244140625;// magnitude *  10v / 2^12 (12 bit device)
               
      printf("ADC2-Channel %d, MSB = %X, LSB = %X, Result in Volts = %f\n",i,adcvaluem,adcvaluel,adcresult);
      delay_ms(10);//test to settle adc pins
   }
   
   delay_ms(400);
   printf("\n");
   
  }//while

}//main

void Initialize_ADCs(void)
{
output_low(ADC1START);//ADC1 conversion start signal, active high
output_low(ADC2START);//ADC2 conversion start signal, active high
output_high(_ADC1RD);//ADC 1 RD or CS signal, active low
output_high(_ADC2RD);//ADC 2 RD or CS signal, active low
}

//Read ADC 1
//channel = 0-7

void ReadLTC1854_1(int8 channel, int8* dataoutm, int8* dataoutl)
{
printf("Sampling Channel Command %X: ", ChannelSelect[channel]);
output_low(_ADC1RD);//enable chip
spi_write(ChannelSelect[channel]);//read command
delay_us(1);//hold
spi_write(ChannelSelect[channel]);//read command
output_high(_ADC1RD);//disable chip
delay_us(5);//hold

output_high(ADC1START);
delay_us(2);//hold
output_low(ADC1START);
delay_us(2);//wait for conversion

output_low(_ADC1RD);//enable chip
*dataoutm = spi_read(0);
*dataoutl = spi_read(0);
output_high(_ADC1RD);//disable chip
}


//Read ADC 2
//channel = 0-7

void ReadLTC1854_2(int8 channel, int8* dataoutm, int8* dataoutl)
{
printf("Sampling Channel Command %X: ", ChannelSelect[channel]);
output_low(_ADC2RD);//enable chip
spi_write(ChannelSelect[channel]);//read command
delay_us(1);//hold
spi_write(ChannelSelect[channel]);//read command
output_high(_ADC2RD);//disable chip
delay_us(5);//hold

output_high(ADC2START);
delay_us(2);//hold
output_low(ADC2START);
delay_us(2);//wait for conversion

output_low(_ADC2RD);//enable chip
*dataoutm = spi_read(0);
*dataoutl = spi_read(0);
output_high(_ADC2RD);//disable chip
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Sep 23, 2010 5:20 pm     Reply with quote

Quote:

The ADCs seem to be working fine if configured for SPI mode 3, but for
channel 0 only. It seems the ADC device is unable to configure itself for
acquisition of other channels. Code returned for +5 input on channel 0
gives 0x7DE0 code, ~= 4.91 V, but still garbage result for other channels.

The text description of the SPI communication in the data sheet sounds
like Mode 3 to me, so your experience matches what I read. The data
transfer diagrams don't show mode 3. They don't match the text
description. I don't know what the intention of their tech writers is.

My advice is to cut down your program so it only tests channel 1 (for
example). If possible, get rid of at least 75% of your code. Then I think
it would be simple enough to trouble-shoot.

For an example of cutting it down, get rid of all this:
Quote:

setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(SPI_MASTER|SPI_MODE_0_0|SPI_CLK_DIV_4|SPI_SAMPLE_AT_END);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);

Replace it with this. It uses Mode 3 and it also slows the clock way down.
Code:

setup_spi(SPI_MASTER | SPI_MODE_1_1 | SPI_CLK_DIV_16);

There is a lot more code that can be removed (for this test).
Owais



Joined: 23 Sep 2010
Posts: 3

View user's profile Send private message

PostPosted: Mon Sep 27, 2010 3:55 am     Reply with quote

I tried the suggestion and reduced code to: (beginning code is same)

Code:

void main()

  unsigned int16  adc2smagnitude;//unsigned magnitude
  unsigned int8 adcvaluem,adcvaluel;//conversion result
  int1 adc2ssign;//sign bit
  float adcresult;//floating point value for user printed as string
 
  setup_spi(SPI_MASTER | SPI_MODE_1_1 | SPI_CLK_DIV_64);
 
  output_high(_ADC1RD);//enable chip
 
  while(TRUE)
  {       
   printf("Command word for Channel 1 (single ended) = %X: ", ChannelSelect[1]);
   output_low(_ADC1RD);//enable chip
   spi_write(ChannelSelect[1]);//read command
   delay_us(1);//hold
   spi_write(0);//read command, dont care by LTC this byte
   output_high(_ADC1RD);//disable chip
   delay_us(5);//hold
   
   output_high(ADC1START);
   delay_us(2);//hold
   output_low(ADC1START);
   delay_us(2);//wait for conversion
     
   output_low(_ADC1RD);//enable chip
   adcvaluem = spi_read(0);
   adcvaluel = spi_read(0);
   output_high(_ADC1RD);//disable chip
   
   adc2smagnitude = (adcvaluem & 0x7F)<<8; //sign not needed
   adc2smagnitude += adcvaluel;     
   adc2smagnitude = adc2smagnitude >> 4;//4 unused nibbles for 12 bit device
   adc2ssign = bit_test(adcvaluem,7);
   
   if(adc2ssign==1)
     adcresult = -5.0f; // span is -5 to +5 volts, MSB = 1 means -5V weight here
   else
     adcresult = 0;
   
   adcresult += adc2smagnitude*0.00244140625;// magnitude *  10v / 2^12 (12 bit device)
             
   printf("MSB = %X, LSB = %X, Result in Volts = %f\n",adcvaluem,adcvaluel,adcresult);     
   delay_ms(400);   
  }//while
}//main


But still only channel no 0 is sampled and i cant get the ADC to be configured for sampling other channels. I have used two different LTC1854 devices and both shouldn't be damaged. Also the controller (on a small header PCB) is functional as i can drive some serial memories just fine on another board with it.

any other suggestions anyone ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19383

View user's profile Send private message

PostPosted: Mon Sep 27, 2010 4:36 am     Reply with quote

First, I'd encapsulate the 16bit transfers. So something like:
Code:

union combiner {
   int8 b[2]
   int16 w;
}

int16 talk_to_adc(union combiner command) {
   union combiner result;
   //Trigger last configured conversion
   output_high(ADC1START);
   delay_cycles(1);//Only 40nSec required high
   output_low(ADC1START);
   delay_us(5);//wait for conversion - note tconv, is 5uSec worst case
   
   output_low(_ADC1RD);//enable chip
   result.b[1] = spi_read(command.b[1]);
   result.b[0] = spi_read(command.b[0]);
   output_high(_ADC1RD);//disable chip
   return result.w;
}

Then the single command, reads the last configured conversion, and sets the new configuration.
Then your test loop becomes:

Code:

  int16 value;
  while(TRUE) {       
   printf("Command word for Channel 1 (single ended) = %X: ", ChannelSelect[1]);
   value=talk_to_adc(ChannelSelect[1]*256L); //Send 16bit command, get
   //16bit value from last command.

   //Then for testing, don't fiddle around converting to volts, but print
   //the value returned
   printf("%ld",value);     
   delay_ms(400);   
  }//while
}//main

Then I'd also try channel 2. Given that the 'odd' channels are effectively the -ve inputs in differential mode, it is possible the problem is switching to single ended operation, rather than with retrieving the other channels - worth testing.
I'm using the internal 'cast' abilities of C here, to convert a 16bit value, into a union to access the bytes, then to treat the MSB of this as the sign for output.

Best Wishes
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