Electronic – ADC registers setup using spi communication

avrcembeddedmicrocontroller

I'm new to microcontrollers – I'm trying to read external ADC values from an AD7798 ADC using SPI communication.

Initially I have to setup some ADC registers – some registers are not configured. To configure the registers, I have to use the communication register to select which register I want to configure.

For example, I want to set the AD7798 configuration register (16bit). I have code like this:
#include
#define ADC_CS PORTB.3
#define WG_CS PORTB.4
#define MOSI PORTB.5
#define MISO_PU PORTB.6
#define MISO_PIN PINB.6
#define SCK PORTB.7

//global functions.
unsigned int adcConfig;
unsigned int adcMode;
unsigned int adcId;

void init_io(void) 
{ 
DDRB = 0xBF;        // make SCK, MOSI, CS1, CS2 outputs 
ADC_CS = 1;              //disable ADC 
WG_CS = 1;               //disable WaveGenerator 
MISO_PU = 1;             //enable pull-up on MISO so we can test !RDY 
} 

unsigned char spi(unsigned char data) 
{ 
//Start transmision 
SPDR = data; 
//Wait for transmision complete 
while (!(SPSR & (1<<SPIF))); 
return SPDR; 
} 

//Sets the waveform generator output to given phase 
void SetWGPhase(unsigned int phase) 
{ 
SPCR = 0x5A; // mode #2 F_CPU/64 
WG_CS = 0;                      // enable 
spi(0x20); 
spi(0x00); 
spi((phase >> 8) | 0xC0);       //Load into phase register 0 
spi(phase & 0x00FF); 
WG_CS = 1; 
} 

void setupAd(){ 
    SPCR = 0x5D; 
    ADC_CS = 0; 
   // while(spi(0x10) != 0x10); 
    spi(0x10);                  //set up communication register for configuration reg. 
    spi(0x07);        
    spi(0x10); 

    spi(0x08);                  //set up communication register for mode reg. 
    spi(0x00);        
    spi(0x0A); 
    ADC_CS = 1; 
    } 


 unsigned int ReadAd(void) 
 { 
unsigned int data; 
SPCR = 0x5D; // mode #3 F_CPU/16 
CheckStatus();
ADC_CS = 0;                     // enable 
while (MISO_PIN != 0) ;         // wait for  DOUT/!RDY line to go low 
//Read data 
spi(0x58);                      //Place readinstruction in communication register 
data = spi(0xFF);               // read hi-byte 
data = (data << 8) | spi(0xFF); // and lo-byte. 
ADC_CS = 1;                     // disable 
return data; 
} 

 unsigned char CheckStatus(void)
{
char adcStatus; 
            SPCR = 0x5D;
            ADC_CS = 0;                     // enable  
            while(ADC_CS_PIN);
            adcStatus = 0xFF; 
while(!(adcStatus & 0x80)){                                     

             spi(0x40);
             adcStatus = spi(0xFF); 
          }          
ADC_CS = 1;                      

return adcStatus;
}

unsigned int ReadAdConfReg(void) 
{              
  unsigned int retvalconfig;
SPCR = 0x5D;  
ADC_CS = 0;      
while (MISO_PIN != 0) ; 
spi(0x50); 
adcConfig = spi(0xFF);    
adcConfig = (adcConfig << 8) | spi(0xFF); 
retvalconfig= adcConfig;
ADC_CS = 1; 
return retvalconfig;
} 

unsigned int ReadAdModeReg(void) 
{              
  unsigned retvalmode;
SPCR = 0x5D;  
ADC_CS = 0;        
while (MISO_PIN != 0) ; 
spi(0x48); 
adcMode = spi(0xFF);  
adcMode = (adcMode << 8) | spi(0xFF); 
retvalmode =adcMode;   
ADC_CS = 1;
return retvalmode;
} 
unsigned int ReadAdIdReg(void) 
{              

SPCR = 0x5D;  
ADC_CS = 0;          
while (MISO_PIN != 0) ; 
spi(0x60); 
adcId = spi(0xFF);    
ADC_CS = 1;
 return adcId; 
} 

when I print configuration register it is giving value"16383". but when I power off/on the target i am getting "1808(which is equivalent to 0x0710)" after that it is giving same value as"16383". I have tested with different configurations also but it is not changing, always printing "16383" except power off/on.I think default value.

Even with mode register it is always printing"10(which is equivalent to 0x000A)" but that is the value i am getting always, even if I change the configuration to "0x0022".

Even I have tried to read Id register, but it is giving "0x48". but in data sheet it mentioned "0xX8" for AD7798.
Thanks in advance.

Someone help me please, I am not getting any idea about what mistake I am doing here.

Best Answer

While this datasheet is making my eyes bleed with the complexity of doing a simple conversion/read, you need to make some simple changes.

I'm not sure why people are making this harder than it really is. You pull the chip select line low, and the target IC should simply read whatever you give it until you pull it high again. Just because your method takes an 8-bit value doesn't mean you can't call it twice to pass a 16-bit value to your IC. There is no need to bit-bang anything. That is nonsense.

Call your SPI method to tell the ADC you're looking to write to the configuration register:

spi(0x10);

As I understand from the datasheet, you can immediately write your 16-bit value to the configuration register after that, so you'd do:

spi(0x07);
spi(0x10);

I forget which way that'll end up being assembled on the target IC side, so you could simply reverse them if things don't work right. There's no need to bit shift any values at all. Worst case scenario is you have to pull the CS line back high before pulling it low again to actually send the data to write to the configuration register.

Otherwise, this is super simple. Remember, if the target SPI device expects more than one byte, i.e. a 16-bit value, chances are good that sending the bytes in the order they'd otherwise appear normally (so if you want to send 0x1234, you'd have 0x12 and 0x34) will work fine and you won't need to shift anything.