TI distributes example code for various MSP430 parts. There's a specific example file which isn't making sense to me: msp430x22x4_uscib0_i2c_12. It transmits and then receives, all from within an ISR for USCIAB0TX. It enables RX interrupts at some point (UCB0RXIE) but there's no ISR for RX, and the RX flag (UCB0RXIFG) is never checked for. So, my question is, how does it work without these features, and why does the code enable an interrupt it appears never to use?
Here's the code:
//******************************************************************************
// MSP430F22x4 Demo - USCI_B0 I2C Master TX/RX multiple bytes from MSP430 Slave
// with a repeated start in between TX and RX operations.
//
// Description: This demo connects two MSP430's via the I2C bus. The master
// transmits to the slave, then a repeated start is generated followed by a
// receive operation. This is the master code. This code demonstrates how to
// implement an I2C repeated start with the USCI module using the USCI_B0 TX
// interrupt.
// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.2MHz
//
// ***to be used with msp430x22x4_uscib0_i2c_13.c***
//
// /|\ /|\
// MSP430F24x 10k 10k MSP430F22x4
// slave | | master
// ----------------- | | -----------------
// -|XIN P3.1/UCB0SDA|<-|---+->|P3.1/UCB0SDA XIN|-
// | | | | |
// -|XOUT | | | XOUT|-
// | P3.2/UCB0SCL|<-+----->|P3.2/UCB0SCL |
// | | | |
//
// R. B. Elliott / H. Grewal
// Texas Instruments Inc.
// April 2008
// Built with IAR Embedded Workbench Version: 3.42A
//******************************************************************************
#include "msp430x22x4.h"
#define NUM_BYTES_TX 3 // How many bytes?
#define NUM_BYTES_RX 2
int RXByteCtr, RPT_Flag = 0; // enables repeated start when 1
volatile unsigned char RxBuffer[128]; // Allocate 128 byte of RAM
unsigned char *PTxData; // Pointer to TX data
unsigned char *PRxData; // Pointer to RX data
unsigned char TXByteCtr, RX = 0;
unsigned char MSData = 0x55;
void Setup_TX(void);
void Setup_RX(void);
void Transmit(void);
void Receive(void);
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
while(1){
//Transmit process
Setup_TX();
RPT_Flag = 1;
Transmit();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
//Receive process
Setup_RX();
Receive();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
}
}
//-------------------------------------------------------------------------------
// 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
// any 2+ number of bytes by pre-loading RXByteCtr with the byte count.
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
if(RX == 1){ // Master Receive?
RXByteCtr--; // Decrement RX byte counter
if (RXByteCtr)
{
*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
}
else
{
if(RPT_Flag == 0)
UCB0CTL1 |= UCTXSTP; // No Repeated Start: stop condition
if(RPT_Flag == 1){ // if Repeated Start: do nothing
RPT_Flag = 0;
}
*PRxData = UCB0RXBUF; // Move final RX data to PRxData
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}}
else{ // Master Transmit
if (TXByteCtr) // Check TX byte counter
{
UCB0TXBUF = MSData++; // Load TX buffer
TXByteCtr--; // Decrement TX byte counter
}
else
{
if(RPT_Flag == 1){
RPT_Flag = 0;
PTxData = &MSData; // TX array start address
TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
__bic_SR_register_on_exit(CPUOFF);
}
else{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
}
}
void Setup_TX(void){
_DINT();
RX = 0;
IE2 &= ~UCB0RXIE;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent// Disable RX interrupt
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 = 0x48; // Slave Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE; // Enable TX interrupt
}
void Setup_RX(void){
_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 = 0x48; // Slave Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE; // Enable RX interrupt
}
void Transmit(void){
PTxData = &MSData; // TX array start address
TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
void Receive(void){
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer
RXByteCtr = NUM_BYTES_RX-1; // Load RX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}