Hi all,
I'd like to detect a new I2C device that is either connected or disconnected to a running code on MSP430G2553 (without program being stuck).
I have a list of just 16 addresses (devices) that can be connected to that I2C so it would be nice to have a scanner that detects what is connected and reads it. In case of disconnection, it would just go further without being stuck.
1. What would be the best way to do it?
2. Which register is the best to check to make sure I2C routine does not get stuck and it countinues in the main program avoiding reading I2C when device is not connected.
I'm using an I2C rutine (written by TI employee) and when you have a I2C device hooked to MSP430G2553 and you disconnected it while main program is running, the whole MSP430 get stuck.
Can I modify this routine to detect connection of disconnection of I2C device? I'm interested in any help, ideas.
Thanks, Daniel
Routine:
/******************************************************************************* * USCI_I2C.c Set's up the MSP430 uC USCI in I2C mode. * * * * Author: William Goh * * * * Revision Date: May 2011 * * * * Revision Level: 00.01 * * * * For Support: https://e2e.ti.com/support/development_tools/mavrk/default.aspx* * * ******************************************************************************** * Copyright © 2009-2010 Texas Instruments Incorporated - http://www.ti.com/ * ******************************************************************************** /******************************************************************************* * Included Headers * *******************************************************************************/ #include "USCI_I2C.h" // Definition Files for USCI I2C module /******************************************************************************* * Prototypes * *******************************************************************************/ // I2C write init void I2CWriteInit(void); // I2C read init void I2CReadInit(void); /******************************************************************************* * External Variables * *******************************************************************************/ /******************************************************************************* * Global Variables * *******************************************************************************/ // Transmit size pointter int PtrTransmit; // I2C transmit buffer array unsigned char I2CBufferArray[5]; // I2C receive buffer unsigned char I2CBuffer; unsigned int I2C_Read (unsigned char Word_Byte_mode, unsigned char Slave_Address, unsigned char Register_Address) { // Variable for transmitted data unsigned int MST_Data = 0; // Wait until I2C module has finished all operations while (UCB0STAT & UCBUSY); IE1 &= ~WDTIE; // DISABLE WDT FOR I2C COMMUNICATION P1IE &= ~BIT5; // Set slave address UCB0I2CSA = Slave_Address; // Set register address I2CBufferArray[0] = Register_Address; // set I2CBufferArray Pointer PtrTransmit = 0; // Configure Write Address first I2CWriteInit(); // Start condition generation => I2C communication is started UCB0CTL1 |= UCTXSTT; // Enable interrupts without entering LPM0. __bis_SR_register(GIE); // Wait till bus is free. while (UCB0STAT & UCBUSY); // Configure Read Data byte I2CReadInit(); // I2C restart condition UCB0CTL1 |= UCTXSTT; // Wait till Start condition sent while(UCB0CTL1 & UCTXSTT); // If sending a byte, send stop bit immediately if (Word_Byte_mode == I2C_BYTE) { // I2C stop condition UCB0CTL1 |= UCTXSTP; } // Enter LPM0 w/ interrupts __bis_SR_register(LPM0_bits + GIE); // Receive the first byte MST_Data = I2CBuffer; // If word mode, receive another byte if (Word_Byte_mode == I2C_WORD) { // I2C stop condition UCB0CTL1 |= UCTXSTP; // Enter LPM0 w/ interrupts __bis_SR_register(LPM0_bits + GIE); // Shift Master data MST_Data <<= 8; // Load data byte MST_Data |= I2CBuffer; } // Ensure stop condition got sent while(UCB0CTL1 & UCTXSTP); IE1 |= WDTIE; P1IE |= BIT5; // Return word return MST_Data; } void I2C_Write (unsigned char Word_Byte_mode, unsigned char Slave_Address, unsigned char Register_Address, unsigned int Register_Data) { // wait until I2C module has finished all operations. while (UCB0STAT & UCBUSY); IE1 &= ~WDTIE; // DISABLE WDT FOR I2C COMMUNICATION P1IE &= ~BIT5; // Set slave address UCB0I2CSA = Slave_Address; if (Word_Byte_mode == I2C_BYTE) { // If byte mode, write only 1 byte // Set register address. I2CBufferArray[1] = Register_Address; // Data to be written I2CBufferArray[0] = (unsigned char) (Register_Data & 0x00FF); // set I2CBufferArray size PtrTransmit = 1; } else { // If word mode, write 2 bytes // Set register address. I2CBufferArray[2] = Register_Address; // High nibble data to be written I2CBufferArray[1] = Register_Data >> 8; // Lower nibble data to be written I2CBufferArray[0] = Register_Data & 0xFF; // set I2CBufferArray size PtrTransmit = 2; } // start condition generation I2CWriteInit(); // => I2C communication is started UCB0CTL1 |= UCTXSTT; // Enter LPM0 w/ interrupts __bis_SR_register(LPM0_bits + GIE); // I2C stop condition UCB0CTL1 |= UCTXSTP; // Ensure stop condition got sents while(UCB0CTL1 & UCTXSTP); IE1 |= WDTIE; // DISABLE WDT FOR I2C COMMUNICATION P1IE |= BIT5; } /*----------------------------------------------------------------------------*/ // Description: // Initialization of the I2C Module for Write operation. /*----------------------------------------------------------------------------*/ void I2CWriteInit(void) { // UCTR=1 => Transmit Mode (R/W bit = 0) UCB0CTL1 |= UCTR; IFG2 &= ~UCB0TXIFG; // disable Receive ready interrupt IE2 &= ~UCB0RXIE; // enable Transmit ready interrupt IE2 |= UCB0TXIE; } /*----------------------------------------------------------------------------*/ // Description: // Initialization of the I2C Module for Read operation. /*----------------------------------------------------------------------------*/ void I2CReadInit(void) { // UCTR=0 => Receive Mode (R/W bit = 1) UCB0CTL1 &= ~UCTR; IFG2 &= ~UCB0RXIFG; // disable Transmit ready interrupt IE2 &= ~UCB0TXIE; // enable Receive ready interrupt IE2 |= UCB0RXIE; } /******************************************************************************* * USI interrupt service routine used for I2C State Macine * *******************************************************************************/ /* Transmit Register in Device Start 7 bit Address W ACK Device Address Register Address _ _______________________ _ _ ___________________________ ___________________________ _ _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | SCL |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| Followed by either Transmit of Data to the Register: Device High Byte Device Low Byte ___________________________ ___________________________ _ _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ SCL |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| or Receive Data from the Register: Re-Start 7 bit Address R ACK Device High Byte Device Low Byte _ _______________________ _ _ ___________________________ ___________________________ _ _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | SCL |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| */ /* * USCI_B0 I2C Transmit ISR. Enable USCI_B0 I2C transmit interrupt and set USCIAB0TX_ISR as the interrupt handler. * Then set the transmit interrupt to Manual on interrupt return. */ unsigned short USCIAB0TX_ISR (void) { // Load TX buffer UCB0TXBUF = I2CBufferArray[PtrTransmit]; // Decrement TX byte counter PtrTransmit--; if(PtrTransmit < 0) { // Wait until the last byte transmittted before exiting while(!(IFG2 & UCB0TXIFG)); // disable interrupts. IE2 &= ~UCB0TXIE; // Clear USCI_B0 TX int flag IFG2 &= ~UCB0TXIFG; // Exit LPM0 return (LPM0_bits); } return 0; } /* * USCI_B0 I2C Receive ISR. Enable USCI_B0 I2C receive interrupt and set USCIAB0RX_ISR as the interrupt handler. * Then set the receive interrupt to Active on interrupt return. */ void USCIAB0RX_ISR (void) { // store received data in buffer I2CBuffer = UCB0RXBUF; }
...just for a reference....here is the HEADER file USCI_I2C.h
/******************************************************************************* * Included Headers * *******************************************************************************/ #include <msp430.h> // Definition Files for the MSP430 /******************************************************************************* * Definitions * *******************************************************************************/ /************************** I2C USIC Engine ***********************************/ #define I2C_SDA BIT7 // SDA on P1.7 #define I2C_SCL BIT6 // SCL on P1.6 #define I2C_WRITE 0x00 #define I2C_READ 0x01 #define I2C_BYTE 0x00 #define I2C_WORD 0x01 #define I2C_ACK 0x00 #define I2C_NAK 0x01 /******************************************************************************* * Prototypes * *******************************************************************************/ /************ System Configuration *************************/ void Set_I2C(void); /************ I2C Interface *******************************/ unsigned int I2C_Read (unsigned char, unsigned char, unsigned char); void I2C_Write (unsigned char, unsigned char, unsigned char, unsigned int);
...end.