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 USCI receive multiple bytes without interrupts (ISR)

So I am new to all of this - self taught mostly - and am having trouble figuring out how in the world to do a multi-byte read without using the ISR (it just seems simpler to me that way and power time doesn't matter much in this case). My trouble is that I don't know how to know when the rx buffer is ready to read, and thus how to trigger another read.

I know that if you issue a stop before the last byte sends then you just wait until the stop sends and then rxbuff will be ready, but for the other bytes I'm not sure... Also, I am only getting zeros from the accelerometer when I'm pretty sure a multi-byte read should auto increment the read register. (datasheet is here) Since I am new, I would really appreciate any advice you may have. Here's my code (I am also attaching a readout of the bus read) :

// SDA: 1.7
// SCL: 1.6

#include <msp430.h>
#include "gy-80_config.h"

int RXByteCtr, RPT_Flag = 0;                // enables repeated start when 1
volatile unsigned char RxBuffer[128];       // Allocate 128 byte of RAM
unsigned char TxData;                     	// TX data
unsigned char *PRxData;                     // Pointer to RX data
unsigned char TXByteCtr, RX = 0;
int i,j,k;
int byte_rdy =0;
int i2c_mode = I2C_DISABLE;					// This is to help the interrupt routing
											// 0 = disabled, 1 = acc, 2 = gyro, 3 = compass; 4 = barometer

int acc_sample_indx = 0;
volatile char acc_samples[32][6];			// 32 samples in buffer - 3 axis with 2 chars data
unsigned char acc_si;						// Sample index

void Setup_TX(unsigned char );
void Setup_RX(unsigned char );
void I2C_Init();
void I2C_Reset();
void Sample_Init();
void Acce_Data();

int main(void) {
    WDTCTL = WDTPW | WDTHOLD;				  // Stop watchdog timer


    I2C_Init();
    Sample_Init();

    while(1){
    	Acce_Data();
    }

}


#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
	byte_rdy = 1;
}

void I2C_Init(){
	byte_rdy = 0;
	I2C_Reset();
	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
}

void I2C_Reset()
{
	P1DIR |= BIT5;								// This controls bus power (connected to bus ground)
	P1OUT |= BIT5;								// bus off
	for (i = 0; i< 100; i++){}					// Wait a second
	P1OUT &= ~BIT5;								// Power bus on
	for (i = 0; i< 100; i++){}					// Wait a second (so that it can get ready)
}

void Sample_Init()
{
	acc_si = 0;
}

void Acce_Data()
{
	Setup_TX(ACCE_ADDR);
	UCB0CTL1 |= UCTR + UCTXSTT;				// I2C TX, start condition
	UCB0TXBUF = ACCE_STT;					// Multi-byte read address
	while (UCB0CTL1 & UCTXSTT); 			// Wait for start condition and data to send
	UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent


    Setup_RX(ACCE_ADDR);
    UCB0CTL1 |= UCTXSTT;                    // I2C start condition
	while (UCB0CTL1 & UCTXSTT); 			// Wait for start condition
    for (i = 0; i< 6; i++)
    {
    	if (i == 5)
    	{
    		UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
    	}
    	
    	acc_samples[acc_si][i] = UCB0RXBUF; 	// Load RXBuffer, start getting next one.
    }
    acc_si++;
}

void Setup_TX(unsigned char slAddress){
	UCB0I2CSA = slAddress;				// Slave Address
	RX = 0;								// TX
	IE2 &= ~UCB0RXIE;					// Disable RX interrupt
	IE2 |= UCB0TXIE;                    // Enable TX interrupt
}

void Setup_RX(unsigned char slAddress){
  _DINT();
  RX = 1;
  IE2 &= ~UCB0TXIE;
  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;
  UCB0I2CSA = slAddress;                    // Slave Address
  UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
  IE2 |= UCB0RXIE;                          // Enable RX interrupt
}
  • So simple.. I just needed to wait until the rxbuffer was ready by adding "while (!(IFG2 & UCB0RXIFG));" before reading the buffer. Still trying to figure out how to do sequential read on my accelerometer though...

**Attention** This is a public forum