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.

ADS124S08EVM: ADS124S08EVM Themocouple Inaccurate Raw Count

Part Number: ADS124S08EVM
Other Parts Discussed in Thread: ADS124S08

Hello, 

Ive attached a Type-K thermocouple to the AIN2, and AIN4 Terminals of the ADS124S08EVM after it has been modified to work with an external Linux processor. See below Specs. 

I shorted the JP1 on the ASD124S08 EVM  https://www.ti.com/tool/ADS124S08EVM so that it could be controlled with another microcontroller,. 

Microcontroller:  nrf5340-dk

RTOS: Zephyr

SDK : nrf SDK V1.8.0

SPI Clock: 5MHz

Ive followed the instructions within the Basic Guide to Thermocouple Measurements and the raw counts produced seem extremely high. I applied the formula within the guide to the raw counts and I am seeing an extremely high value for the Voltage recording., 

  

See below register configurations. 

Register Map: 

00> [00:00:00.551,300] <inf> ads124s08: ADS124S08 Detected with ID: 8
00> [00:00:00.552,062] <inf> ads124s08: REG: 0 , val 8
00> [00:00:00.552,124] <inf> ads124s08: REG: 1 , val 80
00> [00:00:00.552,185] <inf> ads124s08: REG: 2 , val 24
00> [00:00:00.552,276] <inf> ads124s08: REG: 3 , val 2
00> [00:00:00.552,337] <inf> ads124s08: REG: 4 , val 14
00> [00:00:00.552,429] <inf> ads124s08: REG: 5 , val 10
00> [00:00:00.552,490] <inf> ads124s08: REG: 6 , val 0
00> [00:00:00.552,581] <inf> ads124s08: REG: 7 , val ff
00> [00:00:00.552,642] <inf> ads124s08: REG: 8 , val 10
00> [00:00:00.552,734] <inf> ads124s08: REG: 9 , val 10
00> [00:00:00.552,795] <inf> ads124s08: REG: a , val 0
00> [00:00:00.552,856] <inf> ads124s08: REG: b , val 0
00> [00:00:00.552,947] <inf> ads124s08: REG: c , val 0
00> [00:00:00.553,009] <inf> ads124s08: REG: d , val 0
00> [00:00:00.553,070] <inf> ads124s08: REG: e , val 0
00> [00:00:00.553,161] <inf> ads124s08: REG: f , val 40
00> [00:00:00.553,222] <inf> ads124s08: REG: 10 , val 0
00> [00:00:00.553,283] <inf> ads124s08: REG: 11 , val 0

Output: (Time Stamp, Raw counts, samples, and converted voltages (applying formula 3 from the guide): 


00> [00:01:17.841,857] <inf> ads124s08: Raw: ff, ff, 96 , Sample: 16777110, Voltage 319mV
00> [00:01:17.908,721] <inf> ads124s08: Raw: ff, ff, 99 , Sample: 16777113, Voltage 319mV
00> [00:01:17.975,585] <inf> ads124s08: Raw: ff, ff, 9d , Sample: 16777117, Voltage 319mV
00> [00:01:18.042,449] <inf> ads124s08: Raw: ff, ff, 98 , Sample: 16777112, Voltage 319mV
00> [00:01:18.109,313] <inf> ads124s08: Raw: ff, ff, 99 , Sample: 16777113, Voltage 319mV
00> [00:01:18.176,177] <inf> ads124s08: Raw: ff, ff, 96 , Sample: 16777110, Voltage 319mV
00> [00:01:18.243,041] <inf> ads124s08: Raw: ff, ff, 96 , Sample: 16777110, Voltage 319mV
00> [00:01:18.309,906] <inf> ads124s08: Raw: ff, ff, 9a , Sample: 16777114, Voltage 319mV
00> [00:01:18.376,770] <inf> ads124s08: Raw: ff, ff, 98 , Sample: 16777112, Voltage 319mV
00> [00:01:18.443,634] <inf> ads124s08: Raw: ff, ff, 97 , Sample: 16777111, Voltage 319mV
00> [00:01:18.510,528] <inf> ads124s08: Raw: ff, ff, 9c , Sample: 16777116, Voltage 319mV
00> [00:01:18.577,392] <inf> ads124s08: Raw: ff, ff, 98 , Sample: 16777112, Voltage 319mV
00> [00:01:18.644,256] <inf> ads124s08: Raw: ff, ff, 98 , Sample: 16777112, Voltage 319mV

See below screenshot of Logic Analyzer when the RDATA command is being sent: 

See below Code for ADS124S08.c: 

#define DT_DRV_COMPAT ti_ads124s08
#include <init.h>
#include <sys/byteorder.h>
#include <sys/__assert.h>
#include <logging/log.h>

LOG_MODULE_REGISTER(ads124s08, CONFIG_SENSOR_LOG_LEVEL);
#include "ads124s08.h"

#include <devicetree.h>
#include <drivers/gpio.h>

#include <nrf.h>
#include <hal/nrf_gpio.h>

static const struct device *dev_start;
static const struct device *dev_reset;

static int ads124s08_reg_readout(const struct device *dev); 

// configure GPIO Pins for CS, Start and reset

static void init_gpio(void)   {

    int status;

    dev_reset = device_get_binding(ADS124S08_RESET_LABEL);
    if (dev_reset == NULL){ 
      LOG_ERR("dev_reset device_get_binding() failure.");
      return;
    }

    status = gpio_pin_configure(dev_reset, ADS124S08_RESET_PIN, GPIO_OUTPUT_ACTIVE); 
    if (status < 0){ 
      LOG_ERR("dev_reset gpio_pin_configure() failure.");
      return;
    }

	dev_start= device_get_binding(ADS124S08_START_LABEL);
    if (dev_start == NULL){ 
      LOG_ERR("dev_start device_get_binding() failure.");
      return;
    }

    status = gpio_pin_configure(dev_start, ADS124S08_START_PIN, GPIO_OUTPUT_ACTIVE); 
    if (status < 0){ 
      LOG_ERR("dev_start gpio_pin_configure() failure.");
      return;
    }

#ifndef CONFIG_ADS124S08_TRIGGER
	nrf_gpio_cfg_input(DRDY_PIN, NRF_GPIO_PIN_PULLUP); 
#endif 

}


static void ads124s08_set_start_pin(int STATE){ 
  gpio_pin_set(dev_start, ADS124S08_START_PIN, STATE);
}
static void ads124s08_set_reset_pin(int STATE){ 
  gpio_pin_set(dev_reset, ADS124S08_RESET_PIN, STATE);
}



/* 
	Write ADC Values to Sensors Val Stict 
*/

static int ads124s08_channel_get(const struct device *dev,
			      enum sensor_channel chan,
			      struct sensor_value *val)
{
	
	struct ads124s08_data *ads124s08 = dev->data; 

	val->pData = ads124s08->sample.bytes; 

	return 0; 

} 


/*
	Convert internal temperate readings

*/ 

static void convert_internal_temp(const struct device *dev, uint32_t samp){ 

	struct ads124s08_data *ads124s08 = dev->data;


	double scaleFactor = (double)((VREF) / (ADS124S08_PGA_FACTOR * 8388608));  
	double voltage = scaleFactor * (double)samp; 

	ads124s08->cjv = voltage; 

	ads124s08->tempCj =  (((voltage - 129) / 403 ))  + 25;


}

/*
	Convert internal temperate readings

*/ 

static void convert_themocouple_temp(const struct device *dev, uint32_t samp){ 
	struct ads124s08_data *ads124s08 = dev->data;

	double scaleFactor = (double)((VREF) / (ADS124S08_PGA_FACTOR * 32768));  
	double voltage = scaleFactor * (double)samp ; 
		
	ads124s08->chanV = voltage; 

}


/* 	
	Read data from ADC Channels
*/ 

static uint32_t ads124s08_read_data(const struct device *dev){ 

	struct ads124s08_data *ads124s08 = dev->data;

	int status; 
	uint32_t samp; 

	uint8_t sample[RDATA_CMD_READ_BACK_LEN]; 

	status = ads124s08->hw_tf->read_samp(dev,&sample[0]); //send RDATA Command

	if(status < 0){ 
		LOG_ERR("Error. asd124s08_read_data(). Unable to fetch sample" ); 
		return 1; 
	} 

	samp = (uint32_t)(sample[0] << 16 | sample[1] << 8 | sample[2]);

	// record internal temp on every other interval 
	if (ads124s08->internalTempSetBit > 0 ){ 

		convert_internal_temp(dev, samp); 

	}else{ 

		convert_themocouple_temp(dev, samp); 
	
#if !(MODE_CHANNEL_READ_ONLY)
		if (ads124s08->cjv >0){
		
			DEBUG_LOG("ChanV: %dmV,   Internal V:%dmV, CJT:%d C,  V + VCJ: %dmV ", ads124s08->chanV,ads124s08->cjv,ads124s08->tempCj , ads124s08->chanV  + ads124s08->cjv); 
		}
#else 
	DEBUG_LOG("Raw: %x, %x, %x , Sample: %d, Voltage %dmV ", sample[0],sample[1], sample[2], samp, ads124s08->chanV ); 
#endif 
	}


	return 0; 

}


/*

When measuring the internal temperature sensor, the analog inputs are disconnected from the ADC and the
output voltage of the temperature sensor is routed to the ADC for measurement using the selected PGA gain,
data rate, and voltage reference. If enabled, PGA gain must be limited to 4 for the temperature sensor
measurement to remain within the allowed absolute input voltage range of the PGA. As a result of the low device
junction-to-PCB thermal resistance (RθJB), the internal device temperature closely tracks the printed circuit board
(PCB) temperature.

*/ 

static int ads124s08_toggle_internal_temp_settings(const struct device *dev){ 
	struct ads124s08_data *ads124s08 = dev->data;
	static uint8_t ctrl; 
	static uint8_t status; 


	k_sleep(K_MSEC(5)); 

	// Write ref Reg  
	ads124s08->internalTempSetBit ^= 0x1A;  // measures internal temp every other interupt
	ctrl = 0x10 | ads124s08->internalTempSetBit;  
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_REF, ctrl);

	if (status < 0) {
		LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}


	status = ads124s08->hw_tf->read_reg(dev,ADS124S08_REG_SYS, &ctrl);

	if (status < 0) {
		LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}


	ctrl ^= 0x40;  //toggle the internal sensor reading

	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_SYS, ctrl);

	if (status < 0) {
		LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}

	status = ads124s08->hw_tf->read_reg(dev,ADS124S08_REG_PGA, &ctrl);

	if (status < 0) {
		LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}

	ctrl ^= 0x0A; // Enable PGA and set gain to 4 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_PGA, ctrl);

	if (status < 0) {
		LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}

	return 0;//ads124s08_reg_readout(dev); 

}


static int ads124s08_sample_fetch(const struct device *dev,
			       enum sensor_channel chan)
{

	struct ads124s08_data *ads124s08 = dev->data;
	uint32_t sample; 

#ifndef CONFIG_ADS124S08_TRIGGER

	ads124s08->drdyPinStatus =  nrf_gpio_pin_read(DRDY_PIN);

	if (ads124s08->drdyPinStatus == LOW){ 


		while (!nrf_gpio_pin_read(DRDY_PIN)){
			sample = ads124s08_read_data(dev); // read data from ADC
		}

		ads124s08->hw_tf->write_command(dev,ADS124S08_CMD_STOP ); 

		k_sleep(K_MSEC(5));

	#if !(MODE_CHANNEL_READ_ONLY)

		ads124s08_toggle_internal_temp_settings(dev); 
	#endif 
		k_sleep(K_MSEC(5));

		ads124s08->hw_tf->write_command(dev,ADS124S08_CMD_START ); 

		k_sleep(K_MSEC(5));
	}


#else 

	sample = ads124s08_read_data(dev); // read data from ADC

	k_sleep(K_MSEC(5)); 

	// ads124s08_set_internal_temp(dev); // switch to monitor internal temp

#endif 

	return 0; 
}

static const struct sensor_driver_api ads124s08_driver_api = {
#if CONFIG_ADS124S08_TRIGGER
	.trigger_set = ads124s08_trigger_set,
#endif
	.sample_fetch = ads124s08_sample_fetch,
	.channel_get = ads124s08_channel_get,
};



static int ads124s08_reg_readout(const struct device *dev){ 

	
	struct ads124s08_data *ads124s08 = dev->data; 

	uint8_t status; 

	static uint8_t value; 

	
	for ( int i =0; i < 18; i ++){ 

		status = ads124s08->hw_tf->read_reg(dev, i, &value); 

		if (status < 0){ 
			LOG_ERR("ads124s08_reg_readout. Unable to read reg: %x", i);

		}
		
		DEBUG_LOG("REG: %x , val %x", i, value); 
	}

}



static int ads124s08_reset(const struct device *dev){ 

#if ENABLE_SOFT_CONFIGS // software reset 

	struct ads124s08_data *ads124s08 = dev->data; 
	ctrl = ADS124S08_CMD_RESET;
	int status = ads124s08->hw_tf->write_command(dev, ctrl);
	if (status < 0){ 
		LOG_ERR("ads124s08_reset(). Unable to write reset command "); 
	}
#else // hardware reset 
	

  	ads124s08_set_reset_pin(HIGH); 
	k_sleep(K_MSEC(100)); 
	ads124s08_set_reset_pin(LOW);
	k_sleep(K_MSEC(100)); 
	ads124s08_set_reset_pin(HIGH);
	k_sleep(K_MSEC(100)); 
	
	  
#endif 
	return 0; 

}


static int ads124s08_wreg_config(const struct device *dev){ 

	struct ads124s08_data *ads124s08 = dev->data; 

	uint8_t ctrl; 
	int status; 

	// send wreg command to enable register writting 

	// write ID Reg -
	ctrl = 0x08; 
	status = ads124s08->hw_tf->write_reg(dev, ADS124S08_REG_ID,ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write ID Reg.\n");		
		return status;
	}

	// // write Status Reg 
	ctrl = 0x80; 
	status = ads124s08->hw_tf->write_reg(dev, ADS124S08_REG_STATUS,ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write ID Reg.\n");		
		return status;
	}
	
	// write MUX Reg set channel 2 as positive channel 4 as negative
	ctrl = 0x20 | 0x04; 
	status = ads124s08->hw_tf->write_reg(dev, ADS124S08_REG_INPMUX,ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write MUX Reg.\n");		
		return status;
	}

	// Write PGA Reg  (cannot exceed gain of 4 or bit reg of (0x02) for internal temp readings)
	ctrl = 0x00 | ADS124S08_PGA_IDX; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_PGA, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write PGA Reg.\n");		
		return status;
	}

	// Write data rate Reg  
	ctrl = 0x14 | SINGLE_SHOT_MODE_BIT; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_DATARATE, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write  data rate Reg.\n");		
		return status;
	}

	// Write ref Reg  
	ctrl = 0x10; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_REF, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write Ref Reg.\n");		
		return status;
	}

	// Write IDACMAG Reg  
	ctrl = 0x00; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_IDACMAG, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write IDACMAG Reg.\n");		
		return status;
	}
	
	// Write IDACMUX Reg  
	ctrl = 0xFF; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_IDACMUX, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write IDACMUX Reg.\n");		
		return status;
	}

	// Write ADS124S08_REG_SYS *4 bit samples, enable crc and send stat)
	ctrl = 0x10 ;// | 0x02 | 0x01; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_SYS, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write IDACMUX Reg.\n");		
		return status;
	}

	// Write ADS124S08_REG_VBIAS For Thermocouples (Vbias AIN4 for now)
	ctrl = 0x00 | 0x10; 
	status = ads124s08->hw_tf->write_reg(dev,ADS124S08_REG_VBIAS, ctrl);

	if (status < 0) {
    	LOG_ERR("ads124s08_wreg_config(): Failed to write IDACMUX Reg.\n");		
		return status;
	}




#ifdef CONFIG_ADS124S08_TRIGGER
	
	status = ads124s08_init_interrupt(dev);
	if (status < 0) {
		LOG_ERR("Failed to initialize interrupts.");
		return status;
	}

#endif
	return ads124s08_reg_readout(dev); 
}


static int ads124s08_init(const struct device *dev)
{
	struct ads124s08_data *ads124s08 = dev->data;
	const struct ads124s08_config *cfg = dev->config;
	int status;
	uint8_t id; 
	
	ads124s08->bus = device_get_binding(cfg->bus_name);
	if (!ads124s08->bus) {
		LOG_ERR("master not found: %s", cfg->bus_name);
		return -EINVAL;
	}

	cfg->bus_init(dev);

	init_gpio(); 

	//Reset Device 
	status = ads124s08_reset(dev);

	if (status < 0){ 

		LOG_ERR("ads124s08_init(). Unable to reset device"); 
	} 


	status = ads124s08->hw_tf->read_reg(dev, ADS124S08_REG_ID, &id); 

	if (status < 0)
	{ 
		LOG_ERR("ads124s08_init. Unable to read reg: %x", ADS124S08_REG_ID);

	}
	else if (id != ADS124S08_CHIP_ID )
	{
		DEBUG_LOG("Unknown device with ID %x Detected on SPI bus", id); 
	}
	else
	{ 

		DEBUG_LOG("ADS124S08 Detected with ID: %x",id); 
	}
	

#if(INTERNAL_TEMP_TEST)

	ads124s08_toggle_internal_temp_settings(dev);

#else

	//config production registers 
	status = ads124s08_wreg_config(dev); 

	if ( status < 0){ 

		LOG_ERR("ads124s08_init(). Unable to write config registers"); 

	}

#endif

#if (HW_START)

	// toggle start pin 
	ads124s08_set_start_pin(HIGH); 
	k_sleep(K_MSEC(10)); 
	ads124s08_set_start_pin(LOW); 
	k_sleep(K_MSEC(10)); 
	ads124s08_set_start_pin(HIGH); 
#else


	ads124s08_set_start_pin(LOW); 
	k_sleep(K_MSEC(10)); 
	ads124s08->hw_tf->write_command(dev,ADS124S08_CMD_START ); 
	k_sleep(K_MSEC(10)); 
	ads124s08->hw_tf->write_command(dev,ADS124S08_CMD_STOP ); 
	k_sleep(K_MSEC(10)); 
	ads124s08->hw_tf->write_command(dev,ADS124S08_CMD_START ); 


#endif 


	return 0;
}



#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
#warning "ADS124S08 driver enabled without any devices"
#endif
/*
 * Device creation macro, shared by ADS124S08_DEFINE_SPI() and
 */

#define ADS124S08_DEVICE_INIT(inst)					\
	DEVICE_DT_INST_DEFINE(inst,					\
			    ads124s08_init,				\
			    NULL,					\
			    &ads124s08_data_##inst,			\
			    &ads124s08_config_##inst,			\
			    POST_KERNEL,				\
			    CONFIG_SENSOR_INIT_PRIORITY,		\
			    &ads124s08_driver_api);

#define IS_LSM303AGR_DEV(inst) \
	DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), st_lsm303agr_accel)

#define DISC_PULL_UP(inst) \
	DT_INST_PROP(inst, disconnect_sdo_sa0_pull_up)

/*
 * Instantiation macros used when a device is on a SPI bus.
 */

#define ADS124S08_HAS_CS(inst) DT_INST_SPI_DEV_HAS_CS_GPIOS(inst)

#define ADS124S08_DATA_SPI_CS(inst)					\
	{ .cs_ctrl = {							\
		.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(inst),		\
		.gpio_dt_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(inst),	\
		},							\
	}

#define ADS124S08_DATA_SPI(inst)						\
	COND_CODE_1(ADS124S08_HAS_CS(inst),				\
		    (ADS124S08_DATA_SPI_CS(inst)),				\
		    ({}))

#define ADS124S08_SPI_CS_PTR(inst)						\
	COND_CODE_1(ADS124S08_HAS_CS(inst),				\
		    (&(ads124s08_data_##inst.cs_ctrl)),			\
		    (NULL))

#define ADS124S08_SPI_CS_LABEL(inst)					\
	COND_CODE_1(ADS124S08_HAS_CS(inst),				\
		    (DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)), (NULL))

#define ADS124S08_SPI_CFG(inst)						\
	(&(struct ads124s08_spi_cfg) {					\
		.spi_conf = {						\
			.frequency =					\
				DT_INST_PROP(inst, spi_max_frequency),	\
			.operation = (SPI_WORD_SET(8) |			\
				      SPI_OP_MODE_MASTER |		\
				      SPI_MODE_CPHA ),			\
			.slave = DT_INST_REG_ADDR(inst),		\
			.cs = ADS124S08_SPI_CS_PTR(inst),			\
		},							\
		.cs_gpios_label = ADS124S08_SPI_CS_LABEL(inst),		\
	})

#ifdef CONFIG_ADS124S08_TRIGGER
#define GPIO_DT_SPEC_INST_GET_BY_IDX_COND(id, prop, idx)		\
	COND_CODE_1(DT_INST_PROP_HAS_IDX(id, prop, idx),		\
		    (GPIO_DT_SPEC_INST_GET_BY_IDX(id, prop, idx)),	\
		    ({.port = NULL, .pin = 0, .dt_flags = 0}))

#else
#define ADS124S08_CFG_INT(inst)
#endif /* CONFIG_ADS124S08_TRIGGER */

#define ADS124S08_CONFIG_SPI(inst)						\
	{								\
		.bus_name = DT_INST_BUS_LABEL(inst),			\
		.bus_init = ads124s08_spi_init,				\
		.bus_cfg = { .spi_cfg = ADS124S08_SPI_CFG(inst)	}, \
		ADS124S08_CFG_INT(inst)					\
	}

#define ADS124S08_DEFINE_SPI(inst)						\
	static struct ads124s08_data ads124s08_data_##inst =			\
		ADS124S08_DATA_SPI(inst);					\
	static const struct ads124s08_config ads124s08_config_##inst =	\
		ADS124S08_CONFIG_SPI(inst);				\
	ADS124S08_DEVICE_INIT(inst)

/*
 * Main instantiation macro. Use of COND_CODE_1() selects the right
 * bus-specific macro at preprocessor time.
 */

#define ADS124S08_DEFINE(inst)						\
	COND_CODE_1(DT_INST_ON_BUS(inst, spi),				\
		    (ADS124S08_DEFINE_SPI(inst)),				\
		    )

DT_INST_FOREACH_STATUS_OKAY(ADS124S08_DEFINE)

Ads124S08.h


#ifndef ZEPHYR_DRIVERS_SENSOR_ADS124S08_ADS124S08_H_
#define ZEPHYR_DRIVERS_SENSOR_ADS124S08_ADS124S08_H_


#include <kernel.h>
#include <device.h>
#include <sys/util.h>
#include <stdint.h>
#include <drivers/gpio.h>
#include <drivers/sensor.h>
#include <string.h>


#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <drivers/spi.h>
#endif


#define DEBUG_MODE (1)
#if(DEBUG_MODE)
	#define DEBUG_LOG LOG_INF 
#else
	#define DEBUG_LOG(...)
#endif

#define HIGH (0xFF)
#define LOW  (0x00)


#define MULTI_CHANNEL_READ (0) // read through every channel 
#define ENABLE_SOFT_CONFIGS (0)
#define HW_START (0) // Start through toggling START signal rater than sending start command
#define INTERNAL_TEMP_TEST (0)
#define MODE_CHANNEL_READ_ONLY (1) // Debug mode for reading channels, no internal measurment reading
#define PGA_GAIN_4 
#define VREF (2.5)




// #define SINGLE_SHOT_MODE

#if defined(SINGLE_SHOT_MODE)
	#define SINGLE_SHOT_MODE_BIT (0x20)
#else 
	#define SINGLE_SHOT_MODE_BIT (0x00)
#endif
// GPIO Pins

// #define ADS124S08_CS_LABEL	      DT_GPIO_LABEL(DT_ALIAS(gpiocus0), gpios)
// #define ADS124S08_CS_PIN	      DT_GPIO_PIN(DT_ALIAS(gpiocus0), gpios)
#define ADS124S08_RESET_LABEL 	  DT_GPIO_LABEL(DT_ALIAS(gpiocus1), gpios)
#define ADS124S08_RESET_PIN	      DT_GPIO_PIN(DT_ALIAS(gpiocus1), gpios)
#define ADS124S08_START_LABEL     DT_GPIO_LABEL(DT_ALIAS(gpiocus2), gpios)
#define ADS124S08_START_PIN	      DT_GPIO_PIN(DT_ALIAS(gpiocus2), gpios)


// Interrupt Pins
#if DT_INST_PROP_HAS_IDX(0, irq_gpios, 1)
/* INT1 is configured */
#define ADS124S08_INT1_GPIOS_PIN		DT_INST_GPIO_PIN_BY_IDX(0, irq_gpios, 0)
#define ADS124S08_INT1_GPIOS_FLAGS		DT_INST_GPIO_FLAGS_BY_IDX(0, irq_gpios, 0)
#define ADS124S08_INT1_GPIO_DEV_NAME	DT_INST_GPIO_LABEL_BY_IDX(0, irq_gpios, 0)
#else

#define ADS124S08_INT1_GPIOS_PIN		DT_INST_GPIO_PIN(0, irq_gpios)
#define ADS124S08_INT1_GPIOS_FLAGS		DT_INST_GPIO_FLAGS(0, irq_gpios)
#define ADS124S08_INT1_GPIO_DEV_NAME	DT_INST_GPIO_LABEL(0, irq_gpios)

#endif


#define DRDY_PIN (43)

#define RES (double)((double)VREF/pow(2,23))

// Commands 

#define ADS124S08_CMD_NOP	0x00
#define ADS124S08_CMD_WAKEUP	0x02
#define ADS124S08_CMD_PWRDWN	0x04
#define ADS124S08_CMD_RESET	0x06
#define ADS124S08_CMD_START	0x08
#define ADS124S08_CMD_STOP	0x0A
#define ADS124S08_CMD_SYOCAL	0x16
#define ADS124S08_CMD_SYGCAL	0x17
#define ADS124S08_CMD_SFOCAL	0x19
#define ADS124S08_CMD_RDATA	0x12
#define ADS124S08_CMD_RREG	0x20
#define ADS124S08_CMD_WREG	0x40

#define RDATA_CMD_READ_BACK_LEN (3)

// Registers 

#define ADS124S08_REG_ID 0x00
#define ADS124S08_REG_STATUS 0x01
#define ADS124S08_REG_INPMUX 0x02
#define ADS124S08_REG_PGA 0x03
#define ADS124S08_REG_DATARATE 0x04
#define ADS124S08_REG_REF 0x05
#define ADS124S08_REG_IDACMAG 0x06
#define ADS124S08_REG_IDACMUX 0x07
#define ADS124S08_REG_VBIAS 0x08
#define ADS124S08_REG_SYS 0x09
#define ADS124S08_REG_OFCAL0 0x0A
#define ADS124S08_REG_OFCAL1 0x0B
#define ADS124S08_REG_OFCAL2 0x0C
#define ADS124S08_REG_FSCAL0 0x0D
#define ADS124S08_REG_FSCAL1 0x0E
#define ADS124S08_REG_FSCAL2 0x0F
#define ADS124S08_REG_GPIODAT 0x10
#define ADS124S08_REG_GPIOCON 0x11


/* ADS124S0x common channels */
#define ADS124S08_AIN0		0x00
#define ADS124S08_AIN1		0x01
#define ADS124S08_AIN2		0x02
#define ADS124S08_AIN3		0x03
#define ADS124S08_AIN4		0x04
#define ADS124S08_AIN5		0x05
#define ADS124S08_AINCOM	0x0c
#define ADS124S08_AIN6		0x06
#define ADS124S08_AIN7		0x07
#define ADS124S08_AIN8		0x08
#define ADS124S08_AIN9		0x09
#define ADS124S08_AIN10		0x0a
#define ADS124S08_AIN11		0x0b
#define ADS124S08_MAX_CHANNELS	12

#define ADS124S08_POS_MUX_SHIFT	0x04
#define ADS124S08_INT_REF		0x09

#define ADS124S08_START_REG_MASK	0x1f
#define ADS124S08_NUM_BYTES_MASK	0x1f

#define ADS124S08_START_CONV	0x01
#define ADS124S08_STOP_CONV	0x00
#define ADS124S08_CHIP_ID 0x08 

#if defined(PGA_GAIN_1)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_1
	#define ADS124S08_PGA_FACTOR	1
#elif defined(PGA_GAIN_2)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_2
	#define ADS124S08_PGA_FACTOR	2
#elif defined(PGA_GAIN_4)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_4
	#define ADS124S08_PGA_FACTOR	4
#elif defined(PGA_GAIN_8)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_8
	#define ADS124S08_PGA_FACTOR	8
#elif defined(PGA_GAIN_16)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_16
	#define ADS124S08_PGA_FACTOR	16
#elif defined(PGA_GAIN_32)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_32
	#define ADS124S08_PGA_FACTOR	32
#elif defined(PGA_GAIN_64)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_64
	#define ADS124S08_PGA_FACTOR	64
#elif defined(PGA_GAIN_128)
	#define ADS124S08_PGA_IDX		ADS_PGA_GAIN_128
	#define ADS124S08_PGA_FACTOR	128
#endif


#define ADS_PGA_GAIN_1 0x00 
#define ADS_PGA_GAIN_2 0x01 
#define ADS_PGA_GAIN_4 0x02 
#define ADS_PGA_GAIN_8 0x03 
#define ADS_PGA_GAIN_16 0x04 
#define ADS_PGA_GAIN_32 0x05
#define ADS_PGA_GAIN_64 0x06
#define ADS_PGA_GAIN_128 0x07




#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
struct ads124s08_spi_cfg {
	struct spi_config spi_conf;
	const char *cs_gpios_label;
};
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */

union ads124s08_bus_cfg {

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
	const struct ads124s08_spi_cfg *spi_cfg;
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
};

struct ads124s08_config {
	const char *bus_name;
	int (*bus_init)(const struct device *dev);
	const union ads124s08_bus_cfg bus_cfg;
};

struct ads124s08_transfer_function {
	int (*read_reg)(const struct device *dev, uint8_t reg_addr,
			uint8_t *value);
	int (*write_reg)(const struct device *dev, uint8_t reg_addr,
			 uint8_t value);
	int (*read_samp)(const struct device *dev, uint8_t *value);
	int (*write_command)(const struct device *dev, uint8_t value);

};


union asd124s08_sample{ 
	uint8_t bytes[3];  
	uint32_t raw[1]; 
}; 

struct ads124s08_data {
	const struct device *bus;
	const struct ads124s08_transfer_function *hw_tf;
	union asd124s08_sample sample;
	uint8_t tempRecordings[18]; // 3 bytes per sample * 6 channels = 18 bytes
	double cjv; 
	double chanV; 
	double tempCj; 
	double tempTC; 
	uint8_t internalTempSetBit; 
	uint32_t drdyPinStatus; 

#ifdef CONFIG_ADS124S08_TRIGGER
	const struct device *dev;
	const struct device *gpio_int1; 
	struct gpio_callback gpio_int1_cb;
	
	sensor_trigger_handler_t handler_drdy;
	atomic_t trig_flags;
	enum sensor_channel chan_drdy;

#if defined(CONFIG_ADS124S08_TRIGGER_OWN_THREAD)
	K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_ADS124S08_THREAD_STACK_SIZE);
	struct k_thread thread;
	struct k_sem gpio_sem;
#elif defined(CONFIG_ADS124S08_TRIGGER_GLOBAL_THREAD)
	struct k_work work;
#endif

#endif /* CONFIG_ADS124S08_TRIGGER */

#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
	struct spi_cs_control cs_ctrl;
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
};


#ifdef CONFIG_ADS124S08_TRIGGER
int ads124s08_trigger_set(const struct device *dev,
		       const struct sensor_trigger *trig,
		       sensor_trigger_handler_t handler);

int ads124s08_init_interrupt(const struct device *dev);

#endif

int ads124s08_spi_init(const struct device *dev);

#endif 

Any help would be appreciated. 

Thank you, 

Matt 

  • Hi Matt,

    You need to be careful when taking the 24-bit output code of the ADS124S08 and converting to decimal.  The output of the ADS124S08 is binary 2's complement where the most significant bit determines the sign.  If the bit is a '1' then the value is negative.  So 0xFFFF96 has a most significant bit as a '1' so this number is actually a negative value.

    The positive range is 0x000000 to 0x7FFFFF where 0x7FFFFF is the maximum positive value or 8388607 decimal.  The negative range has the maximum negative range at 0x800000 and 0xFFFFFF is actually -1 decimal.  So when converting a 24-bit ADC output code value to a signed 32-bit value you need to properly sign-extend the value to properly preserve the sign of the number.

    Best regards,

    Bob B

  • Hi Bob, 

    Thanks for your reply. 

    I implement the following function to sign-extend the raw counts: 

    uint32_t sign_extend_24_32(uint32_t x) {
        const int bits = 24;
        uint32_t m = 1u << (bits - 1);
        return (x ^ m) - m;
    }
    
    
    uint32_t transform(uint8_t *sample) {
    	uint32_t val,val32; 
    	if (sample[0] & 0x80)
    		val = 0xff;
    
    	val = sample[0] << 16 | sample[1] <<8 | sample[2]; 
    
    	val32 = sign_extend_24_32(val); 
    
    	return val32; 
    }

    I am still getting the same values as before: 

    00> [00:00:00.551,300] <inf> ads124s08: ADS124S08 Detected with ID: 8
    00> [00:00:00.552,032] <inf> ads124s08: REG: 0 , val 8
    00> [00:00:00.552,124] <inf> ads124s08: REG: 1 , val 80
    00> [00:00:00.552,185] <inf> ads124s08: REG: 2 , val 24
    00> [00:00:00.552,276] <inf> ads124s08: REG: 3 , val 3
    00> [00:00:00.552,337] <inf> ads124s08: REG: 4 , val 14
    00> [00:00:00.552,398] <inf> ads124s08: REG: 5 , val 15
    00> [00:00:00.552,490] <inf> ads124s08: REG: 6 , val 0
    00> [00:00:00.552,551] <inf> ads124s08: REG: 7 , val ff
    00> [00:00:00.552,642] <inf> ads124s08: REG: 8 , val 10
    00> [00:00:00.552,703] <inf> ads124s08: REG: 9 , val 10
    00> [00:00:00.552,795] <inf> ads124s08: REG: a , val 0
    00> [00:00:00.552,856] <inf> ads124s08: REG: b , val 0
    00> [00:00:00.552,917] <inf> ads124s08: REG: c , val 0
    00> [00:00:00.553,009] <inf> ads124s08: REG: d , val 0



    00> [00:00:15.508,514] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.575,347] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.642,181] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.709,014] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.775,848] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.842,681] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.909,515] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:15.976,348] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:16.043,182] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV
    00> [00:00:16.110,015] <inf> ads124s08: Raw: 7f, ff, ff , Sample: 8388607, Voltage 159mV

    Any other suggestions? 

    Thanks, 

    Matt

  • Hi Matt,

    The ADC value returned is a signed value as binary 2's complement and you are attempting to manipulate using unsigned numbers.  I personally would keep things as signed.  There are many ways of doing sign-extension.  One way is to take the original value captured and store as a signed integer.  Shift the 24-bit value left (<< 8) and then shift back right (>>8).  If the value is negative the shifting will automatically adjust the signed value to the correct decimal signed equivalent.

    There are other methods that can be used as well such as checking the most significant bit and then if a '1' add 0xFF000000 to the original number.  Again keep the value as a signed 32-bit integer.

    Best regards,

    Bob B

  • Hi Bob, 

    I tried the following method: 

    int32_t transform(uint8_t *sample) {
    
    	int32_t val32; 
    
    	val32 = (int8_t)sample[0]; 
    	val32 = (val32 << 8) | (int8_t)sample[1]; 
    	val32 = (val32 << 8) | (int8_t)sample[2]; 
    
    
    	val32 = val32 & 0x800000 ?  0xFF000000  | val32 : val32;
    
    	return val32 ; 
    }
    

    It produced the following result (note the logger cant display floating point values so they actually decimals below zero): 

    00> [00:00:00.736,999] <inf> ads124s08: ADS124S08 Detected with ID: 8
    00> [00:00:00.737,762] <inf> ads124s08: REG: 0 , val 8
    00> [00:00:00.737,854] <inf> ads124s08: REG: 1 , val 80
    00> [00:00:00.737,915] <inf> ads124s08: REG: 2 , val 24
    00> [00:00:00.737,976] <inf> ads124s08: REG: 3 , val 3
    00> [00:00:00.738,067] <inf> ads124s08: REG: 4 , val 14
    00> [00:00:00.738,128] <inf> ads124s08: REG: 5 , val 15
    00> [00:00:00.738,220] <inf> ads124s08: REG: 6 , val 0
    00> [00:00:00.738,281] <inf> ads124s08: REG: 7 , val ff
    00> [00:00:00.738,372] <inf> ads124s08: REG: 8 , val 10
    00> [00:00:00.738,433] <inf> ads124s08: REG: 9 , val 10
    00> [00:00:00.738,525] <inf> ads124s08: REG: a , val 0
    00> [00:00:00.738,586] <inf> ads124s08: REG: b , val 0
    00> [00:00:00.738,647] <inf> ads124s08: REG: c , val 0
    00> [00:00:00.738,739] <inf> ads124s08: REG: d , val 0


    00> [00:00:00.738,80[00:00:04.838,012] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:04.904,876] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:04.971,740] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.038,604] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.105,468] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.172,332] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.239,196] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.306,030] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.372,863] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV
    00> [00:00:05.439,697] <inf> ads124s08: Raw: 7f, ff, ff , Sample: -1, Voltage 0mV

    The raw values:  7F, FF, FF still seem off to me. Do you see anything wrong with the register configurations or anything I am missing regarding reading the  Thermocouple voltages? 

    Thanks, 

    Matt 

  • Hi Matt,

    0x7FFFF is positive full-scale.  Based on the register settings you have selected REF1 as the reference inputs.  REF1 is an IDAC derived reference for RTDs and is set to 0V.  Try selecting the internal reference instead.  Try changing register 5 to 0x1A.

    Best regards,

    Bob B

  • Hi Bob, 

    I made the change you suggested and I am getting some very small negative values as a result of the ff,ff, 51.. raw counts. Doesnt quite look right: 

    00> [00:00:02.769,744] <inf> ads124s08: REG: 0 , val 8
    00> [00:00:02.769,805] <inf> ads124s08: REG: 1 , val 80
    00> [00:00:02.769,866] <inf> ads124s08: REG: 2 , val 24
    00> [00:00:02.769,958] <inf> ads124s08: REG: 3 , val 3
    00> [00:00:02.770,019] <inf> ads124s08: REG: 4 , val 14
    00> [00:00:02.770,111] <inf> ads124s08: REG: 5 , val 1a
    00> [00:00:02.770,172] <inf> ads124s08: REG: 6 , val 0
    00> [00:00:02.770,263] <inf> ads124s08: REG: 7 , val ff
    00> [00:00:02.770,324] <inf> ads124s08: REG: 8 , val 10
    00> [00:00:02.770,416] <inf> ads124s08: REG: 9 , val 10
    00> [00:00:02.770,477] <inf> ads124s08: REG: a , val 0
    00> [00:00:02.770,538] <inf> ads124s08: REG: b , val 0
    00> [00:00:02.770,629] <inf> ads124s08: REG: c , val 0
    00> [00:00:02.770,690] <inf> ads124s08: REG: d , val 0


    00> [00:00:02.770,75[00:00:07.845,092] <inf> ads124s08: Raw: ff, ff, 54 , Sample: -172, Voltage 0mV
    00> [00:00:07.911,956] <inf> ads124s08: Raw: ff, ff, 51 , Sample: -175, Voltage 0mV
    00> [00:00:07.978,790] <inf> ads124s08: Raw: ff, ff, 53 , Sample: -173, Voltage 0mV
    00> [00:00:08.045,623] <inf> ads124s08: Raw: ff, ff, 4c , Sample: -180, Voltage 0mV
    00> [00:00:08.112,457] <inf> ads124s08: Raw: ff, ff, 50 , Sample: -176, Voltage 0mV
    00> [00:00:08.179,290] <inf> ads124s08: Raw: ff, ff, 50 , Sample: -176, Voltage 0mV
    00> [00:00:08.246,124] <inf> ads124s08: Raw: ff, ff, 50 , Sample: -176, Voltage 0mV
    00> [00:00:08.312,957] <inf> ads124s08: Raw: ff, ff, 50 , Sample: -176, Voltage 0mV

    Ant other suggestions? 

    Thanks for your help, 

    Matt 

  • Hi Matt,

    I'm not sure what you are expecting as a result.  The K thermocouple output voltage table is based on a specific cold-junction temperature.  When the thermocouple connects to the PCB there is another thermocouple created.  So the cold-junction temperature must be converted to a voltage which is then added to the voltage measured by the ADC of the thermocouple itself.

    I would suggest reviewing the information in A Basic Guide to Thermocouple Measurements.  This guide describes how a thermocouple works and details and circuits on how to correctly measure the temperature.

    Best regards,

    Bob B

  • Hi Bob, 

    Ive read through that guide. Should have been a bit more clear as to my indented results. 

    So I am using the ADS124S08 EVM with AIN2/AIN4 as the inputs to a type K Thermocouple it is sitting on my desk at approx. room temperature (25 Degrees C). 

    According to the guide to convert the voltages to degrees Celsius I must do the following: 

    1. Collect the channel voltage, raw counts of inputs AIN2/AIN4 (24 bit 2's complement signed ints), convert to voltage

    2. Collect CJC voltage( I am using the internal temperature of the ADS124S08 for this operation, I have confirmed that it is measuring approx 25 degrees C) 

    3. Get the actual voltage by adding the CJC voltage to the channel voltage 

    4. Look up resulting voltage in Type k conversion table  

    When I perform these steps, I am seeing approx 0.32 V ~ 8 degrees C according to the table. 

    For the CJC calculation. I am performing the following: 

    Vcjc = (2.5/(4 * 2^23) ) * raw counts = ~ 320mV

    Temp_Cjc = ( (Vcjc- 129) / 403uV )) + 25  = ~ 25.4 C 

    As mentioned above, the Channel Voltage was calculated as shown below :

    Vchan = (2.5/ (4 * 2^15)) * raw counts = ~ -0.0015 V, this is where it seems off to me. 

    Let me know if you see anything that looks incorrect. 

    Thanks, 

    Matt 

     

  • Hi Matt,

    I'm not sure where you got your Vchan equation.  If the gain is 4, then the ADC output voltage would be +/- Vref / (Gain*2^24) or 2.5V / (4*2^23) per LSB (code).  If the returned code is -175, then the voltage would be about -13uV.

    Interpolating 25.4 deg C from the K table the voltage would be about 1.0082mV plus the measured thermocouple voltage of -13uV which would be about 995.16uV or about 24.9 deg C from the table.

    Best regards,

    Bob B

  • Hi Bob, 

    I see my mistake. So I was suppose to reverse look up the voltage measured by the internal temperature sensor into the k-table to get the Vcjc and then add that to the measured voltage . That is why the scale seemed off. 

    Thank you for your help. 

    Matt