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 sends repeated start instead of stop in Read command

I'm building an I2C function to read slave devices in the next format:
Start > Address Slave + W > A > Register> A> Repeated Start> Address Slave + R > A > DATA > NACK > STOP ,

but my code is behaving as follows :

Start > Address Slave + W > A > Register> A> Repeated Start> Address Slave + R > A > DATA >NacK > Repeated Start 

I'd like to if I'm missing something important, I'm using as guide the file "slau412d".

Regards

#include <msp430.h>

typedef enum {
writeReg,
writeData,
readI2C,
stop,readReg,
inactive,
readData
} cmd_;

cmd_ i2cStatus=inactive;
unsigned char I2Creg;
unsigned char *PTxData;                     // Pointer to TX data
volatile unsigned char TXByteCtr;

void i2c_init(void){
	  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
	  P1SEL |= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
	  P1SEL2|= BIT6 + BIT7;                     // Assign I2C pins to USCI_B0
	  UCB0CTL1 |= UCSWRST;                      // Enable SW reset
	  UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
	  UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
	  UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
	  UCB0BR1 = 0;
	  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
	  IE2 |= UCB0TXIE + UCB0RXIE;                          // Enable TX interrupt
}


void readBytes(unsigned char address,unsigned char reg,unsigned char * data,unsigned char length){
	    i2cStatus=readReg;
	    I2Creg=reg;
	    UCB0I2CSA = address;                    // Slave Address is 048h                        // TX array start address
	    while (UCB0CTL1 & UCTXSTP);
	    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
	    UCB0TXBUF = I2Creg;
	    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}

void writeByte(unsigned char address,unsigned char reg,unsigned char data){
	    i2cStatus=writeReg;
	    I2Creg=reg;
	    UCB0I2CSA = address;                    // Slave Address is 048h
	    PTxData = &data;                         // TX array start address
	    TXByteCtr = 1;              // Load TX byte counter
	    while (UCB0CTL1 & UCTXSTP);
	    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
	    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}

void writeBytes(unsigned char address,unsigned char reg,unsigned char *data){
	    i2cStatus=writeReg;
	    I2Creg=reg;
	    UCB0I2CSA = address;                    // Slave Address is 048h
	    PTxData = data;                         // TX array start address
	    TXByteCtr = sizeof data;              // Load TX byte counter
	    while (UCB0CTL1 & UCTXSTP);
	    UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
	    __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
}

unsigned char TxData[2] =              // Table of data to transmit
{
  0x11,0x15
};
unsigned char buff[23];
int main(void)
{  // set up bit 0 of P1 as output

  i2c_init();
  readBytes(0x12,0x02,buff,3);

  while (1)
  {
	 //writeByte(0x4e,0x09,0x03);

  }
}
unsigned char data=0;
//------------------------------------------------------------------------------
// The USCIAB0TX_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
// points to the next byte to transmit.
//------------------------------------------------------------------------------
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_ISR (void)
#else
#error Compiler not supported!
#endif
{

	if(UCB0STAT & UCNACKIFG){

		i2cStatus=stop;
	}
	switch(i2cStatus){

		case writeData:

			 if (TXByteCtr)                            // Check TX byte counter
			  {
				UCB0TXBUF = *PTxData++;                 // Load TX buffer
				TXByteCtr--;                            // Decrement TX byte counter
			  }
			  else
			  {
				UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
				IFG2 &= ~UCB0TXIFG;                     // Clear USCI_B0 TX int flag
				i2cStatus=inactive;
				__bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
			  }
			 break;
		case writeReg:

			UCB0TXBUF = I2Creg;
			i2cStatus=writeData;
			break;
		case readData:
			data=UCB0RXBUF;
			UCB0CTL1 |= UCTXSTP;
			break;
		case readReg:
			IFG2 &= ~ UCB0RXIFG ;
			UCB0CTL1 |= UCTXSTT;
			UCB0CTL1 &= ~UCTR;
			i2cStatus=readData;
			break;

		case stop:
			UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
			IFG2 &= ~UCB0RXIFG;                     // Clear USCI_B0 TX int flag
			i2cStatus=inactive;
			__bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
			break;
	}

}

  • void readBytes()
           ...
           UCB0CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
           UCB0TXBUF = I2Creg;

    You should write to TXBUF only when the TXIFG flag is set. Move this to the interrupt handler.

           case readReg:
               IFG2 &= ~ UCB0RXIFG ;
               UCB0CTL1 |= UCTXSTT;
               UCB0CTL1 &= ~UCTR;

    You must clear UCTR before restarting.

**Attention** This is a public forum