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.

ADS1248 design for PT1000 and STM32 - Schematic & Software

Other Parts Discussed in Thread: ADS1248

Dear All,

since I got some requests for help about using ADS1248 with PT1000, and we have used successfully, here I am posting:

  • schematic example
  • how to connect with STM32
  • software example

This all for the benefit of people who would like to start projects using the ADS1248 for PT1000 (PT100) interface.

Regards

ADS1248.pdf

STM32.pdf

#include "def.h"
#include "adc.h"


static void setSpi1Clock(void)
{
	GPIOB->BSRR = 1 << 13;		// PB13
}

static void clrSpi1Clock(void)
{
	GPIOB->BRR = 1 << 13;		// PB13
}

static void setSpi1Mosi(void)
{
	GPIOB->BSRR = 1 << 15;
	//PB15
}

static void clrSpi1Mosi(void)
{
	GPIOB->BRR = 1 << 15;
	//PB15
}

static bool getSpi1Miso(u8 chan)
{
	if (chan) {
		return (GPIOB->IDR & (1 << 11)) != 0;
	} else {
		return (GPIOB->IDR & (1 << 14)) != 0;
	}	
}

// chip select 
static void assertCs(u8 chan)
{
	if (chan) {
		GPIOB->BRR = 1 << 10;
		//PB10
	} else {
		GPIOB->BRR = 1 << 12;
		//PB12
	}
}

// chip select per compensazione temperatura
static void releaseCs(u8 chan)
{
	if (chan) {
		GPIOB->BSRR = 1 << 10;
		//PB10
	} else {
		GPIOB->BSRR = 1 << 12;
		//PB12
	}
}

static void assertReset(void)
{
	GPIOC->BRR = 1 << 3;	// PC3
}

static void releaseReset(void)
{
	GPIOC->BSRR = 1 << 3;
}

static void assertStart(u8 chan)
{
	if (chan) {
		GPIOC->BSRR = 1 << 13;
		//PC13
	} else {
		GPIOC->BSRR = 1 << 12;
		//PC12
	}
}

static void releaseStart(u8 chan)
{
	if (chan) {
		GPIOC->BRR = 1 << 13;
		//PC13
	} else {
		GPIOC->BRR = 1 << 12;
		//PC12
	}
}

// nota : shiftare 0xff = nop durante fase in cui si vuole lettura !!
static u8 spiAdcSendByte(u8 ch, u8 val)
{
	int i;
	u8 mask = 0x80;
	int ret = 0;
	
	for (i = 0; i < 8; i++) {
		delayFix();
		if (val & mask) {
			setSpi1Mosi();
		} else {
			clrSpi1Mosi();
		}
		delayFix();
		setSpi1Clock();
		delayFix();
		ret <<= 1;
		ret |= getSpi1Miso(ch);
		clrSpi1Clock();
		mask >>= 1;
		delayFix();
	}
	return ret;
}

static bool getDRDYConversionComplete(u8 chan)
{
	if (chan) {
		return (GPIOC->IDR & (1 << 1)) == 0;		// PC1
	} else {
		return (GPIOC->IDR & (1 << 0)) == 0;		// PC0
	}	
}

static void AdcSendSync(u8 chan)
{
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, ADS1248_CMD_SYNC);
	spiAdcSendByte(chan, ADS1248_CMD_SYNC); // Send two bytes identical
	delayFix();
	releaseCs(chan);
}

static void AdcSendOneByteCommand(u8 chan, u8 cmd)
{
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, cmd);
	delayFix();
	releaseCs(chan);
}

static void AdcSendSelfOcal(u8 chan)
{
	AdcSendOneByteCommand(chan, ADS1248_CMD_SELFOCAL);
}

// 'quanti' � riportato in formato 'umano' 1 = 1 registro, ecc...
// quanti compreso tra 1 e 16 al max
static void AdcWriteReg(u8 chan, u8 add, u8 *data, u8 quanti)
{
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, ADS1248_CMD_WREG | add);
	spiAdcSendByte(chan, quanti-1);
	while (quanti--) {
		spiAdcSendByte(chan, *data++);
	}
	releaseCs(chan);
}

static void AdcReadReg(u8 chan, u8 add, u8 *data, u8 quanti)
{
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, ADS1248_CMD_RREG | add);
	spiAdcSendByte(chan, quanti-1);
	while (quanti--) {
		*data++ = spiAdcSendByte(chan, ADS1248_CMD_NOP);	// Attention -> NOP (0xff) required!
	}
	releaseCs(chan);
}

// vale solo se DRDY conversion complete
static u32 AdcReadConversion(u8 chan)
{
	u32 value;
	
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, ADS1248_CMD_RDATA);
	value =  spiAdcSendByte(chan, ADS1248_CMD_NOP); // Attention -> NOP (0xff) required!
	value <<= 8;
	value |= spiAdcSendByte(chan, ADS1248_CMD_NOP); // Attention -> NOP (0xff) required!
	value <<= 8;
	value |= spiAdcSendByte(chan, ADS1248_CMD_NOP);	// Attention -> NOP (0xff) required!
	releaseCs(chan);
	return value;
}

static void AdcStopContinuousRead(u8 chan)
{
	assertCs(chan);
	delayFix();
	spiAdcSendByte(chan, ADS1248_CMD_SDATAC);
	releaseCs(chan);
}

static void ConfigureTCInputMux(u8 chan, u8 tcIndex)
{
	// chan 0..1
	// index 0..3
	
	u8 tmp = (tcIndex << 3) | 7;			// ain7 neg channel
	AdcWriteReg(chan, ADS1248_MUX0_REGISTER, &tmp, 1);
	switch (tcIndex) {
	case 0 :
		tmp = 0xf0 | 0x08;		//da IOUT1 	(IDAC2 - IDAC1 disconnected)
		break;
	case 1 :
		tmp = 0xf0 | 0x09;		//da IOUT2 	(IDAC2 - IDAC1 disconnected)
		break;
	case 2 :
		tmp = 0xf0 | 0x04;		//da AIN4 	(IDAC2 - IDAC1 disconnected)
		break;
	case 3 :
		tmp = 0xf0 | 0x05;		//da AIN5 	(IDAC2 - IDAC1 disconnected)
		break;
	}

	AdcWriteReg(chan, ADS1248_IDAC1_REGISTER, &tmp, 1);
}

void thermoThread(void)
{
	static embtime_t tmCold;
	static embtime_t tm;
	static u8 state = THERMOTHREAD_STATE_SETUP_START;
	static u8 currTcIndex = 0;
	static u32 val_ads1 = 0;
	static u32 val_ads2 = 0;
	u8 tmp;
		
	if (time_fired(tmCold)) {
		tmCold = time_ms(100);
		// Cold-Junction temperature updated every 100mS, not always
		temperatureBase = getTemperatureBase();
	}
	
	switch (state) {
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_START:
		// maybe we will do something here in the future...
		state = THERMOTHREAD_STATE_SETUP_HARDWARE_INIT;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_HARDWARE_INIT:
		
		clrSpi1Clock();
		assertReset();	//Put Chip in ResetMode (no operations)
		releaseReset(); //Release Reset Pin (start chip)

		releaseCs(SPI_ADS1248_ONE);
		releaseCs(SPI_ADS1248_TWO);
	
		assertStart(SPI_ADS1248_ONE);	// start pin must be asserted during ADC configuration!
		assertStart(SPI_ADS1248_TWO); // start pin must be asserted during ADC configuration!
		
		tm = time_ms(10);		// 4mS minimum
		state = THERMOTHREAD_STATE_SETUP_RESET_ADS;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_RESET_ADS :
		
		if (time_fired(tm)) {
			spiAdcSendByte(SPI_ADS1248_ONE, ADS1248_CMD_RESET);
			spiAdcSendByte(SPI_ADS1248_TWO, ADS1248_CMD_RESET);

			tm = time_ms(5);		// post reset time (0,6mS minimum)
			state = THERMOTHREAD_STATE_SETUP_STOP_CONTINUOUS_MODE;
		}
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_STOP_CONTINUOUS_MODE :
		
		if ((getDRDYConversionComplete(0) == SPI_ADS1248_ONE) || 
				(getDRDYConversionComplete(1) == SPI_ADS1248_TWO)) {
			break;
		}
		AdcStopContinuousRead(SPI_ADS1248_ONE);
		AdcStopContinuousRead(SPI_ADS1248_TWO);
		tm = time_ms(100);
		state = THERMOTHREAD_STATE_SETUP_CONFIG_REGISTERS;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_CONFIG_REGISTERS:
		
		if (time_fired(tm)) {
			tmp = 0x28; // internal ref on, ref1 selected, normal operation
			AdcWriteReg(SPI_ADS1248_ONE, ADS1248_MUX1_REGISTER, &tmp, 1);
			AdcWriteReg(SPI_ADS1248_TWO, ADS1248_MUX1_REGISTER, &tmp, 1);
			
			tmp = 0x03;			// GAIN=1  SPS=40
			AdcWriteReg(SPI_ADS1248_ONE, ADS1248_SYS0_REGISTER, &tmp, 1);
			AdcWriteReg(SPI_ADS1248_TWO, ADS1248_SYS0_REGISTER, &tmp, 1);
			
			tmp = 0x04;		 //500uA current source DRDY normal mode
			AdcWriteReg(SPI_ADS1248_ONE, ADS1248_IDAC0_REGISTER, &tmp, 1);
			AdcWriteReg(SPI_ADS1248_TWO, ADS1248_IDAC0_REGISTER, &tmp, 1);		
			
			tm = time_ms(500);
			state = THERMOTHREAD_STATE_SETUP_OFFSET_CALIBRATION;
		}
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_OFFSET_CALIBRATION:
		
		if (time_fired(tm)) {
			/* WE DO NOT WANT THE CALIBRATION
			 * If the system is powered without the first TC connected 
			 * the calibration offset will cause wrong readings for 
			 * all the TC's connected. 
			 * We can't do it every reading because it takes
			 * about 400mS @40SPS ~ 200mS @80SPS

			ConfigureTCInputMux(SPI_ADS1248_ONE, 0);
			ConfigureTCInputMux(SPI_ADS1248_TWO, 0);
			
			AdcSendSelfOcal(SPI_ADS1248_ONE);
			AdcSendSelfOcal(SPI_ADS1248_TWO);
			*/

			state = THERMOTHREAD_STATE_SETUP_WAIT_END_CALIBRATION;
		}
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_WAIT_END_CALIBRATION:

		// Wait the DRDY for the end calibration before start Read-Loop
		if ((getDRDYConversionComplete(SPI_ADS1248_ONE) == 0) || 
				(getDRDYConversionComplete(SPI_ADS1248_TWO) == 0)) {
			break;
		}
		releaseStart(SPI_ADS1248_ONE);
		releaseStart(SPI_ADS1248_TWO);
		state = THERMOTHREAD_STATE_SETUP_FINALIZE;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_SETUP_FINALIZE:
	
		tm = time_ms(10); // wait 10mS before start loop readings
		state = THERMOTHREAD_STATE_LOOP_START;
		break;
//===================================================================================	
	// Continuous Reading-Loop states
	case THERMOTHREAD_STATE_LOOP_START:
		
		if (time_fired(tm)) {
			ConfigureTCInputMux(SPI_ADS1248_ONE, currTcIndex);
			ConfigureTCInputMux(SPI_ADS1248_TWO, currTcIndex);
			assertStart(SPI_ADS1248_ONE);
			assertStart(SPI_ADS1248_TWO);
			state = THERMOTHREAD_STATE_LOOP_WAIT_DATA;
		}
		break;
//===================================================================================
	case THERMOTHREAD_STATE_LOOP_WAIT_DATA :
		
		if ((getDRDYConversionComplete(SPI_ADS1248_ONE) == 0) || 
				(getDRDYConversionComplete(SPI_ADS1248_TWO) == 0)) {
			break;
		}
		releaseStart(SPI_ADS1248_ONE);
		releaseStart(SPI_ADS1248_TWO);
		state = THERMOTHREAD_STATE_LOOP_READ;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_LOOP_READ:

		val_ads1 = AdcReadConversion(SPI_ADS1248_ONE);
		val_ads2 = AdcReadConversion(SPI_ADS1248_TWO);
	
		state = THERMOTHREAD_STATE_LOOP_FINALIZE;
		break;
//===================================================================================	
	case THERMOTHREAD_STATE_LOOP_FINALIZE:
		
		tcRawValues[0+currTcIndex] = val_ads1 >> 8;
		tcRawValues[4+currTcIndex] = val_ads2 >> 8;

		if (++currTcIndex == MAX_NUM_OF_SENSORS) {
			Pt1000ReadCounter++; // Increment Read Counter for PLC
			currTcIndex = 0;
		}
		tm = time_ms(1); // wait 1mS before start a new reading
		state = THERMOTHREAD_STATE_LOOP_START;
		break;
	}
}


adc.h