Part Number:MSP430G2553
In my code I have enabled ALL of the USCI_B module's interrupts, set the GIE bit and have an ISR with the correct interrupt vector. (used the vector and ISR name from TI's example code) Currently I use polling to implement I2C. However I'd like to do it the proper way using interrupts to save power since this will a battery operated device.
Using polling, I've verified that the corresponding TX flag is being set and with a logic analyzer I verified that the slave acknowledges each byte. I can't understand why the ISR won't run. Relevant code blocks below:
USCI_B initialization block:
// Initialize USCI_B0 to standard speed I2C master mode. Pins are already assigned to SCL and SDA. UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // 7-bit addressing, single master UCB0CTL1 |= UCSSEL_2 | UCTR | UCSWRST; // Transmitter mode, sourced from SMCLK UCB0BR1 = 0; // set the upper baud rate register to 0 UCB0BR0 = I2C_CLOCK_DIV; // 100KHz bus frequency, sourced from 16MHz SMCLK divided by 40 UCB0STAT = 0; // reset state change flags IFG2 &= ~(UCB0TXIFG | UCB0RXIFG); // reset the transmit and recieve flags UCB0I2CIE = UCNACKIE | UCSTPIE | UCSTTIE | UCALIE; // Enable interrupts for all bus state changes IE2 |= UCB0RXIE | UCB0TXIE; // Enable interrupts for I2C receive and transmit (transmit enabled on default) UCB0I2CSA = 0; // Initialize slave address to 0 UCB0CTL1 &= ~UCSWRST; // Reset UCSWRST, starting I2C communication
__bis_SR_register(GIE); // enable global interrupts
I2C Bus Initialization loop:
while (~status & MCP23018_INIT) { // while the MCP23018 is NOT initialized if (IFG2 & UCB0TXIFG || interrupt_test > 0) { // if it is time to load the TXBUFFER if (~status & MCP23018_INIT) { // if the MCP23018 is NOT initialized: if (i2c_i > OLATB+1) { // if this is the bit after the last register: i2c_i = 0; // reset i2c iterator UCB0CTL1 |= UCTXSTP; // transmit STOP signal status |= MCP23018_INIT; } UCB0TXBUF = MCP23018_INIT_DATA[i2c_i]; // put the corresponding byte from init data array into the tx buffer i2c_i++; // increment the i2c iterator } } else if (UCB0I2CSA == 0) { // otherwise: if the slave address is 0 UCB0I2CSA = MCP23018_OPCODE; // load slave address+0 for write mode UCB0CTL1 |= UCTXSTT; // send I2C start condition } else if (UCB0STAT & UCNACKIFG) { // if NACK was recieved UCB0STAT &= ~UCNACKIFG; // clear the flag i2c_i = 0; // reset address iterator to 0 UCB0CTL1 |= UCTXSTT; // set a start condition IFG2 |= UCB0TXIFG; // set the TX flag }
//__bis_SR_register(LPM0_bits + GIE); // turn off the CPU to save power, global interrupt enabled } P1OUT |= BIT0; // light up LED1 when initialized
I2C Data ISR:
#pragma vector=USCIAB0TX_VECTOR // since the USCI_B is in I2C mode, this is the I2C data ISR __interrupt void USCIAB0TX_ISR(void) { // when the USCI_B TX register is empty or RX register is full __bic_SR_register_on_exit(LPM0_bits); // clear the bits to wake up the CPU } // return to the main loop
I2C State ISR:
#pragma vector=USCIAB0RX_VECTOR // since the USCI_B is in I2C mode, this is the I2C state ISR __interrupt void USCIAB0RX_ISR(void) { // when the I2C state changes __bic_SR_register_on_exit(LPM0_bits); // clear the bits to wake up the CPU } // return to the main loop