This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS8681: Interfacing ADS8681 with PIC32

Part Number: ADS8681

Hi,

I interfaced ADS8681 with PIC32MX processor but it's not working.

READ_HWORD is not returning proper register value. it never worked. I get 32-bit reading. As per datasheet, I should get 16 bit reading followed by 0's. 

Even WRITE_HWORD is also not working. It seemed like it worked one time.  I set RANGE_SEL[3:0] to 1001b (2.5*VREF) once.

When I send all 0's I get ADC conversion value as response and that was working as per the selection I made to RANGE_SEL[3:0] bits. 

But now even as of sudden, though I gave 1.6v as input analog voltage, I get 6.2v (156.25 * 16-bit reading).

Please help me in resolving the issue.

I am attaching the code file. Please check and let me know if I'm missing anything.

ads8681.c
#define SPI_ON_BIT          (SPIFLASH_SPICON1bits.ON)

// Maximum speed of SPI Flash part in Hz
// Should theoretically operate at 25MHz, but need to account for level-shifting delays
#define SPIFLASH_MAX_SPI_FREQ       (16000000ul)

#define ClearSPIDoneFlag()
    static inline __attribute__((__always_inline__)) void WaitForDataByte( void )
    {
        while (!SPIFLASH_SPISTATbits.SPITBE || !SPIFLASH_SPISTATbits.SPIRBF);
    }



#define VREF 4.09f
#define  ADC_RESOLUTION 65535

#define DEVICE_ID_REG 		0x00			//Device ID register
#define DEVICE_ADDR_REG 	0x02			//Device ID register
#define RST_PWRCTL_REG 		0x04			//Reset and power control register

#define PWRDN  0  // 1- power down mode, 0 -active mode
#define NAP_DIS (1<<0) // PUTS ADC IN NAP MODE 0-DISABLE,1- ENABLE, CS#-HIGH
#define NAP_EN (1<<1) // PUTS ADC IN NAP MODE 0-DISABLE,1- ENABLE, CS#-HIGH
#define RST_APP_HW (2<<0)
#define RST_APP_SW (2<<1)
#define IN_AL_DIS  (4<<1)
#define IN_AL_EN  (4<<0)
#define VDD_AL_DIS  (5<<1)
#define VDD_AL_EN  (5<<0)


#define WKEY_REG 0x05
#define WKEY 0x69   

#define SDI_CTL_REG 		0x08			//SDI data input control register
#define SDI_MODE_CPOL0_CPHASE0 0b00
#define SDI_MODE_CPOL0_CPHASE1 0b01
#define SDI_MODE_CPOL1_CPHASE0 0b10
#define SDI_MODE_CPOL1_CPHASE1 0b11

#define SDO_CTL_REG 		0x0C			//SDO-x data input control register
#define SDO_MODE   0b00

#define SD01_CTL_REG 		0x0D			//SDO-1 pin config
#define SDO1_TRISTATE 0b00  
#define SDO1_ALARM    0b01  
#define SDO1_GPIO     0b10  
#define SDO1_QUAD     0b11  
#define GPIO_VAL_0    (0<<4)
#define GPIO_VAL_1    (1<<4)

#define DATAOUT_CTL_REG 	0x10			//Output data control register
#define DATA_VAL 0b000
#define PAR_EN (0<<3) // Parity-0 no parity

#define RANGE_CTL_REG 	0x11		
#define RANGE_INCL (0<<8)	// don't include range conf. reg val
#define ALARM_NO_INCL_SD0 (11<<0|10<<0)	
#define ALARM_INCL_ACT_H (11<<0|10<<1) //H FLAG IN
#define ALARM_INCL_ACT_L (11<<1|10<<0)  //L FLAG IN
#define ALARM_INCL_H_L (11<<1|10<<1)  //INCLUDE BOTH H AND L

#define VDD_ALARM_NO_INCL (13<<0|12<<0)  //INCLUDE BOTH H AND L
#define DEVICE_ADDR_NO_INCL (14<<0)

#define RANGE_SEL_REG 		0x14			//Input range selection control register

#define RANGE_1_25_VREF   0b1011
#define RANGE_1_5_VREF    0b1010
#define RANGE_2_5_VREF    0b1001
#define RANGE_3_VREF      0b1000

#define INTREF_DIS     (1<<6) // INTERNAL ADC-VREF DISABLED.

#define INTREF_EN     (0<<6) // INTERNAL ADC-VREF DISABLED.

#define ALARM_REG 			0x20			//ALARM output register

#define OVW_ALARM   0b1 
#define TRP_IN_H_FLAG (4<<1) // LOW INPUT VOLTAGE
#define TRP_IN_L_FLAG (4<<1) // HIGH INPUT VOLTAGE

#define ALARM_ACTIVE_REG	0x21

#define ACTIVE_IN_H_FLAG (2<<1) // ACTIVE ALM ON LOW INPUT VOLTAGE
#define ACTIVE_IN_L_FLAG (3<<1) // ACTIVE ALM ON HIGH INPUT VOLTAGE

#define ALARM_H_TH_REG 		0x24			//ALARM high threshold and hysteresis register

#define INP_ALRM_HIGH_TH (0x0000) // HIGH THRESHOLD FOR INPUT ALARM

#define INP_ALRM_HYST_REG	0x27

#define INP_ALRM_HYST_RESERVED	0b00
//#define INP_ALRM_HYST ()

#define ALARM_L_TH_REG 		0x28			//ALARM low threshold register
#define INP_ALRM_LOW_TH 	0x0000			//low threshold for the input alarm.

#define CLEAR_HWORD(reg,data)  (0b110000000000000000000000000000000 | (reg<<16) | data)
#define READ_HWORD(reg)   (0b11001000000000000000000000000000| (reg<<16) )
#define READ_BYTE(reg)  (0b01001000000000000000000000000000| (reg<<16) )
#define WRITE_HWORD(reg,data)  (0b11010000000000000000000000000000| (reg<<16) |data)
#define WRITE_MSB(reg,data)  (0b11010010000000000000000000000000| (reg<<16) |data)
#define WRITE_LSB(reg,data)  (0b11010100000000000000000000000000| (reg<<16) |data)
#define SET_HWORD(reg,data)  (0b110110000000000000000000000000000| (reg<<16) | data)

 static DWORD vSPIONSave;
 static DWORD SPICON1Save;
long double measurement=0.0;

static void startAGCSPI(){
   enableDeviceCS(0xFF); //disable CS
   // Save SPI state (clock speed)
   SPICON1Save = SPIFLASH_SPICON1;
   vSPIONSave = SPI_ON_BIT;
   SPI_ON_BIT = 0;
   SPIFLASH_SCK_TRIS = 0;  // Set SCK pin as an output
   SPIFLASH_SDI_TRIS = 1;  // Make sure SDI pin is an input
   SPIFLASH_SDO_TRIS = 0;  // Set SDO pin as an output
   SpiChnOpen(4, SPICON_MSTEN|SPI_OPEN_MODE32 | SPICON_ON, 80 );
   SPI_ON_BIT = 1;	
   DelayMs(1);	
   enableDeviceCS(ADS);//Enable CS
}
static void stopAGCSPI(){
    enableDeviceCS(0xFF);
    SPI_ON_BIT = 0;
    SpiChnClose(4);
    SPIFLASH_SPICON1 = SPICON1Save;
    SPI_ON_BIT = vSPIONSave;
}
DWORD AGCWriteArray(DWORD cmd)
{
	DWORD val;
	startAGCSPI();
       IFS1bits.SPI4TXIF = 0;
	SPIFLASH_SPI_IF = 0;
       SPIFLASH_SSPBUF = cmd;
	//while(!IFS1bits.SPI4TXIF); //WaitForDataByte();
	while(!SPIFLASH_SPI_IF);
	val = SPIFLASH_SSPBUF;
	SPIFLASH_SPI_IF = 0;
	// Release the chip select to begin the write
	stopAGCSPI();
	return val;
}

DWORD AGCReadArray(DWORD dwAddress, DWORD *vData, WORD wLength)
{
	DWORD Dummy;
	startAGCSPI();
	SPIFLASH_SPI_IF = 0;
	IFS1bits.SPI4TXIF=0;
	SPIFLASH_SSPBUF = dwAddress;
	//while(!IFS1bits.SPI4TXIF);
	while(!SPIFLASH_SPI_IF);
	Dummy = SPIFLASH_SSPBUF;
	if(wLength==0){
		*vData++ =Dummy;
	}else{
		while(wLength--)
		{
			SPIFLASH_SSPBUF = 0;
			while(!SPIFLASH_SPI_IF);
			*vData++ = SPIFLASH_SSPBUF;
			SPIFLASH_SPI_IF = 0;
		}
	}
	// Deactivate chip select
	stopAGCSPI();
	return Dummy;
}

static int spi_write_word_reg(BYTE reg, WORD val)
{
    DWORD data = WRITE_HWORD(reg,val);
   data =  AGCWriteArray(data);
    return 1;
}

static int spi_write_byte_reg(BYTE reg, BYTE val)
{
    DWORD data = WRITE_LSB(reg,val);
    data = AGCWriteArray(data);
   //AGCReadArray(0x00,&data,1);
    return 1;
}

static WORD spi_read_word_reg(BYTE reg)
{
    DWORD read[2]={0,0},d[2]={0,0};
    DWORD dwAddress = READ_HWORD(reg);
    d[0]=AGCReadArray(dwAddress,&read[0],1);
    d[1]=AGCReadArray(dwAddress,&read[1],1);
    return read[1];
}

static WORD spi_read_byte_reg(BYTE reg)
{
    DWORD read;
    DWORD dwAddress = READ_BYTE(reg);
    AGCReadArray(dwAddress,&read,1);
    return read;
}

static int spi_set_reg(BYTE reg, WORD val)
{
    DWORD data = SET_HWORD(reg,val);
    data =AGCWriteArray(data);
    return 1;
}

static int spi_clear_reg(BYTE reg, WORD val)
{
    DWORD data = CLEAR_HWORD(reg,val);
    AGCWriteArray(data);
    return 1;
}

void getAGC(){
    DWORD dwAddress=0;//WRITE_HWORD(0,0);//AD_HWORD(RANGE_SEL_REG);
    DWORD read=0;
   AGCReadArray(dwAddress,&read,0);
//    read=AGCWriteArray(dwAddress);
    read&=0xFFFF0000;
    read>>=16;
    measurement =(long double) read*156.25/1000000; //4095
   
}

void AGCInit(void)
{
  	spi_write_word_reg(RANGE_SEL_REG,RANGE_2_5_VREF|INTREF_EN);
	DelayMs(5);
	getAGC();
/*	vSPIONSave = spi_read_word_reg(RANGE_SEL_REG);
	DelayMs(500); SPI_OPEN_CKP_HIGH| 
	vSPIONSave = spi_read_byte_reg(DEVICE_ADDR_REG);
		DelayMs(500);
       spi_write_byte_reg(WKEY_REG,WKEY);
	DelayMs(500);
 	vSPIONSave = spi_read_word_reg(RANGE_SEL_REG);
	DelayMs(500);
	spi_write_byte_reg(RST_PWRCTL_REG,PWRDN|NAP_EN|IN_AL_DIS|VDD_AL_DIS);
    spi_write_byte_reg(SDI_CTL_REG,SDI_MODE_CPOL0_CPHASE0);
    spi_write_byte_reg(SDO_CTL_REG,SDO_MODE);
    spi_write_byte_reg(SD01_CTL_REG,SDO1_GPIO|GPIO_VAL_1);
    spi_write_word_reg(DATAOUT_CTL_REG,DATA_VAL|PAR_EN|RANGE_INCL|ALARM_NO_INCL_SD0|VDD_ALARM_NO_INCL|DEVICE_ADDR_NO_INCL);
   	*/ 
}
#endif

Thanks,

Vikram

  • Hi Srinivasarao,

    Thanks for your query on TI E2E forum.

    After running these commands:

    ->  spi_write_word_reg(RANGE_SEL_REG,RANGE_2_5_VREF|INTREF_EN)

    -->  DWORD data = WRITE_HWORD(reg,val);

    Can you please check if the "data" is   <11010_000> <0001_0100> <00000000> <00001001>? also can you capture the timing on SDI to ADC with SCLK and /CS together by using a scope?

    After these two commands, use your register read instruction to check the content of this RANGE_SEL_REG register, this will let you know if your programming is successful:

    -> vSPIONSave = spi_read_word_reg(RANGE_SEL_REG)

    -->   DWORD dwAddress = READ_HWORD(reg);

    Please check if the "dwAddress" is <11001_000> <0001_0100> <00000000> <00000000>? also can you capture the timing on SDI and SDO on ADC by using a scope? Please notice that If a valid READ_HWORD command is issued in frame F, the output data word for frame (F+1) contains 16-bit register data, so you will be able to see the register data in next (F+1) frame, and one more frame is needed.

    Thanks&regards

    Dale

  • Hi Dale,

    Thank you for the response.

    I checked the 32-bit command data that is sent to ADS8681 and it is correct as per the datasheet.

    Please find the attached word document which got screenshots of timing diagrams for both Write and Read register of RANGE_SEL.

    Please check and let me know if anything is wrong.

    ADS8681.docx

    Thanks,

    Srinivas

  • Hi Srinivas,

    I will get back to you soon, thanks.

    Best regards

    Dale

  • Hi Srinivas,

    Your data in SDI timing to ADC is correct, can you please let me know what code you got on SDO in next frame after reading RANGE_SEL_REG register?

    Can you please let me know your test detail for 1.6V?

    • The conversion code for 1.6V DC input before writing internal register (default configuration after power up)
    • The conversion code for 1.6V DC input after writing internal RANGE_SEL_REG register (select 2.5VxVref range with 1001b for Range_SEL[3:0])
    • Is there any front-end RC filter on ADC input? your schematic will be very helpful.

    Thanks.

    Best regards

    Dale