| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| avjarun 
 
 
 Joined: 28 Mar 2021
 Posts: 13
 
 
 
			    
 
 | 
			
				| SPI INTERFACE |  
				|  Posted: Mon Feb 07, 2022 3:17 am |   |  
				| 
 |  
				| 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: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Feb 07, 2022 4:24 am |   |  
				| 
 |  
				|  	  | 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: 13
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Feb 07, 2022 6:18 am |   |  
				| 
 |  
				| 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: 19967
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Feb 07, 2022 6:31 am |   |  
				| 
 |  
				| 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.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |