|
|
View previous topic :: View next topic |
Author |
Message |
avjarun
Joined: 28 Mar 2021 Posts: 12
|
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: 19495
|
|
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: 12
|
|
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: 19495
|
|
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
|