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.

ADS8668: not get written value to a register

Part Number: ADS8668

code:

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define WHO_AM_I_REG   0x75
#define WHO_AM_I_EXPECTED_VAL 0x91
#define ACCEL_CONFIG_REG  0x28
#define GYRO_CONFIG_REG  0x27
#define USING_WRITE_FUNC 0

static const char *device = "/dev/spidev0.0";
static uint8_t mode = SPI_MODE_1;
static uint8_t bits = 8;
static uint32_t spi_speed_hz = 1000;
static int transfer_len = 4 ;
static int fd;

/*************************************************************************//**
 * Initializes the SPI functionality
 *****************************************************************************/
int payload_board_spi_init(void)
{
 int ret = 0;
 
 fd = open(device, O_RDWR);
 if (fd < 0){
  perror("can't open device");
  return -1;
 }

 //spi mode
 //mode = SPI_MODE_1;
 ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
 if (ret < 0){
  perror("can't set spi mode");
  return ret;
 }

 //bits per word
 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
 if (ret  < 0) {
  perror("SPI_IOC_MESSAGE");
  return ret ;
 }

 //max speed hz
 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed_hz);
 if (ret < 0){
  perror("can't set max speed hz");
  return ret;
 }

 return 0;

 // There are other IOCTL's which are not relevant to this 
 // specific slave device.
}

/*************************************************************************//**
 * Reads one byte from the SPI slave device register.
 *
 * @param reg_addr is the address of the register to be read from.
 * @param read_buffer is the pointer to the variable where the read data byte
 * will be stored.
 *
 * @return 0 if success. else -1.
 *****************************************************************************/
static int icg_20660_reg_read(uint8_t reg_addr, uint8_t* read_buffer)
{
 struct spi_ioc_transfer tr;
 int ret;
 uint8_t wr_data[2] = {0, 0};
 uint8_t rd_data[2] = {0, 0};

 memset(&tr, 0, sizeof(tr)); //clear any invalid data. This is required.
 tr.tx_buf = (unsigned long)wr_data;
 tr.rx_buf = (unsigned long)rd_data;
 tr.len = transfer_len, //one full read/write cycle consists of 16 bits data transfer.

 //set Bit7 to tell slave device that we are reading.
 wr_data[0] = (reg_addr|0x80);

 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
 if (ret < 1){
  perror("[PAYLOAD IMU] can't send spi message");
  return -1;
 }else{
  // we have read 2 bytes of data. But first byte is junk.
  read_buffer[0] = rd_data[1];
  return 0;
 }
}

/*************************************************************************//**
 * Write one byte to the SPI slave device's register.
 *
 * @param reg_addr is the address of the register to be written to.
 * @param write_data is the 8 bit data to be written.
 *
 * @return 0 if success. else -1.
 *****************************************************************************/
int icg_20660_reg_write(uint8_t reg_addr, uint8_t write_data)
{
 struct spi_ioc_transfer tr;
 int ret;
 uint8_t wr_data[4] = {0};
 uint8_t rd_data[4] = {0};

 memset(&tr, 0, sizeof(tr)); //clear any invalid data. This is required.
 tr.tx_buf = (unsigned long)wr_data;
 tr.rx_buf = (unsigned long)rd_data;
 tr.len = transfer_len, //one full cycle consists of 16 bits data transfer.

 //reset Bit7 to tell slave device that we are writting.
 wr_data[0] = reg_addr;
 wr_data[1] = write_data;

 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
printf("\nwrite buff: %X %X %X %X \n",wr_data[0],wr_data[1],wr_data[2],wr_data[3]);
 
printf("read buff : %X %X %X %X \n",rd_data[0],rd_data[1],rd_data[2],rd_data[3]);
if (ret < 1){
  perror("[ERROR][PAYLOAD IMU] can't send spi message");
  return -1;
 }else{
  return 0;
 }
}

/*************************************************************************//**
 * starts the payload board SPI interface test.
 *
 * @param response_buffer is the pointer to the buffer where the TLV 
 * response from the test function will be stored.
 *
 * @return the length of the received TLV string
 *****************************************************************************/
int cmd_pld_imu_spi_test(char* response_buffer)
{
 uint8_t val_read = 0;
 int ret;
 char* pass_string = "04000300140000010004PASS\r\n";
 char* fail_string = "04000300320000010004FAIL0000020008buserror\r\n";

 ret = icg_20660_reg_read(WHO_AM_I_REG, &val_read);
 if(ret<0){
  strcpy(response_buffer, fail_string);
  printf("[ERROR][PAYLOAD IMU] read error\n");
  return strlen(response_buffer);
 }
 
 if(val_read == WHO_AM_I_EXPECTED_VAL){
  strcpy(response_buffer, pass_string);
  return strlen(response_buffer);
 }else{
  strcpy(response_buffer, fail_string);
  printf("[ERROR][PAYLOAD IMU] unexpected who_am_i value: 0x%x\n", val_read);
  return strlen(response_buffer);
 }

}

int main(void)
{
printf("\nStart\n");
int ret;
ret = payload_board_spi_init();
printf("\nret = %d",ret);

int i =10;
while(i>0)
{
ret = icg_20660_reg_write(0b11,0xff);
printf("\nret = %d",ret);
sleep(1);
ret = icg_20660_reg_write(0b11,0xa5);
printf("\nret = %d",ret);
i--;
}
close(fd);
}

 

timing diagram 

problem:

On testing ADS8668 using the above code, I got an unexpected behaviour that the value written to the 0x2 register is not getting after the 16th clock. here I'm using spi mode 1 but the data shifted in the falling edge of the 16th clock instead of the leading edge of 17 the clock. i thought the problem occurs. please help me to avoid unexpected result

  • Hi Bibin,

    Just want to confirm, you tried to program 0x02 channel power down register and also you tried to read the register data back but you did not find the data on the SDI after the 16th clock, please correct me if my understanding is incorrect.

    In the main loop, you are sending the following commands to the ADC:

    Command 1:  0000 0011 1111 1111          ----> This command is writing 0xFF data to the 0x01 program register, and it's not a command to program 0x02 register.

    Command 2:  0000 0011 1010 0101        ----> This command is writing 0xA5 data to the 0x01 program register, not 0x02 register, and also this is not a register reading command.

    Also, the SPI configuration (CPOL = 0 and CPHA = 1) should be used. See more details in the E2E post:  ADS8688 SPI Clock

    Your image is very blurry and it's hard to see. Can you please provide clear and closer timing screenshots for both commands?

    Best regards,

    Dale

  • Hi Dale Li,

    my mistake's, it's 0x01 register (AUTO_SEQ_EN).

    according to the datasheet, the written value will be available in the SDI line after 16 the clock trailing edge.

    but the data sampling is not working correctly because if CPHA = 1 then the data will be shifted out in leading-edge and data will be sampled at the trailing edge of the clock. 

    the original image is :

    drive.google.com/.../view

  • Hi Bibin,

    The timing of ADS8668 is not a standard SPI timing:

    • For the SDI from your host controller to the ADC, the data on the SDI line are read/latched by the ADC at every falling edge of the SCLK.
    • For the SDO from the ADC to your host controller, the MSB of the conversion data is output on the SDO line at the 16th falling edge of the SCLK, your host controller can read the data on the subsequent (17th) falling edge of the SCLK signal. For 16bits of output data, the LSB can be read on the 32nd falling edge of the SCLK signal. Please see the SPI timing for ADS8668 below.

    The SPI configuration (CPOL = 0 and CPHA = 1) is required because your host controller can sample the data at every falling edge of SCLK so that you can get correct conversion result.

    I can not visit Google drive, however I have known you concern and explained the timing to you. Let me know if you have any other questions about ADS8668.

    Thanks&regards,

    Dale