Tool/software: Code Composer Studio
I am writing a generic, polling-based I2C master RX/TX driver on the MSP430F5529LP evaluation board (Default Clock Rate). I have an Adafruit metro-mini (Arduino based) board functioning as a slave transmitter sending "Hello" when I request a read.
My write function works properly, but when I attempt to read, I experience strange behavior. The first byte read from RXBUF is garbage, however the the entire message is received in consecutive reads. If I step through the code, the first byte is no longer garbage, and I receive the entire message properly. This makes me think I am not checking for some IFG/CTL flag to be set properly after the start condition, and as a result have a timing issue. The baffling thing is if I read the RXBUF prior to issuing the start condition, all bytes are read correctly. I didn't see anything obvious in the User guide to make me think this is correct (Seems more like a Hack) so I am hoping you guys see my issue.
i2c::i2c(I2C_Type port, uint8_t clkDiv) { switch((int16_t)port) { case USCIB0: UCxxCTL1 = &UCB0CTL1; UCxxCTL0 = &UCB0CTL0; UCxxBR0 = &UCB0BR0; UCxxBR1 = &UCB0BR1; UCxxI2CSA = &UCB0I2CSA; UCxxIFG = &UCB0IFG; UCxxRXBUF = &UCB0RXBUF; UCxxTXBUF = &UCB0TXBUF; break; case USCIB1: UCxxCTL1 = &UCB1CTL1; UCxxCTL0 = &UCB1CTL0; UCxxBR0 = &UCB1BR0; UCxxBR1 = &UCB1BR1; UCxxI2CSA = &UCB1I2CSA; UCxxIFG = &UCB1IFG; UCxxRXBUF = &UCB1RXBUF; UCxxTXBUF = &UCB1TXBUF; break; default: return; } pinSetup(); *UCxxCTL1 |= UCSWRST; // Enable SW reset *UCxxCTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode *UCxxCTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset // *UCxxI2CSA = 0x04; *UCxxBR0 = clkDiv; // Apply Clock divider to SMCLK *UCxxBR1 = 0; *UCxxCTL1 &= ~UCSWRST; // Clear SW reset, resume operation *UCxxIE = 0; *UCxxIFG = 0; // Clear interrupt flags } bool i2c::start(bool isRead) { // Set the I2C r/w bit, Send start condition if(isRead == false) { *UCxxCTL1 |= UCTR|UCTXSTT; } else { *UCxxCTL1 |= UCTXSTT; *UCxxCTL1 &= ~UCTR; } return !((*UCxxIFG & UCNACKIFG) == UCNACKIFG); } bool i2c::stop(void) { // Wait for the Stop condition to be accepted uint16_t count = 5000; *UCxxCTL1 |= UCTXSTP; while ((*UCxxCTL1 & UCTXSTP)==UCTXSTP) { count--; if(count <= 0) return false; } return true; } uint8_t i2c::read(uint8_t address, uint8_t* data, uint8_t length, bool repeated) { // Holds number of bytes read uint8_t br = 0; // Assign the Slave Address *UCxxI2CSA = address; { // A junk byte is read if I don't clear the RXBUF uint8_t junk = *UCxxRXBUF; } // Issue Start Request if(start(true) == false) { // Regardless of repeated status, issue stop and terminate stop(); return br; } for(uint8_t idx = 0; idx < length; idx++) { int16_t counts=10; // Wait for previous rx to complete. while (!(*UCxxIFG & UCRXIFG)) { _delay_cycles(100); counts--; if(counts <= 0) { // Regardless of repeated status, issue stop and terminate stop(); return 0; } } data[br++] = *UCxxRXBUF; } // Calling function will issue a repeated start, don't issue a STOP if(repeated == false) stop(); return br; }