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

SPI INTERFACE

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



Joined: 28 Mar 2021
Posts: 12

View user's profile Send private message

SPI INTERFACE
PostPosted: Mon Feb 07, 2022 3:17 am     Reply with quote

Hi All,

I am trying to interface with AD5421 using SPI which is of 24 bits. I have written the code for reading and writing registers. However, when I write a value to the control register and read it back, I am getting a value of 0 which indicates that I am making mistakes. Tried to figure out the error but I keep on failing and I do get ZERO always. Can someone please check my code and advice me to get it fixed please.

Wiring / Connections mentioned in code.

Thanks in advance.

Code:




/*
AD5421            PIC
-----------------------------
SCLK            RC3
SDI               RC5
SDO               RC4
SYNC            RC0
*/


#include <16F1783.h>
#fuses INTRC_IO, NOWDT, NOBROWNOUT, PUT,NOMCLR
#use delay(clock=32M)
#use rs232(baud=1200,xmit=pin_C6,rcv=pin_C7)
#use spi(MASTER, DI=PIN_C4, DO=PIN_C5, CLK=PIN_C3, BAUD=10000000,FORCE_HW,SAMPLE_RISE,)

#define SPI_SELECT PIN_C0
#define SPI_CLK    PIN_C3
#define SPI_DI     PIN_C4 
#define SPI_DO     PIN_C5 


#define uchar unsigned char
#define uint8 unsigned int8
#define uint16 unsigned int16
#define uint32 unsigned int32



#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)




#byte PORTA = 0x00C
#byte PORTB = 0x00D
#byte PORTC = 0x00E



#byte LATA = getenv("SFR:LATA")
#byte LATB = getenv("SFR:LATB")
#byte LATC = getenv("SFR:LATC")


#bit RLED=LATC.2
#bit GLED=LATC.1
#bit XCEN=LATB.0
#bit RTS=LATB.2
#bit RESET=LATB.3
#bit SYNC=LATC.0
#bit FAULT= PORTB.5

char data;
int1 spi_flag=0;



void init_ad5421();
void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue);
int32 AD5421_GetRegisterValue(uint8 regAddress);


//////////////////////////////////
//AD5421
//////////////////////////////////
/* Registers */
#define AD5421_REG_DAC_DATA            0x1
#define AD5421_REG_CTRL               0x2
#define AD5421_REG_OFFSET            0x3
#define AD5421_REG_GAIN               0x4
#define AD5421_READ                  (1 << 7)
#define AD5421_REG_RESET            0x7

//////////////////////////////////


void main(void) {

   set_tris_b(0b00100010);
   set_tris_c(0b10000000);
   setup_adc(ADC_OFF);


   XCEN=0;
   RTS=0;
   RESET=1;
   RLED=0;
   GLED=0;
   printf("Starting");

   output_high(SPI_SELECT); delay_ms(100);
     init_ad5421();
 
  while (TRUE)  {
   GLED=1; delay_ms(300); GLED=0;delay_ms(300);

  }

}






void init_ad5421() {
   int32 retVal=0;
   
   
   AD5421_SetRegisterValue(AD5421_REG_RESET,0);
   delay_us(500);


   AD5421_SetRegisterValue(AD5421_REG_CTRL,0x1180);

   retVal = AD5421_GetRegisterValue( AD5421_REG_CTRL);

   printf("RET VAL:%lu",retVal);
   

   
}



void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue)
{
   uint8 data[5] = {0x00, 0x00, 0x00, 0x00, 0x00};   
   
   data[1] = regAddress;
   data[2] = (uint8)((regValue & 0xFF00) >> 8);
   data[3] = (uint8)((regValue & 0x00FF) >> 0);
   output_low(SPI_SELECT); 
   spi_write(data[1]);
   spi_write(data[2]);
   spi_write(data[3]);
   output_high(SPI_SELECT);
}



int32 AD5421_GetRegisterValue(uint8 regAddress)
{
   uint8 data[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
   uint32 receivedData = 0x00;   
   
   data[1] = regAddress | AD5421_READ;
   output_low(SPI_SELECT); 
   SPI_Write(data[1]);
   SPI_Write(data[2]);
   SPI_Write(data[3]);
   output_high(SPI_SELECT);
   

   delay_us(100);
   output_low(SPI_SELECT);
   

   data[0]=spi_read(0);
   data[1]=spi_read(0);
   data[2]=spi_read(0);

   
   output_high(SPI_SELECT);
   
   receivedData += ((uint32)data[1] << 8);
   receivedData += ((uint32)data[2] << 0);

    return receivedData;
}


Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Mon Feb 07, 2022 4:24 am     Reply with quote

Code:

/*
AD5421            PIC
-----------------------------
SCLK            RC3
SDI               RC5
SDO               RC4
SYNC            RC0
*/


#include <16F1783.h>
#fuses INTRC_IO, NOWDT, NOBROWNOUT, PUT,NOMCLR
#use delay(INTERNAL=32M)
#use rs232(baud=1200,xmit=pin_C6,rcv=pin_C7)
#use spi(MASTER, SPI1, BAUD=8000000, MODE=0, BITS=24, STREAM=AD5421)
//The chip uses mode 0, Set this here.

#define SPI_SELECT PIN_C0

#define uchar unsigned char
#define uint8 unsigned int8
#define uint16 unsigned int16
#define uint32 unsigned int32
//Don't mix things. You have settings here for
//the 'old' setup SPI operation, but are using #use SPI.

#byte PORTA = 0x00C
#byte PORTB = 0x00D
#byte PORTC = 0x00E



#byte LATA = getenv("SFR:LATA")
#byte LATB = getenv("SFR:LATB")
#byte LATC = getenv("SFR:LATC")


#define RLED PIN_C2
#define GLED PIN_C1
#define XCEN PIN_B0
#define RTS PIN_B2
#define RESET PIN_B3
#define SYNC PIN_B0
#define FAULT PIN_B5

char data;
int1 spi_flag=0;

void init_ad5421();
void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue);
unsigned int16 AD5421_GetRegisterValue(uint8 regAddress);


//////////////////////////////////
//AD5421
//////////////////////////////////
/* Registers */
#define AD5421_REG_DAC_DATA            0x1
#define AD5421_REG_CTRL               0x2
#define AD5421_REG_OFFSET            0x3
#define AD5421_REG_GAIN               0x4
#define AD5421_REG_RESET            0x7
#define AD5421_READ 0b10000000

//////////////////////////////////


void main(void)
{
   set_tris_b(0b01000010);
   //SDI must have TRIS set. SDO and SCK must have this cleared
   set_tris_c(0b10000000);
   setup_adc(ADC_OFF);


   output_low(XCEN);
   output_low(RTS);
   output_high(RESET);
   output_low(RLED);
   output_low(GLED);
   printf("Starting");

   output_high(SPI_SELECT); delay_ms(100);
   init_ad5421();
 
   while (TRUE) 
   {
      output_high(GLED); delay_ms(300); output_low(GLED);delay_ms(300);
   }
}

void init_ad5421()
{
   unsigned int16 retVal=0;
     
   AD5421_SetRegisterValue(AD5421_REG_RESET,0);
   delay_us(50);

   AD5421_SetRegisterValue(AD5421_REG_CTRL,0x1180);
   retVal = AD5421_GetRegisterValue( AD5421_REG_CTRL);

   printf("RET VAL:%lu",retVal);
}

void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue)
{
   uint32 data = 0;   
   
   data=make32((int8)0, regAddress, regValue);
   output_low(SPI_SELECT);
   spi_xfer(AD5421, data, 24); //send 24 bit data
   output_high(SPI_SELECT);
}

unsigned int16 AD5421_GetRegisterValue(uint8 regAddress)
{
   uint32 data = 0x00; 
   
   data=make32((int8)0, regAddress|AD5421_READ, 0,0);
   output_low(SPI_SELECT);
   data = spi_xfer(AD5421, data, 24); //send 24 bit data, with reply
   output_high(SPI_SELECT);
   output_high(SPI_SELECT);
   
   return data;  //return low 16bit of data clocked back
}


There are several things to comment and think about.
First use the compiler. It is much simpler to let the compiler do the I/O
rather than manually controlling the port and LAT. The compiler 'knows' to
write to LAT and read the port, so let it do this. Much less likely to make
errors. You were making one in your TRIS setup for the SPI. SDI must
have it's TRIS set. SDO and SCK must have this clear. You were setting
TRIS B.5 to 1 not B.6....
SDI on the PIC is the input, and must connect to SDO on the peripheral.

Then don't mix the SPI operation modes. CCS has two fundamentally
distinct ways of setting up and using SPI. The first used setup_spi,
spi_read and spi_write. The second uses #USE SPI, and spi_xfer.
If you look in the manual, you will find that the entries for each of these
_do not_ reference the commands for the other way of working. The
#USE is the modern way of working, and does lots of extra things
for you. Do not mix operations from these two methods.
#USE already knows about mode numbers.

Now that having been said the big reason it goes wrong is you are
misunderstanding how the read works. You send a single 8 bit value
containing the register number with the read bit set. You then clock
16 bull bits, and receive the 16bit value back as part of the same
transfer. You are sending 24bits and then trying to clock the 'reply'....
avjarun



Joined: 28 Mar 2021
Posts: 12

View user's profile Send private message

PostPosted: Mon Feb 07, 2022 6:18 am     Reply with quote

Firstly, I thank you so much for your quick reply. Noted on your comments and will remember your words. Made the modifications as below.... but still... I am using the following PINS on PORTC and not the PINS on PORTB

DI=PIN_C4, DO=PIN_C5, CLK=PIN_C3

In this case should I used APFCON as I did below???
The other one what I could see is... No matter what I write to the control register...... I do get a reply of 384 when I read it back. Meaning... it still holds the defaults and what I write is not being updated. Any clues???

Code:



/*
AD5421            PIC
-----------------------------
SCLK            RC3
SDI               RC5
SDO               RC4
SYNC            RC0
*/


#include <16F1783.h>
#fuses INTRC_IO, NOWDT, NOBROWNOUT, PUT,NOMCLR
#use delay(clock=32M)
#use rs232(baud=1200,xmit=pin_C6,rcv=pin_C7)

#use spi(MASTER, SPI1, BAUD=8000000, MODE=0, BITS=24, STREAM=AD5421)

#define SPI_SELECT PIN_C0


#define uchar unsigned char
#define uint8 unsigned int8
#define uint16 unsigned int16
#define uint32 unsigned int32




#byte APFCON = 0x11D
#byte PORTA = 0x00C
#byte PORTB = 0x00D
#byte PORTC = 0x00E



#byte LATA = getenv("SFR:LATA")
#byte LATB = getenv("SFR:LATB")
#byte LATC = getenv("SFR:LATC")


#bit SCKSEL=APFCON.4
#bit SDOSEL=APFCON.5
#bit SDISEL=APFCON.3


#bit RLED=LATC.2
#bit GLED=LATC.1
#bit XCEN=LATB.0
#bit RTS=LATB.2
#bit RESET=LATB.3
#bit SYNC=LATC.0
#bit FAULT= PORTB.5

char data;
int1 spi_flag=0;



void init_ad5421();
void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue);
unsigned int16 AD5421_GetRegisterValue(uint8 regAddress);


//////////////////////////////////
//AD5421
//////////////////////////////////
/* Registers */
#define AD5421_REG_DAC_DATA            0x1
#define AD5421_REG_CTRL               0x2
#define AD5421_REG_OFFSET            0x3
#define AD5421_REG_GAIN               0x4
#define AD5421_READ                  (1 << 7)
#define AD5421_REG_RESET            0x7

//////////////////////////////////


void main(void) {

   set_tris_b(0b00100010);
   set_tris_c(0b10010000);
   setup_adc(ADC_OFF);


   SDISEL=0;
   SDOSEL=0;
   SCKSEL=0;


   XCEN=0;
   RTS=0;
   RESET=1;
   RLED=0;
   GLED=0;
   printf("\n\r\r\r\nStarting");

   output_high(SPI_SELECT); delay_ms(100);
     init_ad5421();
 
     while (TRUE)  {
    GLED=1; delay_ms(300); GLED=0;delay_ms(300);
   if(FAULT==1)RLED=1; else RLED=0;
  }

}






void init_ad5421() {
   int16 retVal=0;
   
   
   AD5421_SetRegisterValue(AD5421_REG_RESET,0);
   delay_us(50);

   AD5421_SetRegisterValue(AD5421_REG_CTRL,0x1C00);
   delay_ms(100);

   retVal = AD5421_GetRegisterValue( AD5421_REG_CTRL);

   printf("RET VAL:%lu\n\r",retVal);
   

   
}



void AD5421_SetRegisterValue(uint8 regAddress, uint16 regValue)
{
   uint32 data = 0;   
   
   data=make32((int8)0, regAddress, regValue);
   output_low(SPI_SELECT);
   spi_xfer(AD5421, data, 24); //send 24 bit data
   output_high(SPI_SELECT);
}

unsigned int16 AD5421_GetRegisterValue(uint8 regAddress)
{
   uint32 data = 0x00;
   
   data=make32((int8)0, regAddress|AD5421_READ, 0,0);
   output_low(SPI_SELECT);
   data = spi_xfer(AD5421, data, 24); //send 24 bit data, with reply
   output_high(SPI_SELECT);
   output_high(SPI_SELECT);
   
   return data;  //return low 16bit of data clocked back
}


Thanks Again
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Mon Feb 07, 2022 6:31 am     Reply with quote

Yes, to use the alternate pin locations, you have to set the APFCON
bits 3, 4 or 5 according to what pin you want to move.
You also have to set the TRIS correctly for the pins you want to use.

Again for the APF controls just use the compiler:

#bit SDISEL=getenv("BIT:SDISEL")

etc..
You don't show APF selections in your original post, so if FORCE_HW is
accepted the port will be on the default pins. If it isn't, software SPI
will be setup, which won't work with the spi_read or write functions.
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