Hi,
I think, I run into the I2C-Erratum USCI30. But the Workaround doesn't work.
I use Master Repeated Receive with UCB0.
The Symptoms are ( s Picture):
- SCL clocks endlessy
- No Interrupt any more
The green Signal shows the duration of the Interrupt-Routine.
The delay comes from the Workaround ( waiting for SCL == LOW). The error comes during the reading of bytes.
Do you have any hint?
I've appended the ISR.
regards,
Steffen
#pragma vector = USCI_B0_VECTOR __interrupt void I2C_B0_ISR(void) { bool test = true; int i; int count; switch (__even_in_range(UCB0IV, 12)) { case USCI_I2C_UCNACKIFG: /* NAK interrupt. */ i2c[0].state = STATE_NACK; UCB0CTL1 |= UCTXSTP; break; case USCI_I2C_UCRXIFG: /* RX interrupt. */ /* Read byte, decrement counter. */ /* UCSI30 other bytes follow the workaround: Code flow for workaround (1) Enter RX ISR for reading receiving bytes (2) Check if UCSCLLOW.UCBxSTAT == 1 (3) If no, repeat step 2 until set (4) If yes, repeat step 2 for a time period > 3 x t (BitClock) where t (BitClock) = 1/ f (BitClock) (5) If window of 3 x t(BitClock) cycles has elapsed, it is safe to read UCBxRXBUF */ if (--i2c[0].length) { test = true; while (test) { test = false; while ((UCB0STAT & UCSCLLOW)!= UCSCLLOW ) ; // High for (i = 0; i < 7; i++) { __delay_cycles(15); // BR / 2 = 0x1E / 2 ; if ((UCB0STAT & UCSCLLOW)!= UCSCLLOW) { // Low test = true; break; } } } *i2c[0].data = UCB0RXBUF; /* If only one byte left, prepare stop signal. */ if (i2c[0].length == 1) { UCB0CTL1 |= UCTXSTP; } i2c[0].data++; } else { *i2c[0].data = UCB0RXBUF; i2c[0].state = STATE_READY; } break; case USCI_I2C_UCTXIFG: /* TX interrupt. */ if (i2c[0].state == STATE_WRITING) { if (!i2c[0].slave_reg_written) { UCB0TXBUF = i2c[0].slave_reg; i2c[0].slave_reg_written = 1; } else if (i2c[0].length) { /* Send next byte, increment pointer. */ UCB0TXBUF = *(i2c[0].data); i2c[0].data++; i2c[0].length--; } else { UCB0CTL1 |= UCTXSTP; UCB0IFG &= ~UCTXIFG; i2c[0].state = STATE_READY; } } else if (i2c[0].state == STATE_READING) { if (!i2c[0].slave_reg_written) { UCB0TXBUF = i2c[0].slave_reg; i2c[0].slave_reg_written = 1; } else { /* Repeated start, switch to RX mode. */ UCB0CTL1 &= ~UCTR; UCB0CTL1 |= UCTXSTT; /* If single byte, prepare stop signal immediately. */ if (i2c[0].length == 1) { /* Well, not IMMEDIATELY. First we need to make sure * the start signal got sent. */ while (UCB0CTL1 & UCTXSTT) ; UCB0CTL1 |= UCTXSTP; } } } break; case USCI_I2C_UCALIFG: /* Arbitration lost interrupt. */ SNASSERT(33); break; default: break; } __bic_SR_register_on_exit(LPM0_bits); }