Tool/software:
I've implemented I2C master based on I2C examples source code. It works OK except one thing: when I make reset via debugger during I2C operation (for ex., on breakpoint inside interrupt processing), SDA remains in low state and only power cycling helps to restore operation
Here's my code:
void init_i2c() {
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB1BR1 = 0;
UCB1I2CSA = RTC_ADDR >> 1; // Set slave address
UCB1IE |= UCNACKIE; // allow NACK interrupt
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
}
void i2c_write(uint8_t offset, const uint8_t *data, uint8_t size) {
i2cbuf = (volatile uint8_t*) data;
i2clength = size;
i2coffset = offset;
UCB1IFG &= ~UCRXIFG; // Clear USCI_B1 TX int flag
UCB1IE |= UCTXIE; // Enable TX interrupt
UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts
__no_operation(); // Remain in LPM0 until all data
// is TX'd
while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB1IE &= ~UCTXIE; // Disable TX interrupt
}
// USCI B1 interrupt service routine
#pragma vector = USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
{
switch(__even_in_range(UCB1IV,12))
{
case 0: break; // Vector 0: No interrupts
case 2: break; // Vector 2: ALIFG
case 4:
UCB1IFG &= ~UCNACKIFG; // Clear USCI_B1 NACK int flag
__bic_SR_register_on_exit(LPM0_bits);
break; // Vector 4: NACKIFG
case 6: break; // Vector 6: STTIFG
case 8: break; // Vector 8: STPIFG
case 10: break; // Vector 10: RXIFG
case 12: // Vector 12: TXIFG
if (i2clength) // Check TX byte counter
{
UCB1TXBUF = *i2cbuf++; // Load TX buffer
i2clength--; // Decrement TX byte counter
}
else
{
UCB1CTL1 |= UCTXSTP; // I2C stop condition if this is NOT intermediate byte and this is NOT read op
UCB1IFG &= ~UCTXIFG; // Clear USCI_B1 TX int flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
default: break;
}
}
