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.

  • TI Thinks Resolved

MSP430G2553: USCIAB0TX_VECTOR working

Prodigy 70 points

Replies: 8

Views: 516

Part Number: MSP430G2553

Hello Everyone,

Currently, I am working on BME280 sensor with has an I2C interface. I have referenced the code from the link: https://electronics.stackexchange.com/questions/67524/msp430-i%C2%B2c-single-write-read-example.

The code is basically on I2C interrupt and it's working fine. I have also tested with Polling method and it works as well. I have some doubts as below regarding both the polling and interrupt methods.

1. With interrupt,the  UCB0RXIE & UCB0TXIE are set for receive & transmit interrupt. so when the data is received and transmit the ISR will call i.e USCIAB0TX_VECTOR. I am confused with USCIAB0TX_VECTOR  triggering. I refer the user guide it mentions that with start condition generated the TXIFG flag will be set and UCTXSTT is cleared once ACK receives from the slave.  On the ISR they haven't cleared the TXFIG flag once the first byte is loaded but cleared on second triggering. I check if the triggering is due to TXIFG so I clear once the first byte is loaded but it triggers again, I also see on second triggering the UCTXSTT  was cleared. I  want to know on what situation the USCIAB0TX_VECTOR ISR will call ?

2. On the polling method, I have polled while(!(UCB0STAT & UCBBUSY)); to check if the bus is busy or idle data transfer. If I poll the while (!(IFG2 & UCA0TXIFG)); it doesn't send the first byte but only send the address and start bit. what I am doing wrong in this case?

Below is code for both Interrupt and Polling. Kindly comment the MACRO #define POLLING for I2C interrupt flow.

#include <msp430g2553.h>


int TXByteCtr;
unsigned char PRxData;
int Rx = 0;
char WHO_AM_I = 0xD0;
char flag = 0;
char itgAddress = 0x77;

void init_I2C(void);
void Transmit(void);
void Receive(void);

//#define POLLING

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
   P1DIR |= BIT0;
  P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
  P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0
  P1OUT &= ~BIT0;
  init_I2C();

 while(1)

{
  //Transmit process
 Rx = 0;
 TXByteCtr = 1;
 Transmit();
 //Receive process
 Rx = 1;
 Receive();
 while(1);
 // _no_operation();
 }
}

//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{

if(Rx == 1){ // Master Recieve?
PRxData = UCB0RXBUF; // Get RX data
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}

else{ // Master Transmit
if (TXByteCtr) // Check TX byte counter
{
P1OUT &= ~BIT0;

UCB0TXBUF = WHO_AM_I; // Load TX buffer
TXByteCtr--; // Decrement TX byte counter
                                                               /*  if used this IFG2 &= ~UCB0TXIFG  API here it triggers again  */
}
else
{

/* comes here even cleared  UCB0TXIFG in above case*/


P1OUT |= BIT0;
UCB0CTL1 |= UCTXSTP; // I2C stop condition
// Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}

}
void init_I2C(void) {
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 = itgAddress; // Slave Address is 077h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
#ifndef POLLING
IE2 |= UCB0RXIE + UCB0TXIE; //Enable RX and TX interrupt
#endif
}

void Transmit(void)
{

while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent

UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

#ifdef POLLING
while(!(UCB0STAT & UCBBUSY));  //working   /* with while (!(IFG2 & UCA0TXIFG)); not working */
UCB0TXBUF = WHO_AM_I;
while(!(UCB0STAT & UCBBUSY));                  /* with while (!(IFG2 & UCA0TXIFG)); not working */
while (UCB0CTL1 & UCTXSTT);

UCB0CTL1 |= UCTXSTP;
while (UCB0CTL1 & UCTXSTP);

#else
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
// _no_operation();
#endif
}
void Receive(void){
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 &= ~UCTR ; // Clear UCTR
UCB0CTL1 |= UCTXSTT; // I2C start condition
while (UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
#ifdef POLLING
while (!( IFG2 & UCB0RXIFG));
PRxData = UCB0RXBUF;
#else
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
#endif
}

Kindly share your views for the same. Any help will be greatly appreciated. 

Regards,

Amit

  • Hi AMITKUMAR,

    For question 1:

    For question 2:

    TXIFG is only used for TX buffer empty interrupt. So you shouldn't use while (!(IFG2 & UCA0TXIFG));

  • In reply to Stanford Li:

    Hello Stanford,

    Thanks for your Kind Response !!!

    If UCAOTXIFG is set when TXBUF is clear,  Does  USCIAB0TX_VECTOR raise when UCA0TXIFG is set i.e TXBUF is empty?

    Regards 

    Amit

  • In reply to AMITKUMAR PRAMANIK:

    Hi AMITKUMAR,

    Right. When the TXBUF is empty, it will set UCAOTXIFG, and if you enable the TX interrupt, you will jump into USCIAB0TX_VECTOR, then you can send a new data to the TXBUF.

    Best regards,
    Stanford
  • In reply to Stanford Li:

    Hello Stanford,

    I have some doubts as below:

    1. If USCIAB0TX_VECTOR event raise while txbuf is empty why I2C is working properly in interrupt? It is checking the same if TXBUF is empty.

    2. As per the manual, it mentions that the TXFIG will clear once start byte and I2C address are sent why I cannot poll TXFIG instead of UCBUSY?

    Regards,

    Amit
  • In reply to AMITKUMAR PRAMANIK:

    Hi AMITKUMAR,

    For question 1. See the picture, TXFIG may be empty while the data is transferring. This interrupt is intended to update the TXBUF in time.

    For question 2. TXFIG only for TXBUF empty check. Even the buffer is empty, the I2C logic may still work (like waiting ACK).

  • In reply to Stanford Li:

    Hello Stanford,

    As per the picture, I see that the UCBxTXIFG is set when an address and start bit are send and after slave ACK the UCTXSTT is cleared and UCBxTXIFG is set.
    As per the I2C interrupt code when the first time the USCIAB0TX_VECTOR event raise it is due to txbuf is empty during this the register address is loaded to txbuf without clearing the TXIFG flag. so on next time of the interrupt UCTXSTT is cleared and stop is send and TXIFG flag. I have doubt what is a scenario when the USCIAB0TX_VECTOR is raised for the second because we haven't cleared the TXFIG flag it should execute the ISR again with no waiting.

    Regards,

    Amit
  • In reply to AMITKUMAR PRAMANIK:

    Hi AMITKUMAR,

    If you write first data to TXBUF, TXIFG is automatically reset. And when the TXBUF is empty again, TXIFG will be raised for second data transfer.

    Or if you want to stop I2C, you need do "UCTXSTP=1 and UCBxTXIFG=0"

  • In reply to Stanford Li:

    Hello Stanford,

    Thanks for your Kind Response !!!

    I will check the Register values that you have mention during I2C interrupt operation and I will share the results.

    Regards,
    Amit

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.