__interrupt void USI_TXRX (void) { if (USICTL1 & USISTTIFG) // Start entry? { P1OUT |= 0x01; // LED on: sequence start I2C_State = 2; // Enter 1st state on start } switch(__even_in_range(I2C_State,14)) { case 0: // Idle, should not get here break; case 2: // RX Address USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, RX address USICTL1 &= ~USISTTIFG; // Clear start flag I2C_State = 4; // Go to next state: check address break; case 4: // Process Address and send (N)Ack if (USISRL & 0x01){ // If master read... SLV_Addr = 0x91; // Save R/W bit transmit = 1;} else{transmit = 0; SLV_Addr = 0x90;} USICTL0 |= USIOE; // SDA = output if (USISRL == SLV_Addr) // Address match? { USISRL = 0x00; // Send Ack P1OUT &= ~0x01; // LED off if (transmit == 0){ I2C_State = 6;} // Go to next state: RX data if (transmit == 1){ I2C_State = 10;} // Else go to next state: TX data } else { USISRL = 0xFF; // Send NAck P1OUT |= 0x01; // LED on: error I2C_State = 8; // next state: prep for next Start } USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit break; case 6: // Receive data byte Data_RX(); break; case 8:// Check Data & TX (N)Ack USICTL0 |= USIOE; // SDA = output if (Bytecount <= (Number_of_Bytes-2)) // If not last byte { USISRL = 0x00; // Send Ack I2C_State = 6; // Rcv another byte Bytecount++; USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit } else // Last Byte { USISRL = 0xFF; // Send NAck USICTL0 &= ~USIOE; // SDA = input SLV_Addr = 0x90; // Reset slave address I2C_State = 0; // Reset state machine Bytecount =0; // Reset counter for next TX/RX } break; case 10: // Send Data byte TX_Data(); break; case 12:// Receive Data (N)Ack USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack I2C_State = 14; // Go to next state: check (N)Ack break; case 14:// Process Data Ack/NAck if (USISRL & 0x01) // If Nack received... { USICTL0 &= ~USIOE; // SDA = input SLV_Addr = 0x90; // Reset slave address I2C_State = 0; // Reset state machine Bytecount = 0; // LPM0_EXIT; // Exit active for next transfer } else // Ack received { P1OUT &= ~0x01; // LED off TX_Data(); // TX next byte } break; } USICTL1 &= ~USIIFG; // Clear pending flags }
__interrupt void USI_TXRX (void){ switch(I2C_State){ case 0: // Generate Start Condition & send address to slave Bytecount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; USISRL = slave_i2c_address; // Send slave address + write first! USICNT = 8; // USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX if (USISRL & 0x01) // If Nack received... { // Send stop... USICTL0 |= USIOE; // SDA = output USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop } else { // Ack received, TX adress to slave... if (slave_address_sent == 1){ // Now, the slave will start sending data. // This should really only happen if // transmit == 0.. Data_RX(); } else{ // Send the slave address across. USICTL0 |= USIOE; // SDA = output USISRL = curr_reg_address; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX Bytecount++; I2C_State = 10; // next state: receive data (N)Ac } } break; case 5: // Generate repeated start condition USISRL = 0x00; // While clock is high, force SDA low. USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; USICTL0 |= USIOE; // make sure that the output is enabled. // Now send slave address. USISRL = slave_i2c_address + 1; // Send slave address + read. USICNT = 8; // Bit counter = 8, TX Address slave_address_sent = 1; // Set flag, so that data is sent in state 4. I2C_State = 2; // next state: rcv address (N)Ack break; case 6: // Send Data Ack/Nack bit USICTL0 |= USIOE; // SDA = output curr_output = USISRL; // grab output if (Bytecount <= number_of_bytes-2) { // If this is not the last byte USISRL = 0x00; // Send Ack I2C_State = 4; // Go to next state: data/rcv again Bytecount++; } else //last byte: send NACK { USISRL = 0xFF; // Send NAck I2C_State = 8; // stop condition } USICNT |= 0x01; // Bit counter = 1, send (N)Ack bit break; case 8: // Prep Stop Condition USICTL0 |= USIOE; // SDA = output USISRL = 0x00; USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop break; case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (Transmit == 1){ if (Bytecount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop USICNT |= 0x01; // set count=1 to trigger next state Bytecount++; }else{ Data_TX(); // TX byte } } else { // prepare a repeated start transmission. USICTL0 |= USIOE; USISRL = 0xFF; USICNT = 1; I2C_State = 5; } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt slave_address_sent = 0; // Reset flag LPM0_EXIT; // Exit active for next transfer break; } USICTL1 &= ~USIIFG; // Clear pending flag }