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.

I2C data corruption! reliable SW

Other Parts Discussed in Thread: TMP100, CONTROLSUITE

Hello,

I am reading temperatures from 2x TMP100, I2C temperature sensors and storing the received data into files, as well as a time reference using timer1.

SW wise, I test the initialization of both TMPs (set and wait 100msec), I2C-clock frequency of 50 kHz, and just read data each 400msec by INT0 and get it by usual I2C interruptions, i2c_basic and i2c_fifo. NACKs are evaluated. Writing files using breakpoints. Please see code attached.

HW wise, the TMP's are soldered to a small piece of PCB each, and then about 5 feet of network cable from the PCBs to Delfino 28335. TMPs and DSP board are close to a significant power supply (ps) and are therefore subjected to EMI. They have to be there, anyway. There is a common GND to the ps and computer, where DSP board is plugged into.

The issues: I am having errors and stability issues. When I turn the power supply (ps) on/off, all variables go to Error in watch window, only way to fix is restarting the DSP board. Sometimes, it doesn't lock up everything, but just locks the TMP's, sometimes just the TMP that is closer to the ps. Other error is that, when I plotted the stored data, there are many points in which the reading of one sensor is actually exactly the other's value. What I thought of it is that one sensor was addressed, yet other answered! It happened about twice (consecutive) each 1000 readings, to both sensors and not exactly under a regular period.

I am switching to shielded cables and running tests again. Havenn't seen yet on an oscilloscope exactly in what condition it locks, eg, SCL state.

Doubts: Is there any proven working way to split GND's - PC/USB and DSP Board, in order to avoid spikes, glitches? How low can I set I2C clk frequency, assuming it would be helpful? I am looking for the documents to calculate the correct pull up resistors, I'd appreciate if you could indicate where they are. Any other suggestion?

This is a prototype for medical device, I can't afford those errors and, even if I improve HW condition, I figure out I still need a reliable SW that handle these errros - bus lock up, address one chip and receive answer from other. Can you advice me on that? Is there maybe a chance to write a CRC check?

Thank you!

#include "DSP2833x_Device.h"
#include "IQmathLib.h"

// TMP100 commands
#define TMP100_SLAVE_1 			0x48	// slave address TMP100 (ADDR0=ADDR1=0)
#define TMP100_SLAVE_2 			0x4D	// slave address TMP100 (ADDR0=Float, ADDR1=1)
#define POINTER_TEMPERATURE 	0	
#define POINTER_CONFIGURATION 	1
#define POINTER_T_LOW 			2
#define POINTER_T_HIGH 			3

// external function prototypes
extern void InitSysCtrl(void);
extern void InitPieCtrl(void);
extern void InitPieVectTable(void);
extern void InitCpuTimers(void);
extern void ConfigCpuTimer(struct CPUTIMER_VARS *, float, float);

// Prototype statements for functions found within this file.
void Gpio_select(void);
void I2CA_Init(void);
interrupt void cpu_timer0_isr(void);
interrupt void cpu_timer1_isr(void);
interrupt void i2c_fifo_isr(void);
interrupt void i2c_basic_isr(void);

//global variables:
int temperature_TMP_1;	// temperature = 2' complement of temperature (-128 ... +127 Celsius) // is an I8Q8 - Value
int temperature_TMP_2;

char I2C_Comm_Error=0;
char Alt_TMP = 0; // Alternate between TMP's. 0 = TMP100#1, 1 = TMP100#2

//int t1,t2,t3;

//###########################################################################
//						main code									
//###########################################################################
void main(void)
{
	char I2C_Init_Error_TMP100_1 = 0;
	char I2C_Init_Error_TMP100_2 = 0;
	

	InitSysCtrl();	// Basic Core Init from DSP2833x_SysCtrl.c

	EALLOW;
   	SysCtrlRegs.WDCR = 0x68; // DISABLES WDT
   	EDIS;			// 0x00AF  to NOT disable the Watchdog, Prescaler = 64

	DINT;				// Disable all interrupts
	
	Gpio_select();

	I2CA_Init(); //	Initialize I2C module (28335)

	InitPieCtrl();							// basic setup of PIE table; from DSP2833x_PieCtrl.c
	InitPieVectTable();						// default ISR's in PIE

	// load addresses of interrupt service routines into the PieVectTable
	EALLOW;
	PieVectTable.TINT0 = &cpu_timer0_isr;
	PieVectTable.XINT13 = &cpu_timer1_isr;
	PieVectTable.I2CINT2A = &i2c_fifo_isr;
	PieVectTable.I2CINT1A = &i2c_basic_isr;
	EDIS;

	InitCpuTimers();	// basic setup CPU Timer0, 1 and 2
	ConfigCpuTimer(&CpuTimer0,150,400000); // CPU - Timer0 at 400 milliseconds
	ConfigCpuTimer(&CpuTimer1,150,1000000); // CPU - Timer1 at 1 sec

	PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //timer0
	PieCtrlRegs.PIEIER8.bit.INTx1 = 1; // i2c - basic
	PieCtrlRegs.PIEIER8.bit.INTx2 = 1; // i2c - FIFO

	//IER |=1;
	IER |=0x81; //register IER must now allow lines INT1 and INT8 for timers (0,1), i2c basic and fifo interrupts
	IER |=M_INT13; //timer1 is not connected to PIE Group. Enable TIMER1 interrupt directly in IER (bit 12)

	EINT;
	ERTM;

	//Configure TMP100#1

		I2caRegs.I2CSAR = TMP100_SLAVE_1; // I2C slave address register

		// Send START, set pointer to Configuration register and set resolution to 12 bit
		I2caRegs.I2CCNT	= 2;	// set count # in DSP to 2 bytes (i.e. for writing)
		I2caRegs.I2CDXR = POINTER_CONFIGURATION;
		I2caRegs.I2CDXR = 0x60; //set TMP100 Config. Register - 12 bits resolut.:
			/*
			OS/ALERT:
			write 1: single temperature conversion
			write 0: continuous temperature conversion
			read 1: temperature above THIGH
			read 0: temperature below TLOW
			R1, R0:
			Resolution 9 bit (0,0) � 12 bit (1,1)
			F1,F0:
			activate ALERT after number of consecutive faults (1,2,4,6)
			POL:
			Polarity of ALERT (0 or 1)
			TM:
			write 0: Comparator Mode (ALERT stays active as long as condition is true)
			write 1: Interrupt Mode( ALERT is cleared by a read instruction of any reg)
			SD:
			write 1: shutdown
			write 0: active mode
			*/

		I2caRegs.I2CMDR.all = 0x6E20;	// Initialize register �I2CMDR�:
			/*
			Bit15 = 0; no NACK in receiver mode
			Bit14 = 1; FREE on emulation halt
			Bit13 = 1; STT generate START
			Bit12 = 0; reserved
			Bit11 = 1; STP generate STOP
			Bit10 = 1; MST master mode
			Bit9 = 1; TRX transmitter mode // if 0, receiver mode
			Bit8 = 0; XA 7-bit address mode
			Bit7 = 0; RM non-repeat mode, I2CCNT determines # of bytes
			Bit6 = 0; DLB no loopback mode
			Bit5 = 1; IRS I2C module enabled
			Bit4 = 0; STB no start byte mode
			Bit3 = 0; FDF no free data format
			 */

		CpuTimer0Regs.TCR.bit.TSS = 0;	// start timer0

		//Test stop condition for TMP100#1
		while (CpuTimer0.InterruptCount == 0 && I2caRegs.I2CSTR.bit.SCD == 0); 	//Wait for the successful generation of the stop-condition of TMP100#1 within 100ms
		if (CpuTimer0.InterruptCount == 0 && I2caRegs.I2CSTR.bit.SCD == 1)	// Initialized ok
		{
			I2caRegs.I2CSTR.bit.SCD = 1; 			//Clear the stop condition flag
			//DISPLAY TMP100#1 Initialized ok
		}
		if (CpuTimer0.InterruptCount == 1 && I2caRegs.I2CSTR.bit.SCD == 0) 	// Error
		{
			I2C_Init_Error_TMP100_1 = 1;
			//DISPLAY TMP100#1 Failure Initializing
		}

	//Configure TMP100#2

			I2caRegs.I2CSAR = TMP100_SLAVE_2; // I2C slave address register

			// Send START, set pointer to Configuration register and set resolution to 12 bit
			I2caRegs.I2CCNT	= 2;	// set count # in DSP to 2 bytes (i.e. for writing)
			I2caRegs.I2CDXR = POINTER_CONFIGURATION;
			I2caRegs.I2CDXR = 0x60; //set TMP100 Config. Register - 12 bits resolut.:
				/*
				OS/ALERT:
				write 1: single temperature conversion
				write 0: continuous temperature conversion
				read 1: temperature above THIGH
				read 0: temperature below TLOW
				R1, R0:
				Resolution 9 bit (0,0) � 12 bit (1,1)
				F1,F0:
				activate ALERT after number of consecutive faults (1,2,4,6)
				POL:
				Polarity of ALERT (0 or 1)
				TM:
				write 0: Comparator Mode (ALERT stays active as long as condition is true)
				write 1: Interrupt Mode( ALERT is cleared by a read instruction of any reg)
				SD:
				write 1: shutdown
				write 0: active mode
				*/

			I2caRegs.I2CMDR.all = 0x6E20;	// Initialize register �I2CMDR�:
				/*
				Bit15 = 0; no NACK in receiver mode
				Bit14 = 1; FREE on emulation halt
				Bit13 = 1; STT generate START
				Bit12 = 0; reserved
				Bit11 = 1; STP generate STOP
				Bit10 = 1; MST master mode
				Bit9 = 1; TRX transmitter mode // if 0, receiver mode
				Bit8 = 0; XA 7-bit address mode
				Bit7 = 0; RM non-repeat mode, I2CCNT determines # of bytes
				Bit6 = 0; DLB no loopback mode
				Bit5 = 1; IRS I2C module enabled
				Bit4 = 0; STB no start byte mode
				Bit3 = 0; FDF no free data format
				 */

			CpuTimer0Regs.TIM.all = 0;	// zero timer0

			//Test stop condition for TMP100#2
			while (CpuTimer0.InterruptCount == 0 && I2caRegs.I2CSTR.bit.SCD == 0); 	//Wait for the successful generation of the stop-condition of TMP100#2 within 100ms
			if (CpuTimer0.InterruptCount == 0 && I2caRegs.I2CSTR.bit.SCD == 1) 	// Initialized ok
			{
				I2caRegs.I2CSTR.bit.SCD = 1; 			//Clear the stop condition flag
				//DISPLAY TMP100#2 Initialized ok
			}
			if (CpuTimer0.InterruptCount == 1 && I2caRegs.I2CSTR.bit.SCD == 0) 	// Error
			{
				I2C_Init_Error_TMP100_2 = 1;
				//DISPLAY TMP100#2 Failure Initializing
			}

	CpuTimer1Regs.TCR.bit.TSS = 0;	// start timer1

	while(1)
	{    
			if(CpuTimer0.InterruptCount != 0)				//returning from INT Timer0
	  		{
	  			CpuTimer0.InterruptCount = 0;
	  			GpioDataRegs.GPBTOGGLE.bit.GPIO34 = 1;		// toggle red LED LD3 @ 28335CC
	  			GpioDataRegs.GPATOGGLE.bit.GPIO31 = 1;

				//configure TMP100#1 for reading temperatures. Send START and set pointer to temperature - register

	  			if(Alt_TMP == 0) //test for which TMP to read from
	  				I2caRegs.I2CSAR = TMP100_SLAVE_1;
	  			else
	  				I2caRegs.I2CSAR = TMP100_SLAVE_2;

	  			I2caRegs.I2CCNT = 1; // 1 byte message
				I2caRegs.I2CDXR = POINTER_TEMPERATURE;
				I2caRegs.I2CMDR.all = 0x6620; // master-transmitter

				// master - receiver mode is initialized in "i2c_basic_isr" after ARDY
				// read of temperature is done by ISR "i2c_fifo_isr"

	  		}

	  		/*
			EALLOW;
			SysCtrlRegs.WDKEY = 0x55;	// service WD #1
			EDIS;
			*/






	}
} 

void Gpio_select(void)
{
	EALLOW;
	GpioCtrlRegs.GPAMUX1.all = 0;			// GPIO15 ... GPIO0 = General Puropse I/O
	GpioCtrlRegs.GPAMUX2.all = 0;			// GPIO31 ... GPIO16 = General Purpose I/O
	
	GpioCtrlRegs.GPBMUX1.all = 0;			// GPIO47 ... GPIO32 = General Purpose I/O
	GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;	// GPIO32 = I2C - SDA
	GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;	// GPIO33 = I2C - SCL

	GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0;    // Enable pull-up for GPIO32 (SDAA)
	GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0;	   // Enable pull-up for GPIO33 (SCLA)

	GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3;  // Asynch input GPIO32 (SDAA)
    GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3;  // Asynch input GPIO33 (SCLA)

	GpioCtrlRegs.GPBMUX2.all = 0;			// GPIO63 ... GPIO48 = General Purpose I/O

	GpioCtrlRegs.GPCMUX1.all = 0;			// GPIO79 ... GPIO64 = General Purpose I/O
	GpioCtrlRegs.GPCMUX2.all = 0;			// GPIO87 ... GPIO80 = General Purpose I/O
	 

	GpioCtrlRegs.GPADIR.all = 0;			// GPIO0 to 31 as inputs
	GpioCtrlRegs.GPADIR.bit.GPIO31 = 1;		// GpIO31 = LED LD2

	GpioCtrlRegs.GPBDIR.all = 0;			// GPIO63-32 as inputs
	GpioCtrlRegs.GPBDIR.bit.GPIO34 = 1;		// LED LD3 at GPIO34

	GpioCtrlRegs.GPCDIR.all = 0;			// GPIO87-64 as inputs
	EDIS;
}  

void I2CA_Init(void)
{
	
	I2caRegs.I2CMDR.bit.IRS = 0;	// Reset the I2C module

	//	I2C Prescale Register
	I2caRegs.I2CPSC.all = 14;		// Internal I2C module clock = SYSCLK/(PSC +1)
								    // = 10 MHz
								    
	//	Setting I2C-clock frequency of 50 kHz (clock period = 20us). Ver eq. abaixo.
	I2caRegs.I2CCLKL = 95;			// Tmaster = (PSC +1)[ICCL + 5 + ICCH + 5] / 150MHz
	I2caRegs.I2CCLKH = 95;			// Tmaster =  15 [ICCL + ICCH + 10] / 150 MHz 
									// d = 5  for IPSC >1
									
									// for I2C 50 kHz:
									// Tmaster = 20 �s * 150 MHz / 15 = 200 = (ICCL + ICCH +10)  
									// ICCL + ICCH = 190
									// ICCL = ICH = 190/2 = 95	

//	I2caRegs.I2CCLKL = 45;			
//	I2caRegs.I2CCLKH = 45;			// for I2C 100 kHz:
									// Tmaster = 10 �s *150 MHz / 15 = 100 = (ICCL + ICCH + 10)  
									// ICCL + ICCH = 90
									// ICCL = ICH = 90/2 = 45 	

	I2caRegs.I2CIER.bit.ARDY = 1; 	//enable basic I2C-interrupt - access ready, which is generated, when the first two bytes of the �TMP100 Read Timing� I2C - data frame (see Slide 12-31) are transmitted.
	I2caRegs.I2CIER.bit.NACK = 1; 	//enables I2C NACK interrupt: communication error handling

	I2caRegs.I2CFFTX.all = 0; 			//I2C Transmit FIFO Register
	I2caRegs.I2CFFTX.bit.TXFFIL = 0; 	//set the transmit interrupt level (bit field TXFFIL) to zero
	I2caRegs.I2CFFTX.bit.I2CFFEN = 1; 	//Enable the FIFOs
	I2caRegs.I2CFFTX.bit.TXFFRST = 1; 	//Enable the FIFO-transmit support

	I2caRegs.I2CFFRX.all = 0; 			//I2C Receive FIFO Register
	I2caRegs.I2CFFRX.bit.RXFFIL = 2; 	//set the receive interrupt level (bit field RXFFIL) to 2, because we will receive a 2 byte temperature message from the TMP100
	I2caRegs.I2CFFRX.bit.RXFFRST = 1; 	//Enable the FIFO-receiver support

	I2caRegs.I2CFFRX.bit.RXFFIENA = 1; 	//enable interrupt after receiving two temperature bytes from the TMP100

	I2caRegs.I2CMDR.bit.IRS = 1;		//Take I2C out of reset
}

interrupt void cpu_timer0_isr(void)
{
	CpuTimer0.InterruptCount++;
	//EALLOW;
	//SysCtrlRegs.WDKEY = 0xAA;	// service WD #2
	//EDIS;
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

interrupt void cpu_timer1_isr(void)
{
	//t1 = CpuTimer1.RegsAddr->TIM.half;
	//long i;
	//for (i=0;i<10000000;i++)
	//	"nop";
	CpuTimer1.InterruptCount++;

	//t2 = CpuTimer1.RegsAddr->TIM;
	//EALLOW;
	//SysCtrlRegs.WDKEY = 0xAA;	// service WD #2
	//EDIS;
}


interrupt void i2c_fifo_isr(void)
{
	int i;
	if (I2caRegs.I2CFFRX.bit.RXFFINT == 1) // RX-FIFO - interrupt
	{
	i = I2caRegs.I2CDRR << 8; // read upper 8 bit (integers)
	i += I2caRegs.I2CDRR; // add lower 8 bit (fractions)

	if (Alt_TMP == 0)
		temperature_TMP_1 = i;
	else
		temperature_TMP_2 = i;

	I2caRegs.I2CFFRX.bit.RXFFINTCLR = 1; // clear ISR
	}

	Alt_TMP ^= 0x1; //Invert next TMP sensor to be read
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

interrupt void i2c_basic_isr(void)
{
	unsigned int IntSource;
	IntSource = I2caRegs.I2CISRC.all; //make a local copy of this register - first read of this register will clear it automatically. It is good practice and will be very important later, when you enable more than one basic source,

	if (IntSource == 3) // ARDY was source of interruption
		{
		I2caRegs.I2CCNT = 2; // read 2 byte temperature
		I2caRegs.I2CMDR.all = 0x6C20; // Master-Receiver-Mode. Details of I2CMDR in main
		}

	if (IntSource == 2) // NACK was source of interruption - Communication Error
			{
			I2caRegs.I2CMDR.bit.STP = 1; // send STP to end transfer
			I2caRegs.I2CSTR.bit.NACK = 1; // clear NACK bit
			I2C_Comm_Error++;
			}
	PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}

//===========================================================================
// End of SourceCode.
//===========================================================================

  • Decided adding TXS0104EDRG4 Voltage translator to +5V to the chips. And setting chips addresses the most different as possible - add0=add1=1 for one and add0=add1=-0 for other. That should make it more difficult for misaddressing - if that word exists :)

    Couldn't find CRC code or instructions for I2C neither a working solution for stuck bus yet!

    Any thoughts?

  • Hi Thiago,

    Thiago M said:
    I figure out I still need a reliable SW that handle these errros - bus lock up, address one chip and receive answer from other. Can you advice me on that? Is there maybe a chance to write a CRC check?

    Im not sure how you would fix the issue with "address one chip and receive answer from another". The assumption is that each temp sensor has a unique address to which only it responds. There is no other way for the C2000 to figure out which of the two devices responded. As for the CRC, if you look into the VCU library in controlsuite (controlsuite/libs/dsp/VCU) there is a C routine that implements the CRC using a table look-up methodology.

    The I2C v2.1 spec does specify resistor values for use in standard I2C mode (http://www.nxp.com/documents/other/39340011.pdf, page 39) that you might find useful. I'm no expert on board design so hopefully someone with more experience in the area will chime in with better suggestions.