This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

I2C communication does not appear to be working correctly with Energia and CCS. How do I fix it?

Other Parts Discussed in Thread: ENERGIA, MSP430G2553

I've just done a fresh install of CCS 6.1.3.00034.

I've also just installed Energia 0101E0017.

I am attempting to use code from an Arduino project to detect I2C devices.  The code is quite simple:

void findAddress()
{
  for (int a = fromAddress; a < toAddress; a++)
  {
    Wire.beginTransmission(a);
    Wire.write(0);
    int endStatus = Wire.endTransmission();

    if (endStatus == 0)
    {
      Serial.print("Found device at: ");
      printHex(a, true);
    }
  }
}

In the Arduino environmnet, it would output the address of all I2C devices that were connected.  However, this basically says that every address is a device..

Anyway, I believe there is a bug fix somewhere with the Energia project.  It is quite frustrating that we have to go find and install code hacks in order to get Energia to run and play nicely with CCS...

Perhaps there could be some encouragement by TI or somebody with more clout than me to get the latest Energia release to work well with the MSP430G2553 Launchpad.

Please let me know if there is a known fix for this problem, as it is currently stalling my project and making me ask why CCS has Energia as a project type when Energia doesn't appear to work with TI MSP430G2553 Launchpad right out of the box...

Thanks, and sorry if my post has turned into a slight rant..  Just frustrated fighting the tools that are supposed to make my job as a developer easier... :-< 

  • Hi Curtis,

    Sorry to hear this is not working for you. The issue was fixed after the release of Energia 17. Energia 18 took a bit longer than expected but will be out shortly.

    With that said, it's easy to patch Energia 17 to make this work.

    1. Make sure that you are using pins 14 (SCL) and 15 (SDA). A change in the BoosterPack header standard was introduced a while back which I had to adopt in Energia. This meant that by default I2C would be on pins 7 and 8. The G2553 does not have a hardware I2C on those pins and thus we had to implement a software version. This software version is not performing as it should and I will be taking it out in the future to not further cause issues for Energia users with I2C not always working properly on those pins. To set the default I2C back to pins 14 and 15 you have to call Wire.setModule(0) in setup() before Wire.begin(). Please see the example Sketch below.
    2. I am sure you already did so but just a checkpoint, make sure that you have pull-ups on SCL/SDA.
    3. copy the attached files to you Energia installation under hardware/msp430/cores/msp430
    4. make sure you remove the jumper for LED2 (P1.6) next to S2.

    With that in place you should not be able to run the Sketch below and successfully scan the bus.

    Robert @ Energia

    #include <Wire.h>
    
    void setup()
    {
      Serial.begin(9600);
      Serial.println("Start!");
      
      Wire.setModule(0);
      Wire.begin();
    }
    
    void loop()
    {
      findAddress();
      delay(1000);
    }
    
    uint8_t fromAddress = 0;
    uint8_t toAddress = 127;
    
    void findAddress()
    {
      for (uint8_t a = fromAddress; a < toAddress; a++)
      {
        Wire.beginTransmission(a);
        int endStatus = Wire.endTransmission();
    
        if (endStatus == 0)
        {
          Serial.print("Found device at: 0x");
          Serial.println(a, HEX);
        }
      }
    }

  • I'm having trouble finding the 'attached' files... Where are they?
  • I really thought that I had attached them but must have forgotten. Sorry about that.

    twi.c
    /*
      ************************************************************************
      *	twi.c
      *
      *	Arduino core files for MSP430
      *		Copyright (c) 2012 Robert Wessels. All right reserved.
      *
      *
      ***********************************************************************
      Derived from:
      twi.c - TWI/I2C library for Wiring & Arduino
      Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
    
      This library is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
      License as published by the Free Software Foundation; either
      version 2.1 of the License, or (at your option) any later version.
    
      This library is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Lesser General Public License for more details.
    
      You should have received a copy of the GNU Lesser General Public
      License along with this library; if not, write to the Free Software
      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    */
    
    #include <math.h>
    #include <stdlib.h>
    #include "Energia.h"  // for digitalWrite
     
    #ifndef cbi
    #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
    #endif
    
    #ifndef sbi
    #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
    #endif
    
    #include "wiring_private.h"
    #include "pins_energia.h"
    #include "twi.h"
    #include "usci_isr_handler.h"
    #if DEFAULT_I2C == -1 // SW I2C implementation on default port
    #include "twi_sw.h"   // software I2C interface
    #endif
    
    static volatile uint8_t twi_state;
    static volatile uint8_t twi_sendStop;           // should the transaction end with a stop
    static volatile uint8_t twi_inRepStart;         // in the middle of a repeated start
    
    static void (*twi_onSlaveTransmit)(void);
    static void (*twi_onSlaveReceive)(uint8_t*, int);
    
    static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
    static volatile uint8_t twi_masterBufferIndex;
    static uint8_t twi_masterBufferLength;
    
    static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
    static volatile uint8_t twi_txBufferIndex;
    static volatile uint8_t twi_txBufferLength;
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) \
     || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B0__)
    static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
    static volatile uint8_t twi_rxBufferIndex;
    #endif
    
    static volatile uint8_t twi_error;
    
    #if defined(__MSP430_HAS_USI__)
    static uint8_t twi_slarw;
    static uint8_t twi_my_addr;
    #endif
    
    
    
    
    #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    
    #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__)
    #define UCB0_BASE ((uint16_t)&UCB0CTLW0)
    #endif
    #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    #define UCB1_BASE ((uint16_t)&UCB1CTLW0)
    #endif
      
    #define UCBxCTLW0     (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0)  - UCB0_BASE))))
    #define UCBxCTLW1     (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW1)  - UCB0_BASE))))
    #define UCBxCTL0      (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0)+1- UCB0_BASE))))
    #define UCBxCTL1      (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTLW0)  - UCB0_BASE))))
    #define UCBxBRW       (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW)    - UCB0_BASE))))
    #define UCBxBR0       (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW)    - UCB0_BASE))))
    #define UCBxBR1       (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BRW)+1  - UCB0_BASE))))
    #define UCBxMCTL      (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCTL)   - UCB0_BASE))))
    #define UCBxMCTLW     (*((volatile uint16_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCTLW)  - UCB0_BASE))))
    #define UCBxSTAT      (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0STAT)   - UCB0_BASE))))
    #define UCBxTBCNT     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TBCNT)  - UCB0_BASE))))
    #define UCBxRXBUF     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0RXBUF)  - UCB0_BASE))))
    #define UCBxTXBUF     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TXBUF)  - UCB0_BASE))))
    #define UCBxABCTL     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ABCTL)  - UCB0_BASE))))
    #define UCBxIRCTL     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRCTL)  - UCB0_BASE))))
    #define UCBxIRTCTL    (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRTCTL) - UCB0_BASE))))
    #define UCBxIRRCTL    (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IRRCTL0 - UCB0_BASE))))
    #define UCBxICTL      (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL)   - UCB0_BASE))))
    #define UCBxI2COA     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA)  - UCB0_BASE))))
    #define UCBxI2COA0    (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA0) - UCB0_BASE))))
    #define UCBxI2CSA     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CSA)  - UCB0_BASE))))
    #if defined(UCB0ICTL_)
    #define UCBxIE        (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL)   - UCB0_BASE))))
    #define UCBxIFG       (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL)+1 - UCB0_BASE))))
    #else
    #define UCBxIE        (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IE)     - UCB0_BASE))))
    #define UCBxIFG       (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IFG)    - UCB0_BASE))))
    #endif
    #define UCBxI2CIE     (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CIE)  - UCB0_BASE))))
    #define UCBxIV        (*((volatile uint8_t  *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0IV)     - UCB0_BASE))))
    
    #else // #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    
    #if defined(__MSP430_HAS_USCI__)
    #define UCB0_BASE ((uint16_t)&UCB0CTL0)
    #define UCB1_BASE ((uint16_t)&UCB1CTL0)
    
    #define UCBxCTL0      (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTL0)   - UCB0_BASE))))
    #define UCBxCTL1      (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0CTL1)   - UCB0_BASE))))
    #define UCBxBR0       (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BR0)    - UCB0_BASE))))
    #define UCBxBR1       (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0BR1)    - UCB0_BASE))))
    //#define UCBxMCTL      (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0MCT)   - UCB0_BASE))))
    #define UCBxSTAT      (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0STAT)   - UCB0_BASE))))
    #define UCBxRXBUF     (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0RXBUF)  - UCB0_BASE))))
    #define UCBxTXBUF     (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0TXBUF)  - UCB0_BASE))))
    //#define UCBxICTL      (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0ICTL)   - UCB0_BASE))))
    #define UCBxI2COA     (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2COA)  - UCB0_BASE))))
    #define UCBxI2CSA     (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CSA)  - UCB0_BASE))))
    
    #define UCxIE         UC0IE
    #define UCBxI2CIE     (*((volatile uint8_t *)((uint16_t)(I2C_baseAddress + ((uint16_t)&UCB0I2CIE)  - UCB0_BASE))))
    #define UCxIFG        UC0IFG
    #if defined(UCB1RXIE)
    #define UCBxRXIE      UCB0RXIE  ? (I2C_baseAddress == UCB0_BASE) : UCB1RXIE
    #define UCBxRXIFG     UCB0RXIFG ? (I2C_baseAddress == UCB0_BASE) : UCB1RXIFG
    #else
    #define UCBxRXIE      UCB0RXIE
    #define UCBxRXIFG     UCB0RXIFG
    #endif
    #if defined(UCB1TXIE)
    #define UCBxTXIE      UCB0TXIE  ? (I2C_baseAddress == UCB0_BASE) : UCB1TXIE
    #define UCBxTXIFG     UCB0TXIFG ? (I2C_baseAddress == UCB0_BASE) : UCB1TXIFG
    #else
    #define UCBxTXIE      UCB0TXIE
    #define UCBxTXIFG     UCB0TXIFG
    #endif
    
    #endif //#if defined(__MSP430_HAS_USCI__)
    #endif // #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    
    
    #if DEFAULT_I2C == -1 // SW I2C implementation on default port
    uint16_t I2C_baseAddress = -1;
    #endif
    #if DEFAULT_I2C == 0
    uint16_t I2C_baseAddress = UCB0_BASE;
    #endif
    #if DEFAULT_I2C == 1
    uint16_t I2C_baseAddress = UCB1_BASE;
    #endif
    
    
    /*
     * Function twi_setModule
     * Desc     Selects the I2C module to use
     * Input    Module instance
     * Output   none
     */
    void twi_setModule(uint8_t _i2cModule)
    {
    #if DEFAULT_I2C == -1 // SW I2C implementation on default port
    	if (_i2cModule == -1)
    	{
    		I2C_baseAddress = -1;
    	}
    #endif
    	if (_i2cModule == 0)
    	{
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__)
    		I2C_baseAddress = UCB0_BASE;
    #endif
    	}
    	if (_i2cModule == 1)
    	{
    #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    		I2C_baseAddress = UCB1_BASE;
    #endif
    	}
    }
    
    /*
     * Function twi_init_port
     * Desc     initialises the port pins
     * Input    none
     * Output   none
     */
    static void twi_init_port(void)
    {
    #if DEFAULT_I2C == -1 // SW I2C implementation on default port
    	if (I2C_baseAddress == -1)
    	{
    		//pinMode_int(TWISDA1, TWISDA1_SET_MODE);
    		//pinMode_int(TWISCL1, TWISCL1_SET_MODE);
    		i2c_sw_init();
    		return;
    	}
    #endif
    #if defined(__MSP430_HAS_USCI__)
    	if (I2C_baseAddress == UCB0_BASE)
    	{
    		pinMode_int(TWISDA0, TWISDA0_SET_MODE);
    		pinMode_int(TWISCL0, TWISCL0_SET_MODE);
    		return;
    	}
    #endif
    #if defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_EUSCI_B0__)
    	if (I2C_baseAddress == UCB0_BASE)
    	{
    		/* Set pins to I2C mode */
    		pinMode_int(TWISDA0, INPUT_PULLUP);
    		if (digitalRead(TWISDA0) == 0){ // toggle SCL if SDA is low at startup
    			pinMode_int(TWISCL0, INPUT_PULLUP);
    			digitalWrite(TWISCL0, LOW);
    			pinMode(TWISCL0, OUTPUT);
    			pinMode_int(TWISCL0, INPUT_PULLUP);
    		}
    #if defined(__MSP430_HAS_USCI_B0__)
    		if ((TWISDA0_SET_MODE & INPUT_PULLUP) == 0) {
    			pinMode(TWISDA0, INPUT);          // some device do not allow the pull up to be enabled
    			pinMode(TWISCL0, INPUT);
    		}
    #endif
    		pinMode_int(TWISDA0, TWISDA0_SET_MODE);
    		pinMode_int(TWISCL0, TWISCL0_SET_MODE);
    	}
    #endif
    #if defined(__MSP430_HAS_USCI_B1__) || defined(__MSP430_HAS_EUSCI_B1__)
    	if (I2C_baseAddress == UCB1_BASE)
    	{
    		/* Set pins to I2C mode */
    		pinMode_int(TWISDA1, INPUT_PULLUP);
    		if (digitalRead(TWISDA1) == 0){ // toggle SCL if SDA is low at startup
    			pinMode_int(TWISCL1, INPUT_PULLUP);
    			digitalWrite(TWISCL1, LOW);
    			pinMode(TWISCL1, OUTPUT);
    			pinMode_int(TWISCL1, INPUT_PULLUP);
    		}
    #if defined(__MSP430_HAS_USCI_B1__)
    		if ((TWISDA1_SET_MODE & INPUT_PULLUP) == 0) {
    			pinMode(TWISDA1, INPUT);          // some device do not allow the pull up to be enabled
    			pinMode(TWISCL1, INPUT);
    		}
    #endif
    		pinMode_int(TWISDA1, TWISDA1_SET_MODE);
    		pinMode_int(TWISCL1, TWISCL1_SET_MODE);
    	}
    #endif
    }
    
    /*
     * Function twi_init
     * Desc     readys twi pins and sets twi bitrate
     * Input    none
     * Output   none
     */
    void twi_init(void)
    {
    	// initialize state
    	twi_state = TWI_IDLE;
    	twi_sendStop = true;		// default value
    	twi_inRepStart = false;
    
    #if DEFAULT_I2C == -1 // SW I2C implementation on default port
    	if (I2C_baseAddress == -1)
    	{
    		twi_init_port();
    		return;
    	}
    #endif
    
    #if defined(__MSP430_HAS_USI__)
    
    	/* 100 KHz for all */
    #if (F_CPU >= 16000000L) || (F_CPU >= 12000000L)
    	USICKCTL = USIDIV_7;
    #elif defined(CALBC1_8MHZ_) && (F_CPU >= 8000000L)
    	USICKCTL = USIDIV_6;
    #elif defined(CALBC1_1MHZ_) && (F_CPU >= 1000000L)
    	USICKCTL = USIDIV_3;
    #endif
    	/* Enable USI I2C mode. */
    	USICTL1 = USII2C;
    	/* SDA/SCL port enable and hold in reset */
    	USICTL0 = (USIPE6 | USIPE7 | USISWRST);
    	/* SMCLK and SCL inactive state is high */
    	USICKCTL |= (USISSEL_2 | USICKPL);
    	/* Disable automatic clear control */
    	USICNT |= USIIFGCC;
    	/* Enable USI */
    	USICTL0 &= ~USISWRST;
    	/* Counter interrupt enable */
    	USICTL1 |= USIIE;
    #endif
    
    #if defined(__MSP430_HAS_USCI__) \
     || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
    
        /* Calling this dummy function prevents the linker
         * from stripping the USCI interupt vectors.*/ 
        usci_isr_install();
    	
    	twi_init_port();
    
        //Disable the USCI module and clears the other bits of control register
        UCBxCTL1 = UCSWRST;
    
         /*
         * Configure as I2C Slave.
         * UCMODE_3 = I2C mode
         * UCSYNC = Synchronous mode
         * UCCLK = SMCLK
         */
        UCBxCTL0 = UCMODE_3 | UCSYNC;
        /*
         * Compute the clock divider that achieves less than or
         * equal to 100kHz.  The numerator is biased to favor a larger
         * clock divider so that the resulting clock is always less than or equal
         * to the desired clock, never greater.
         */
        UCBxBR0 = (unsigned char)((F_CPU / TWI_FREQ) & 0xFF);
        UCBxBR1 = (unsigned char)((F_CPU / TWI_FREQ) >> 8);
    
        UCBxCTL1 &= ~(UCSWRST);
    
    #if defined(__MSP430_HAS_USCI__)
        /* Set I2C state change interrupt mask */
        UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTTIE|UCSTPIE);
        /* Enable state change and TX/RX interrupts */
        UCxIE |= UCBxRXIE | UCBxTXIE;
    #else
        /* Set I2C state change interrupt mask and TX/RX interrupts */
        UCBxIE |= (UCALIE|UCNACKIE|UCSTTIE|UCSTPIE|UCRXIE|UCTXIE);
    #endif
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
    	twi_init_port();
    	
        //Disable the USCI module and clears the other bits of control register
        UCBxCTLW0 = UCSWRST;
    
        //Configure Automatic STOP condition generation
        UCBxCTLW1 &= ~UCASTP_3;
    
        /*
         * Configure as I2C master mode.
         * UCMODE_3 = I2C mode
         * UCSYNC = Synchronous mode (read/write 1 for eUSCI_B)
         * UCCLK = SMCLK
         */
        UCBxCTLW0 = UCMODE_3 | UCSSEL__SMCLK | UCSYNC | UCSWRST;
    
        /*
         * Compute the clock divider that achieves the fastest speed less than or
         * equal to the desired speed.  The numerator is biased to favor a larger
         * clock divider so that the resulting clock is always less than or equal
         * to the desired clock, never greater.
         */
        UCBxBRW = (unsigned short)(F_CPU / 400000);
        UCBxCTLW0 &= ~(UCSWRST);
        UCBxIE |= (UCRXIE0|UCTXIE0|UCSTTIE|UCSTPIE); // Enable I2C interrupts
    #endif
    }
    
    /*
     * Function twi_setAddress
     * Desc     sets slave address and enables interrupt
     * Input    none
     * Output   none
     */
    void twi_setAddress(uint8_t address)
    {
    #if defined(__MSP430_HAS_USI__)
    	twi_my_addr = address << 1;
    #endif
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
    	/* UCGCEN = respond to general Call */
    	UCBxI2COA = (address | UCGCEN);
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__)
    	/* UCGCEN = respond to general Call */
    	UCBxI2COA0 = (address | UCOAEN | UCGCEN);
    #endif
    }
    
    /*
     * Function twi_readFrom
     * Desc     attempts to become twi bus master and read a
     *          series of bytes from a device on the bus
     * Input    address: 7bit i2c device address
     *          data: pointer to byte array
     *          length: number of bytes to read into array
     * Output   number of bytes read
     */
    uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
    {
    	uint8_t i;
    
    #if (DEFAULT_I2C == -1)
    	if (I2C_baseAddress == -1)
    	{
    		i2c_sw_read(address, length, data, sendStop);
    		return length;
    	}
    #endif
    #if defined(__MSP430_HAS_USI__)
    	/* Disable START condition interrupt */
    	USICTL1 &= ~USISTTIE;
    	/* I2C master mode */
    	USICTL0 |= USIMST;
    #endif
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
        UCBxCTL1 = UCSWRST;                      // Enable SW reset
        UCBxCTL1 |= (UCSSEL_2);                  // I2C Master, synchronous mode
        UCBxCTL0 |= (UCMST | UCMODE_3 | UCSYNC); // I2C Master, synchronous mode
        UCBxCTL1 &= ~(UCTR);                     // Configure in receive mode
        UCBxI2CSA = address;                     // Set Slave Address
        UCBxCTL1 &= ~UCSWRST;                    // Clear SW reset, resume operation
    #if defined(__MSP430_HAS_USCI__)
        UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTPIE);  // Enable I2C interrupts
        UCxIE |= (UCBxRXIE | UCBxTXIE);          // Enable I2C interrupts
    #else
        UCBxIE |= (UCALIE|UCNACKIE|UCSTPIE|UCRXIE|UCTXIE);  // Enable I2C interrupts
    #endif
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
        UCBxCTLW0 |= UCSWRST;                     // Enable SW reset
        UCBxCTLW0 |= (UCMST);                     // I2C Master, synchronous mode
        UCBxCTLW0 &= ~(UCTR);                     // Configure in receive mode
        UCBxI2CSA = address;                      // Set Slave Address
        UCBxTBCNT = length;                       // set number of bytes to transmit
        UCBxCTLW0 &= ~UCSWRST;                    // Clear SW reset, resume operation
        UCBxIE |= (UCRXIE0|UCALIE|UCNACKIE|UCSTTIE|UCSTPIE); // Enable I2C interrupts
    #endif
    	// ensure data will fit into buffer
    	if(TWI_BUFFER_LENGTH < length){
    		return 0;
    	}
    
    	// initialize buffer iteration vars
    	twi_masterBufferIndex = 0;
    	twi_masterBufferLength = length-1;  // This is not intuitive, read on...
    	// On receive, the previously configured ACK/NACK setting is transmitted in
    	// response to the received byte before the interrupt is signalled.
    	// Therefor we must actually set NACK when the _next_ to last byte is
    	// received, causing that NACK to be sent in response to receiving the last
    	// expected byte of data.
    
    #if defined(__MSP430_HAS_USI__)
    	/* build sla+w, slave device address + w bit */
    	twi_slarw = 1;
    	twi_slarw |= address << 1;
    
    	// send start condition
    	twi_state = TWI_SND_START;
    	// this will trigger an interrupt kicking off the state machine in the isr
    	USICTL1 |= USIIFG;
    #endif
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
        twi_state =  TWI_MRX;                     // Master receive mode
        UCBxCTL1 |= UCTXSTT;                      // I2C start condition
    
        if(length == 1) {                         // When only receiving 1 byte..
            while(UCBxCTL1 & UCTXSTT);            // Wait for start bit to be sent
            UCBxCTL1 |= UCTXSTP;                  // Send I2C stop condition after recv
        }
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
        twi_state =  TWI_MRX;                     // Master receive mode
        //while (UCBxCTLW0 & UCTXSTP);              // Ensure stop condition got sent
        UCBxCTLW0 |= UCTXSTT;                     // I2C start condition
    #endif
    
    	/* Wait in low power mode for read operation to complete */
    	while(twi_state != TWI_IDLE){
    		__bis_SR_register(LPM0_bits);
    	}
    
    	if (twi_masterBufferIndex < length)
    		length = twi_masterBufferIndex;
    
    	for(i = 0; i < length; ++i){
    		data[i] = twi_masterBuffer[i];
    	}
    
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
    	/* Ensure stop condition got sent before we exit. */
    	while (UCBxCTL1 & UCTXSTP);
    #endif
    	return length;
    }
    
    /*
     * Function twi_writeTo
     * Desc     attempts to become twi bus master and write a
     *          series of bytes to a device on the bus
     * Input    address: 7bit i2c device address
     *          data: pointer to byte array
     *          length: number of bytes in array
     *          wait: boolean indicating to wait for write or not
     * Output   0 .. success
     *          1 .. length to long for buffer
     *          2 .. address send, NACK received
     *          3 .. data send, NACK received
     *          4 .. other twi error (lost bus arbitration, bus error, ..)
     */
    uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
    {
    	uint8_t i;
    	twi_error = TWI_ERRROR_NO_ERROR;
    	twi_sendStop = sendStop;
    
    #if (DEFAULT_I2C == -1)	
    	if (I2C_baseAddress == -1)
    	{
    		return (i2c_sw_write(address, length, data, sendStop));
    	}
    #endif
    #if defined(__MSP430_HAS_USI__)
    	/* Disable START condition interrupt */
    	USICTL1 &= ~USISTTIE;
    	/* I2C master mode */
    	USICTL0 |= USIMST;
    #endif
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
        UCBxCTL1 = UCSWRST;                      // Enable SW reset
        UCBxCTL1 |= UCSSEL_2;                    // SMCLK
        UCBxCTL0 |= (UCMST | UCMODE_3 | UCSYNC); // I2C Master, synchronous mode
        UCBxCTL1 |= UCTR;                        // Configure in transmit mode
        UCBxI2CSA = address;                     // Set Slave Address
        UCBxCTL1 &= ~UCSWRST;                    // Clear SW reset, resume operation
    #if defined(__MSP430_HAS_USCI__)
        UCBxI2CIE |= (UCALIE|UCNACKIE|UCSTPIE);  // Enable I2C interrupts
        UCxIE |= UCBxTXIE;                     // Enable I2C interrupts
    #else
        UCBxIE |= (UCALIE|UCNACKIE|UCSTPIE|UCTXIE);  // Enable I2C interrupts
    #endif
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
        UCBxCTLW0 |= UCSWRST;                     // Enable SW reset
        UCBxCTLW0 |= (UCMST | UCTR);              //  I2C Master, transmit mode
        UCBxI2CSA = address;                      // Set Slave Address
        UCBxTBCNT = length;                       // set number of bytes to transmit
    	if((sendStop) && (length > 0)) {
    		UCBxCTLW1 |= UCASTP_2;                // do generate Stop after last Byte to send
    	} else {
    		UCBxCTLW1 &= ~UCASTP_2;               // do not generate Stop
    	}
        UCBxCTLW0 &= ~UCSWRST;                    // Clear SW reset, resume operation
        UCBxIE |= (UCRXIE|UCTXIE0|UCALIE|UCNACKIE|UCSTPIE); // Enable I2C interrupts
    #endif
    
    	/* Ensure data will fit into buffer */
    	if(length > TWI_BUFFER_LENGTH){
    		return TWI_ERROR_BUF_TO_LONG;
    	}
    
    
    	/* initialize buffer iteration vars */
    	twi_masterBufferIndex = 0;
    	twi_masterBufferLength = length;
    
    	for(i = 0; i < length; ++i){
    		twi_masterBuffer[i] = data[i];
    	}
    
    #if defined(__MSP430_HAS_USI__)
    	/* build sla+w, slave device address + w bit */
    	twi_slarw = 0;
    	twi_slarw |= address << 1;
    	
    	twi_state = TWI_SND_START;
    	/* This will trigger an interrupt kicking off the state machine in the isr */
    	USICTL1 |= USIIFG;
    #endif
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
        twi_state =  TWI_MTX;                     // Master Transmit mode
        UCBxCTL1 |= UCTXSTT;                      // I2C start condition
    #endif
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
        twi_state =  TWI_MTX;                     // Master Transmit mode
        //while (UCBxCTLW0 & UCTXSTP);           // Ensure stop condition got sent
        UCBxCTLW0 |= UCTXSTT;                  // I2C start condition
    #endif
    
    	/* Wait for the transaction to complete */
    	while(twi_state != TWI_IDLE) {
    		__bis_SR_register(LPM0_bits);
    	}
    
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
    	/* Ensure stop/start condition got sent before we exit. */
    	if(sendStop)
    	{
    		while (UCBxCTL1 & UCTXSTP);	// end with stop condition
    	} else {
    		while (UCBxCTL1 & UCTXSTT);	// end with (re)start condition
    	}
    #endif
    
    	return twi_error;
    }
    
    /*
     * Function twi_transmit
     * Desc     fills slave tx buffer with data
     *          must be called in slave tx event callback
     * Input    data: pointer to byte array
     *          length: number of bytes in array
     * Output   1 length too long for buffer
     *          2 not slave transmitter
     *          0 ok
     */
    uint8_t twi_transmit(const uint8_t* data, uint8_t length)
    {
      uint8_t i;
    
      twi_state =  TWI_STX;                     // Slave transmit mode
      
      // ensure data will fit into buffer
      if(TWI_BUFFER_LENGTH < length){
        return 1;
      }
      // set length and copy data into tx buffer
      twi_txBufferLength = length;
      for(i = 0; i < length; ++i){
        twi_txBuffer[i] = data[i];
      }
    
      return 0;
    }
    
    /*
     * Function twi_attachSlaveRxEvent
     * Desc     sets function called before a slave read operation
     * Input    function: callback function to use
     * Output   none
     */
    void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
    {
      twi_onSlaveReceive = function;
    }
    
    /*
     * Function twi_attachSlaveTxEvent
     * Desc     sets function called before a slave write operation
     * Input    function: callback function to use
     * Output   none
     */
    void twi_attachSlaveTxEvent( void (*function)(void) )
    {
      twi_onSlaveTransmit = function;
    }
    
    #if defined(__MSP430_HAS_USI__)
    void send_start()
    {
    	USISRL = 0x00;
    	USICTL0 |= USIGE+USIOE;
    	USICTL0 &= ~USIGE;
    	USISRL = twi_slarw;
    	USICNT = (USICNT & 0xE0) + 0x08;
    }
    #endif
    
    #if defined(__MSP430_HAS_USI__)
    __attribute__((interrupt(USI_VECTOR)))
    void USI_ISR(void)
    {
    	if (!(USICTL0 & USIMST) && (USICTL1 & USISTTIFG)) {
    		twi_state = TWI_SL_START;
    	}
    	
    	switch(twi_state){
    	/* Master transmit / receive */
    	case TWI_SND_START:
    		send_start();
    		twi_state = TWI_PREP_SLA_ADDR_ACK;
    		break;
    	case TWI_PREP_SLA_ADDR_ACK: // reveive (N)ACK
    		USICTL0 &= ~USIOE; // SDA = input
    		USICNT |= 0x01; // Bit counter=1
    		twi_state = TWI_MT_PROC_ADDR_ACK;
    		break;
    	case TWI_MT_PROC_ADDR_ACK:
    		if (USISRL & 0x01) {
    			twi_error = TWI_ERROR_ADDR_NACK;
    			USICTL0 |= USIOE;
    			USISRL = 0x00;
    			USICNT |=  0x01;
    			twi_state = TWI_EXIT;
    			break;
    		}
    
    		if(twi_slarw & 1)
    			goto mtre;
    		else
    			goto mtpd;
    
    		break;
    	/* Prepare to receive data (N)ACK */
    	case TWI_MT_PREP_DATA_ACK:
    		/* SDA = input */
    		USICTL0 &= ~USIOE;
    		/* Bit counter = 1 */
    		USICNT |= 0x01;
    		twi_state = TWI_MT_PROC_DATA_ACK;
    		break;
    	case TWI_MT_PROC_DATA_ACK:
    mtpd:
    		if (USISRL & 0x01) {
    			twi_error = TWI_ERROR_DATA_NACK;
    			USICTL0 |= USIOE;
    			USISRL = 0x00;
    			USICNT |=  0x01;
    			twi_state = TWI_EXIT;
    			break;
    		}
    
    		if(twi_masterBufferIndex == twi_masterBufferLength) {
    			USICTL0 |= USIOE;
    			USISRL = 0x00;
    			USICNT |=  0x01;
    			twi_state = TWI_EXIT;
    			break;
    		}
    
    		USICTL0 |= USIOE;
    		USISRL = twi_masterBuffer[twi_masterBufferIndex++];
    		USICNT |=  0x08;
    		twi_state = TWI_MT_PREP_DATA_ACK;
    		break;
    	// Master receiver
    mtre:
    	case TWI_MR_PREP_DATA_RECV:
    		/* SDA input */
    		USICTL0 &= ~USIOE;
    		/* bit counter = 8 */
    		USICNT |=  0x08;
    		twi_state = TWI_MR_PROC_DATA_RECV;
    		break;
    	case TWI_MR_PROC_DATA_RECV:
    		/* SDA output */
    		USICTL0 |= USIOE;
    
    		twi_masterBuffer[twi_masterBufferIndex++] = USISRL;
    		if(twi_masterBufferIndex > twi_masterBufferLength ) {
    			USISRL = 0xFF; // that was the last byte send NACK
    			twi_state = TWI_MR_PREP_STOP;
    		} else {
    			USISRL = 0x00; // keep on receiving and send ACK
    			twi_state = TWI_MR_PREP_DATA_RECV;
    		}
    
    		USICNT |= 0x01;
    		break;
    	case TWI_MR_PREP_STOP:
    		USICTL0 |= USIOE;
    		USISRL = 0x00;
    		USICNT |=  0x01;
    		twi_state = TWI_EXIT;
    		break;
    	/* All */
    	case TWI_EXIT:
    		/* Load FF into output shift register */
    		USISRL = 0x0FF;
    		/* Output latch transparant. MSB of USISR to the SDO pin. */
    		USICTL0 |= USIGE;
    		/* Latch disabled and make SDA input */
    		USICTL0 &= ~(USIGE+USIOE);
    		twi_state = TWI_IDLE;
    		break;
    	case TWI_IDLE:
                    /* Nothing to do. Fall thru and clear interrupt flag. */
    	default:
    		break;
    	}
    
    	/* Clear counter interrupt */
    	USICTL1 &= ~USIIFG;
    
    }
    #endif /* __MSP430_HAS_USI__ */
    
    #if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_B0__) || defined(__MSP430_HAS_USCI_B1__)
    uint16_t i2c_txrx_isr(void)  // RX/TX Service
    {
    	uint16_t stay_active = false;
    
    	/* USCI I2C mode. USCI_B0 receive interrupt flag.
    	 * UCBxRXIFG is set when UCBxRXBUF has received a complete character. */
    #if defined(__MSP430_HAS_USCI__)
    	if (UCxIFG & UCBxRXIFG){
    #else
    	if (UCBxIFG & UCRXIFG){
    #endif
    		/* Master receive mode. */
    		if (twi_state ==  TWI_MRX) {
    			twi_masterBuffer[twi_masterBufferIndex++] = UCBxRXBUF;
    			if(twi_masterBufferIndex == twi_masterBufferLength )
    				/* Only one byte left. Generate STOP condition.
    				 * In master mode a STOP is preceded by a NACK */
    				UCBxCTL1 |= UCTXSTP;
    			if(twi_masterBufferIndex > twi_masterBufferLength ) {
    				/* All bytes received. We are idle*/
    				stay_active = true;
    				twi_state = TWI_IDLE;
    			}
    		/* Slave receive mode. (twi_state = TWI_SRX) */
    		} else {
    			// if there is still room in the rx buffer
    			if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
    				// put byte in buffer and ack
    				twi_rxBuffer[twi_rxBufferIndex++] = UCBxRXBUF;
    			} else {
    				// otherwise nack
    				UCBxCTL1 |= UCTXNACK;   // Generate NACK condition
    			}
    		}
    	}
    	/* USCI I2C mode. USCI_Bx transmit interrupt flag.
    	 * UCBxTXIFG is set when UCBxTXBUF is empty.*/
    #if defined(__MSP430_HAS_USCI__)
    	if (UCxIFG & UCBxTXIFG){
    #else
    	if (UCBxIFG & UCTXIFG){
    #endif
    		/* Master transmit mode */
    		if (twi_state == TWI_MTX) {
    			// if there is data to send, send it, otherwise stop 
    			if(twi_masterBufferIndex < twi_masterBufferLength){
    				// Copy data to output register and ack.
    				UCBxTXBUF = twi_masterBuffer[twi_masterBufferIndex++];
    			} else {
    				if (twi_sendStop) {
    					/* All done. Generate STOP condition and IDLE */
    					UCBxCTL1 |= UCTXSTP;
    				} else {
    					twi_inRepStart = true;  // we're gonna send the START
    					// don't enable the interrupt. We'll generate the start, but we 
    					// avoid handling the interrupt until we're in the next transaction,
    					// at the point where we would normally issue the start.
    					UCBxCTL1 |= UCTXSTT;
    				}
    				twi_state = TWI_IDLE;
    				stay_active = true;
    			}
    		/* Slave transmit mode (twi_state = TWI_STX) */
    		} else {
    			// copy data to output register
    			UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++];
    			// if there is more to send, ack, otherwise nack
    			if(twi_txBufferIndex < twi_txBufferLength){
    			} else {
    				UCBxCTL1 |= UCTXNACK;    // Generate NACK condition
    			}
    		}
    	}
    	return(stay_active);
    }
    
    uint16_t i2c_state_isr(void)  // I2C Service
    {
    	uint16_t stay_active = false;
    
    	/* Arbitration lost interrupt flag */
    #if defined(__MSP430_HAS_USCI__)
    	if (UCBxSTAT & UCALIFG) {
    		UCBxSTAT &= ~UCALIFG;
    #else
    	if (UCBxIFG & UCALIFG) {
    		UCBxIFG &= ~UCALIFG;
    #endif
    		/* TODO: Handle bus arbitration lost */
    	}
    	/* Not-acknowledge received interrupt flag. 
    	 * UCNACKIFG is automatically cleared when a START condition is received.*/
    #if defined(__MSP430_HAS_USCI__)
    	if (UCBxSTAT & UCNACKIFG) {
    		UCBxSTAT &= ~UCNACKIFG;
    #else
    	if (UCBxIFG & UCNACKIFG) {
    		UCBxIFG &= ~UCNACKIFG;
    #endif
    		////UCBxCTL1 |= UCTXSTP;
    		/* TODO: This can just as well be an address NACK.
    		 * Figure out a way to distinguish between ANACK and DNACK */
    		if (twi_masterBufferIndex == 0)
    			twi_error = TWI_ERROR_ADDR_NACK;
    		else
    			twi_error = TWI_ERROR_DATA_NACK;
    		//twi_state = TWI_IDLE;
    		//stay_active = true;
    	}
    	/* Start condition interrupt flag.
    	 * UCSTTIFG is automatically cleared if a STOP condition is received. */
    #if defined(__MSP430_HAS_USCI__)
    	 if (UCBxSTAT & UCSTTIFG) {
    		UCBxSTAT &= ~UCSTTIFG;
    #else
    	 if (UCBxIFG & UCSTTIFG) {
    		UCBxIFG &= ~UCSTTIFG;
    #endif
    		/* UCTR is automagically set by the USCI module upon a START condition. */
    		if (UCBxCTL1 &  UCTR) {
    			/* Slave TX mode. */
    			twi_state =  TWI_STX;
    			/* Ready the tx buffer index for iteration. */
    			twi_txBufferIndex = 0;
    			/* Set tx buffer length to be zero, to verify if user changes it. */
    			twi_txBufferLength = 0;
    			/* Request for txBuffer to be filled and length to be set. */
    			/* note: user must call twi_transmit(bytes, length) to do this */
    			twi_onSlaveTransmit();
    			/* If they didn't change buffer & length, initialize it 
    			 * TODO: Is this right? Shouldn't we reply with a NACK if there is no data to send? */
    			if (0 == twi_txBufferLength) {
    				twi_txBufferLength = 1;
    				twi_txBuffer[0] = 0x00;
    			}
    		} else {
    			/* Slave receive mode. */
    			twi_state =  TWI_SRX;
    			/* Indicate that rx buffer can be overwritten and ACK */
    			twi_rxBufferIndex = 0;
    		}
    	}
    	/* Stop condition interrupt flag.
    	 * UCSTPIFG is automatically cleared when a STOP condition is received. */
    #if defined(__MSP430_HAS_USCI__)
    	if (UCBxSTAT & UCSTPIFG) {
    		UCBxSTAT &= ~UCSTPIFG;
    #else
    	if (UCBxIFG & UCSTPIFG) {
    		UCBxIFG &= ~UCSTPIFG;
    #endif
    		if (twi_state ==  TWI_SRX) {
    			/* Callback to user defined callback */
    			twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
    		}
    		twi_state =  TWI_IDLE;
    		stay_active = true;
    	}
    	return(stay_active);
    }
    #endif
    
    #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
    uint16_t eusci_isr_handler(void)
    {
      uint16_t exit_lpm = 0;
    //	switch(twi_state){
      switch(UCBxIV){
        case USCI_NONE:            // No Interrupt pending
          break;
        case USCI_I2C_UCALIFG:     // USCI I2C Mode: UCALIFG
          // enter slave transmitter mode
          twi_state = TWI_STX;
          // ready the tx buffer index for iteration
          twi_txBufferIndex = 0;
          // set tx buffer length to be zero, to verify if user changes it
          twi_txBufferLength = 0;
          // request for txBuffer to be filled and length to be set
          // note: user must call twi_transmit(bytes, length) to do this
          twi_onSlaveTransmit();
          // if they didn't change buffer & length, initialize it
          if(0 == twi_txBufferLength){
            twi_txBufferLength = 1;
            twi_txBuffer[0] = 0x00;
          }
          // transmit first byte from buffer, fall
          // copy data to output register
          UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++];
          // if there is more to send, ack, otherwise nack
          if(twi_txBufferIndex < twi_txBufferLength){
            //twi_reply(1);
          } else {
    		UCBxCTLW0 |= UCTXNACK;                // Generate NACK condition
          }
          // leave slave receiver state
          twi_state = TWI_IDLE;
    
          break;
        case USCI_I2C_UCNACKIFG:   // USCI I2C Mode: UCNACKIFG
    		if (twi_masterBufferIndex == 0) // when no data, we received the address
    			twi_error = TWI_ERROR_ADDR_NACK;
    	    else
    			twi_error = TWI_ERROR_DATA_NACK;
            // leave slave receiver state
            twi_state = TWI_IDLE;
    		if (UCBxTBCNT == 0) 
    			UCBxCTLW0 |= UCTXSTP;                // Generate I2C stop condition manually
    		exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM
          break;
        case USCI_I2C_UCSTTIFG:    // USCI I2C Mode: UCSTTIFG
    		UCBxIFG &= ~UCSTTIFG;
    		if (twi_state ==  TWI_IDLE){
    			if (UCBxCTLW0 &  UCTR){
    				twi_state =  TWI_STX;      // Slave Transmit mode
    				// ready the tx buffer index for iteration
    				twi_txBufferIndex = 0;
    				// set tx buffer length to be zero, to verify if user changes it
    				twi_txBufferLength = 0;
    				// request for txBuffer to be filled and length to be set
    				// note: user must call twi_transmit(bytes, length) to do this
    				twi_onSlaveTransmit();
    				// if they didn't change buffer & length, initialize it
    				if(0 == twi_txBufferLength){
    					twi_txBufferLength = 1;
    					twi_txBuffer[0] = 0x00;
    				}
    			} else {
    				twi_state =  TWI_SRX;      // Slave receive mode
    				// indicate that rx buffer can be overwritten and ack
    				twi_rxBufferIndex = 0;
    			}
    		}
          break;
        case USCI_I2C_UCSTPIFG:    // USCI I2C Mode: UCSTPIFG
            //UCBxIFG &= ~UCSTPIFG;
    		if (twi_state ==  TWI_SRX){
    			// callback to user defined callback
    			twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
    		}
    		twi_state =  TWI_IDLE; // IDLE mode
    		/* Work around for:
    		 * If the master does a read and then a write the START interrupt occurs
    		 * but the RX interrupt never fires. Clearing bit 4 and 5 of UCBxCTLW0 solves this.
    		 * bit 4 and 5 are however marked as reserved in the datasheet.
    		 */
    		UCBxCTLW0 &= ~0x18;
    
    		exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM
          break;
        case USCI_I2C_UCRXIFG3:    // USCI I2C Mode: UCRXIFG3
          break;
        case USCI_I2C_UCTXIFG3:    // USCI I2C Mode: UCTXIFG3
          break;
        case USCI_I2C_UCRXIFG2:    // USCI I2C Mode: UCRXIFG2
          break;
        case USCI_I2C_UCTXIFG2:    // USCI I2C Mode: UCTXIFG2
          break;
        case USCI_I2C_UCRXIFG1:    // USCI I2C Mode: UCRXIFG1
          break;
        case USCI_I2C_UCTXIFG1:    // USCI I2C Mode: UCTXIFG1
          break;
        case USCI_I2C_UCRXIFG0:    // USCI I2C Mode: UCRXIFG0
    		//UCBxIFG &= ~UCRXIFG;                  // Clear USCI_B0 TX int flag
    		if (twi_state ==  TWI_MRX) {      // Master receive mode
    			twi_masterBuffer[twi_masterBufferIndex++] = UCBxRXBUF; // Get RX data
    			if(twi_masterBufferIndex == twi_masterBufferLength )
    				UCBxCTLW0 |= UCTXSTP;  // Generate I2C stop condition
    			if(twi_masterBufferIndex > twi_masterBufferLength ) {
    				twi_state = TWI_IDLE; //Idle
    			} else {
    			}
    		} else {
    			// if there is still room in the rx buffer
    			if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
    				// put byte in buffer and ack
    				twi_rxBuffer[twi_rxBufferIndex++] = UCBxRXBUF;
    			} else {
    				// otherwise nack
    				UCBxCTLW0 |= UCTXNACK;                // Generate NACK condition
    			}
    		}
          break;
        case USCI_I2C_UCTXIFG0:    // USCI I2C Mode: UCTXIFG0
    		//UCBxIFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
    		if (twi_state == TWI_MTX) {      // Master transmit mode
    			// if there is data to send, send it, otherwise stop
    			if(twi_masterBufferIndex < twi_masterBufferLength){
    				// copy data to output register and ack
    				UCBxTXBUF = twi_masterBuffer[twi_masterBufferIndex++];                 // Transmit data at address PTxData
    			}else{
    			   if (twi_sendStop) {
    				 if (UCBxTBCNT == 0) 
    					 UCBxCTLW0 |= UCTXSTP;                // Generate I2C stop condition manually
    			   } else {
    				 twi_inRepStart = true;   // we're gonna send the START
    				 // don't enable the interrupt. We'll generate the start, but we
    				 // avoid handling the interrupt until we're in the next transaction,
    				 // at the point where we would normally issue the start.
    				 UCBxCTLW0 |= UCTXSTT;
    				 twi_state = TWI_IDLE;
    				 exit_lpm = 1; //__bic_SR_register_on_exit(LPM4_bits); // Exit LPM
    			   }
    			}
    		} else if (twi_state == TWI_MRX) {      // Master receive mode
    			// copy data to output register
    			UCBxTXBUF = twi_txBuffer[twi_txBufferIndex++];
    			// if there is more to send, ack, otherwise nack
    			if(twi_txBufferIndex < twi_txBufferLength){
    			} else {
    				UCBxCTLW0 |= UCTXNACK;                // Generate NACK condition
    			}
    		}
          break;
        case USCI_I2C_UCBCNTIFG:   // USCI I2C Mode: UCBCNTIFG
          break;
        case USCI_I2C_UCCLTOIFG:   // USCI I2C Mode: UCCLTOIFG/
          break;
        case USCI_I2C_UCBIT9IFG:   // USCI I2C Mode: UCBIT9IFG
          break;
    	}
    	return (exit_lpm);
    }
    
    #if defined(__MSP430_HAS_EUSCI_B0__)
    __attribute__((interrupt(USCI_B0_VECTOR)))
    void USCI_B0_ISR(void)
    {
    	if (eusci_isr_handler()) 
    		__bic_SR_register_on_exit(LPM4_bits); // Exit LPM
    } 
    #endif
    
    #if defined(__MSP430_HAS_EUSCI_B1__)
    __attribute__((interrupt(USCI_B1_VECTOR)))
    void USCI_B1_ISR(void)
    {
    	if (eusci_isr_handler()) 
    		__bic_SR_register_on_exit(LPM4_bits); // Exit LPM
    }	
    #endif
    
    #endif // #if defined(__MSP430_HAS_EUSCI_B0__) || defined(__MSP430_HAS_EUSCI_B1__)
    
    

    twi_sw.c
    /*
      ************************************************************************
      *	twi_sw.c
      *
      *	twi software files for MSP430
      *		Copyright (c) 2015 StefanSch. All right reserved.
      *
      * V1.1 : updates to correct SCL and SDA assignments
      *        support of connected device scan with return values defined in twi.h
      *
      ***********************************************************************
    
      This library is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
      License as published by the Free Software Foundation; either
      version 2.1 of the License, or (at your option) any later version.
    
      This library is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Lesser General Public License for more details.
    
      You should have received a copy of the GNU Lesser General Public
      License along with this library; if not, write to the Free Software
      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    */
    
    #include "twi_sw.h"
    #include "twi.h"
    
    #if DEFAULT_I2C == -1 /* indicates SW I2C on pseudo module 1 */
    
    
    #define I2C_DELAY1() __delay_cycles(F_CPU / 1000000UL * 10)
    #define I2C_DELAY2() __delay_cycles(F_CPU / 1000000UL * 20)
    
    #define I2C_READ   BIT0
    #define I2C_WRITE  0
    
    uint8_t i2c_sw_start(uint8_t address, uint8_t rw);
    uint8_t i2c_sw_txByte(uint8_t data);
    void i2c_sw_ack(void);
    uint8_t i2c_sw_rxByte(uint8_t lastChar);
    void i2c_sw_stop(void);
    
    
    void i2c_sw_init(void)
    {
      digitalWrite(TWISDA, LOW);
      digitalWrite(TWISCL, LOW);
      pinMode(TWISDA, INPUT);
      pinMode(TWISCL, INPUT);
    }
    
    uint8_t i2c_sw_read(uint8_t slaveAddress,
                              uint16_t numBytes, uint8_t* data, uint8_t sendStop)
    {
      uint16_t i;
      uint8_t ack_error;
      
      ack_error = i2c_sw_start(slaveAddress, I2C_READ);   // Send Start condition
                                                // [ADDR] + R/W bit = 1
      if (ack_error) return (ack_error);
      for (i = 0; i < numBytes-1; i++) {
        *data++ = i2c_sw_rxByte(0);             // Read data
      }
      *data++ = i2c_sw_rxByte(1);               // Read last data
      if (sendStop) i2c_sw_stop();              // Send Stop condition
      return (0);
    }
    
    uint8_t i2c_sw_write(uint8_t slaveAddress,
                               uint16_t numBytes, uint8_t* data, uint8_t sendStop)
    {        
       uint16_t i;
       uint8_t status;
       
       status = i2c_sw_start(slaveAddress, I2C_WRITE);       // Send Start condition
                                                // [ADDR] + R/W bit = 0
       if (status) {
    	   i2c_sw_stop();                       // Send Stop condition
       	   return (TWI_ERROR_ADDR_NACK);
       }
       for (i = 0; i < numBytes; i++) {
    	   status |= i2c_sw_txByte(*data++);    // Send data and ack
       }
       if (sendStop) i2c_sw_stop();             // Send Stop condition
       if (status) return (TWI_ERROR_DATA_NACK);
       return (status);
    }
    
    uint8_t i2c_sw_start(uint8_t address, uint8_t rw)               // Set up start condition for I2C
    {
      pinMode(TWISDA, OUTPUT);
      I2C_DELAY2();                             // delay
      pinMode(TWISCL, OUTPUT);
      I2C_DELAY2();                             // delay
      return(i2c_sw_txByte((address << 1) | rw)); // [ADDR] + R/W bit
    }
    
    uint8_t i2c_sw_txByte(uint8_t data)
    {
      uint8_t bits = 0x08;
      uint8_t ack_error;
      
      while (bits != 0x00)                      // Loop until all bits are shifted
      {
        if (data & BIT7)                        // Test data bit
          pinMode(TWISDA, INPUT);
        else
          pinMode(TWISDA, OUTPUT);
        I2C_DELAY2();
        pinMode(TWISCL, INPUT);
        data <<= 1;                             // Shift bits 1 place to the left
        I2C_DELAY1();                           // Quick delay
        pinMode(TWISCL, OUTPUT);
        bits--;                                 // Loop until 8 bits are sent
      }
      pinMode(TWISDA, INPUT);
      // Get acknowledge
      I2C_DELAY2();
      pinMode(TWISCL, INPUT);
      I2C_DELAY2();
      ack_error = digitalRead(TWISDA);
      pinMode(TWISCL, OUTPUT);
      return (ack_error);
    }
    
    void i2c_sw_ack(void)                       // Check for I2C acknowledge
    {
       I2C_DELAY2();
       pinMode(TWISCL, INPUT);
       I2C_DELAY2();
       pinMode(TWISCL, OUTPUT);
    }
                
    uint8_t i2c_sw_rxByte(uint8_t lastChar)    // Read 8 bits of I2C data
    {
       uint8_t bits = 0x08;
       uint8_t data = 0;
    
       pinMode(TWISDA, INPUT);
       I2C_DELAY1();
       while (bits > 0)                         // Loop until all bits are read
       {
          pinMode(TWISCL, INPUT);
          I2C_DELAY1();
          data <<= 1;                           // Shift bits 1 place to the left
          if (digitalRead(TWISDA))              // Check digital input
            data |= 1;                          // If input is 'H' store a '1'
          pinMode(TWISCL, OUTPUT);
          I2C_DELAY1();
          bits--;                               // Decrement I2C bit counter
       }
       if (lastChar == 0)
         pinMode(TWISDA, OUTPUT);               // Set acknowledge
       I2C_DELAY1();
       pinMode(TWISCL, INPUT);
       I2C_DELAY1();
       pinMode(TWISCL, OUTPUT);
       I2C_DELAY1();
       return (data);                           // Return 8-bit data byte
    }   
    
    void i2c_sw_stop(void)                      // Send I2C stop command
    {
      pinMode(TWISDA, OUTPUT);
      I2C_DELAY2();
      pinMode(TWISCL, INPUT);
      I2C_DELAY2();
      pinMode(TWISDA, INPUT);
      I2C_DELAY2();
    }
    
    #endif // #if DEFAULT_I2C = -1 /* indicates SW I2C on pseudo module 1 */
    

  • The stars have aligned !!!  It works like a charm now !!!  Life are GROOVY !!!  Thanks a bunch Robert !!

  • Great to hear that you got it working! Thanks for reporting back!

    Robert

  • Well, we've changed chips over to the MSP430G2553IRHB32R.  It's got 32 pins and ses pins 21 and 22 for I2C_SCL and I2C_SDA respectively.  This is a QFN package.

    My problem is that I cannot get I2C to work with this chip.  I've tried all of the above, but am using version 18 of energia.  I've replaced the pins_energia.h with the following and still cannot seem to get any response from my I2C devices.  Do you have any suggestions or recommendations?

    /*
    ************************************************************************
    * pins_energia.h
    *
    * Energia core files for MSP430
    * Copyright (c) 2012 Robert Wessels. All right reserved.
    *
    * Contribution: Rei VILO
    *
    ***********************************************************************
    Derived from:
    pins_arduino.h - Pin definition functions for Arduino
    Part of Arduino - http://www.arduino.cc/
    Copyright (c) 2007 David A. Mellis
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    Lesser General Public License for more details.
    You should have received a copy of the GNU Lesser General
    Public License along with this library; if not, write to the
    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
    Boston, MA 02111-1307 USA
    */
    #define __MSP430_HAS_PORT3_R__
    //#define IOT_SENSOR_NODE
    #ifndef Pins_Energia_h
    #define Pins_Energia_h
    #ifndef BV
    #define BV(x) (1 << (x))
    #endif

    #if defined(__MSP430_HAS_USCI__)
    static const uint8_t SS = 16; /* P2.4 */
    static const uint8_t SCK = 5; /* P1.5 */
    static const uint8_t MOSI = 22; /* P1.7 */
    static const uint8_t MISO = 21; /* P1.6 */
    static const uint8_t TWISDA = 22; /* P1.6 */
    static const uint8_t TWISCL = 21; /* P1.7 */
    static const uint8_t TWISCL1 = 11; /* P2.1 SW I2C */
    static const uint8_t TWISDA1 = 12; /* P2.2 SW I2C */
    static const uint8_t TWISDA0 = 23; /* P1.7 */
    static const uint8_t TWISCL0 = 22; /* P1.6 */
    static const uint8_t DEBUG_UARTRXD = 1; /* Receive Data (RXD) at P1.1 */
    static const uint8_t DEBUG_UARTTXD = 2; /* Transmit Data (TXD) at P1.2 */
    #define TWISDA1_SET_MODE (INPUT)
    #define TWISCL1_SET_MODE (INPUT)
    #define TWISDA0_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/) /* do not enable the pull ups for this device */
    #define TWISCL0_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/)
    #define TWISDA_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/) /* do not enable the pull ups for this device */
    #define TWISCL_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 /* | INPUT_PULLUP*/)
    #define DEBUG_UARTRXD_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 | INPUT)
    #define DEBUG_UARTTXD_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1 | OUTPUT)
    #define SPISCK_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
    #define SPIMOSI_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
    #define SPIMISO_SET_MODE (PORT_SELECTION0 | PORT_SELECTION1)
    #endif

    #define DEBUG_UART_MODULE_OFFSET 0x0

    #if defined(__MSP430_HAS_USI__)
    static const uint8_t SS = 16; /* P2.4 */
    static const uint8_t SCK = 5; /* P1.5 */
    static const uint8_t MOSI = 22; /* P1.7 */
    static const uint8_t MISO = 21; /* P1.6 */
    static const uint8_t TWISDA = 22; /* P1.6 */
    static const uint8_t TWISCL = 21; /* P1.7 */
    static const uint8_t DEBUG_UARTRXD = 1; /* Receive Data (RXD) at P1.1 */
    static const uint8_t DEBUG_UARTTXD = 2; /* Transmit Data (TXD) at P1.2 */
    #define TWISDA_SET_MODE (PORT_SELECTION0 | INPUT_PULLUP)
    #define TWISCL_SET_MODE (PORT_SELECTION0 | INPUT_PULLUP)
    #define DEBUG_UARTRXD_SET_MODE (PORT_SELECTION0 | INPUT)
    #define DEBUG_UARTTXD_SET_MODE (PORT_SELECTION0 | OUTPUT)
    #endif

    #define DEBUG_UART_MODULE 0x0

    static const uint8_t A0 = 31;
    static const uint8_t A1 = 1;
    static const uint8_t A2 = 2;
    static const uint8_t A3 = 3;
    static const uint8_t A4 = 4;
    static const uint8_t A5 = 5;
    static const uint8_t A6 = 21;
    static const uint8_t A7 = 22;
    static const uint8_t A10 = 128 + 10; // special. This is the internal temp sensor

    // +-+-+-+-+-+-+-+-+-+
    // VCC 1| |20 GND
    // (A0) P1.0 2| |19 XIN
    // (A1) P1.1 3| |18 XOUT
    // (A2) P1.2 4| |17 TEST
    // (A3) P1.3 5| |16 RST#
    // (A4) P1.4 6| |15 P1.7 (A7) (SCL) (MISO) depends on chip
    // (A5) P1.5 7| |14 P1.6 (A6) (SDA) (MOSI)
    // P2.0 8| |13 P2.5
    // P2.1 9| |12 P2.4
    // P2.2 10| |11 P2.3
    // +-+-+-+-+-+-+-+-+-+
    //

    // Pin names based on the silkscreen
    //
    static const uint8_t P1_1 = 1;
    static const uint8_t P1_2 = 2;
    static const uint8_t P1_3 = 3;
    static const uint8_t P1_4 = 4;
    static const uint8_t P1_5 = 5;
    static const uint8_t P3_1 = 6;
    static const uint8_t P3_0 = 7;
    static const uint8_t P2_0 = 9;
    static const uint8_t P2_1 = 10;
    static const uint8_t P2_2 = 11;
    static const uint8_t P3_2 = 12;
    static const uint8_t P3_3 = 13;
    static const uint8_t P3_4 = 14;
    static const uint8_t P2_3 = 15;
    static const uint8_t P2_4 = 16;
    static const uint8_t P2_5 = 17;
    static const uint8_t P3_5 = 18;
    static const uint8_t P3_6 = 19;
    static const uint8_t P3_7 = 20;
    static const uint8_t P1_6 = 21;
    static const uint8_t P1_7 = 22;
    static const uint8_t P2_7 = 25;
    static const uint8_t P2_6 = 26;
    static const uint8_t P1_0 = 31;

    static const uint8_t RED_LED = 25;
    static const uint8_t GREEN_LED = 26;

    #define PIN_MOSI P1_7
    #define PIN_MISO P1_6
    #define PIN_CLK P1_5
    #define PIN_CE P3_5
    #define PIN_nCS P3_6
    #define PIN_IRQ P2_5

    #define PIN_SCL P1_6
    #define PIN_SDA P1_7

    #define BATTERY_ADC A0

    static const uint8_t TEMPSENSOR = 10; // depends on chip


    #ifdef ARDUINO_MAIN

    const uint16_t port_to_input[] = {
    NOT_A_PORT,
    (uint16_t) &P1IN,
    (uint16_t) &P2IN,
    #ifdef __MSP430_HAS_PORT3_R__
    (uint16_t) &P3IN,
    #endif
    };

    const uint16_t port_to_output[] = {
    NOT_A_PORT,
    (uint16_t) &P1OUT,
    (uint16_t) &P2OUT,
    #ifdef __MSP430_HAS_PORT3_R__
    (uint16_t) &P3OUT,
    #endif
    };

    const uint16_t port_to_dir[] = {
    NOT_A_PORT,
    (uint16_t) &P1DIR,
    (uint16_t) &P2DIR,
    #ifdef __MSP430_HAS_PORT3_R__
    (uint16_t) &P3DIR,
    #endif
    };

    const uint16_t port_to_ren[] = {
    NOT_A_PORT,
    (uint16_t) &P1REN,
    (uint16_t) &P2REN,
    #ifdef __MSP430_HAS_PORT3_R__
    (uint16_t) &P3REN,
    #endif
    };

    const uint16_t port_to_sel0[] = { /* put this PxSEL register under the group of PxSEL0 */
    NOT_A_PORT,
    (uint16_t) &P1SEL,
    (uint16_t) &P2SEL,
    #ifdef __MSP430_HAS_PORT3_R__
    (uint16_t) &P3SEL,
    #endif
    };

    const uint16_t port_to_sel2[] = {
    NOT_A_PORT,
    #ifdef P1SEL2_
    (uint16_t) &P1SEL2,
    #else
    NOT_A_PORT,
    #endif
    #ifdef P2SEL2_
    (uint16_t) &P2SEL2,
    #else
    NOT_A_PORT,
    #endif
    #ifdef P3SEL2_
    (uint16_t) &P3SEL2,
    #else
    NOT_A_PORT,
    #endif
    };


    /*
    * Defines for devices with 2x TA3 timers (e.g. MSP430g2553). On the 20pin devices, upto 3 analog outputs are available
    * T0A1, T1A1 and T1A2
    */
    const uint8_t digital_pin_to_timer[] = {
    NOT_ON_TIMER, /* dummy */
    NOT_ON_TIMER, /* 1 - VCC */
    NOT_ON_TIMER, /* 2 - P1.0 */
    T0A0, /* 3 - P1.1, note: A0 output cannot be used with analogWrite */
    T0A1, /* 4 - P1.2 */
    NOT_ON_TIMER, /* 5 - P1.3 */
    NOT_ON_TIMER, /* 6 - P1.4 note: special case. Leaving as no timer due to difficulty determining if available */
    T0A0, /* 7 - P1.5 note: A0 output cannot be used with analogWrite */
    #if defined(__MSP430_HAS_T1A3__)
    T1A0, /* 8 - P2.0 note: A0 output cannot be used with analogWrite */
    T1A1, /* 9 - P2.1 */
    T1A1, /* 10 - P2.2 */
    T1A0, /* 11 - P2.3 note: A0 output cannot be used with analogWrite */
    T1A2, /* 12 - P2.4 */
    T1A2, /* 13 - P2.5 */
    #else
    NOT_ON_TIMER, /* 8 - P2.0 */
    NOT_ON_TIMER, /* 9 - P2.1 */
    NOT_ON_TIMER, /* 10 - P2.3 */
    NOT_ON_TIMER, /* 11 - P2.4 */
    NOT_ON_TIMER, /* 12 - P2.5 */
    NOT_ON_TIMER, /* 13 - P2.6 */
    #endif
    T0A1, /* 14 - P1.6 */
    NOT_ON_TIMER, /* 15 - P1.7 */
    NOT_ON_TIMER, /* 16 - /RESET */
    NOT_ON_TIMER, /* 17 - TEST */
    NOT_ON_TIMER, /* 18 - XOUT - P2.7 */
    T0A1, /* 19 - XIN - P2.6: */
    NOT_ON_TIMER, /* 20 - GND */
    };

    const uint8_t digital_pin_to_port[] = {
    NOT_A_PIN, /* dummy */
    P1, /* 1 */
    P1, /* 2 */
    P1, /* 3 */
    P1, /* 4 */
    P1, /* 5 */
    P3, /* 6 */
    P3, /* 7 */
    NOT_A_PIN, /* 8 */
    P2, /* 9 */
    P2, /* 10 */
    P2, /* 11 */
    P3, /* 12 */
    P3, /* 13 */
    P3, /* 14 */
    P2, /* 15 */
    P2, /* 16 */
    P2, /* 17 */
    P3, /* 18 */
    P3, /* 19 */
    P3, /* 20 */
    P1, /* 21 */
    P1, /* 22 */
    NOT_A_PIN, /* 23 */
    NOT_A_PIN, /* 24 */
    P2, /* 25 */
    P2, /* 26 */
    NOT_A_PIN, /* 27 */
    NOT_A_PIN, /* 28 */
    NOT_A_PIN, /* 29 */
    NOT_A_PIN, /* 30 */
    P1, /* 31 */
    NOT_A_PIN, /* 32 */
    };

    const uint8_t digital_pin_to_bit_mask[] = {
    NOT_A_PIN, /* 0, pin count starts at 1 */
    BV(1), /* 1, P1.1 */
    BV(2), /* 2, port P1.2 */
    BV(3), /* 3, port P1.3 */
    BV(4), /* 4, port P1.4 */
    BV(5), /* 5, port P1.5 */
    BV(1), /* 6, port P3.1 */
    BV(0), /* 7, port P3.0 */
    NOT_A_PIN, /* 8, NC */
    BV(0), /* 9, port P2.0 */
    BV(1), /* 10, port P2.1 */
    BV(2), /* 11, port P2.2 */
    BV(2), /* 12, port P3.2 */
    BV(3), /* 13, port P3.3 */
    BV(4), /* 14, port P3.4 */
    BV(3), /* 15, port P2.3 */
    BV(4), /* 16, P2.4 */
    BV(5), /* 17, P2.5 */
    BV(5), /* 18, P3.5 */
    BV(6), /* 19, P3.6 */
    BV(7), /* 20, P3.7 */
    BV(6), /* 21, P1.6 */
    BV(7), /* 22, P1.7 */
    NOT_A_PIN, /* 23, RST */
    NOT_A_PIN, /* 24, TEST */
    BV(7), /* 25, P2.7 */
    BV(6), /* 26, P2.6 */
    NOT_A_PIN, /* 27, GND */
    NOT_A_PIN, /* 28, GND */
    NOT_A_PIN, /* 29, VCC */
    NOT_A_PIN, /* 30, VCC */
    BV(0), /* 31, P1.0 */
    NOT_A_PIN, /* 32, NC */
    };
    const uint32_t digital_pin_to_analog_in[] = {
    NOT_ON_ADC, /* 0, pin count starts at 1 */
    1, /* 1, A1 */
    2, /* 2, A2 */
    3, /* 3, A3 */
    4, /* 4, A4 */
    5, /* 5, A5 */
    NOT_ON_ADC, /* 6, port P3.1 */
    NOT_ON_ADC, /* 7, port P3.0 */
    NOT_ON_ADC, /* 8, NC */
    NOT_ON_ADC, /* 9, port P2.0 */
    NOT_ON_ADC, /* 10, port P2.1 */
    NOT_ON_ADC, /* 11, port P2.2 */
    NOT_ON_ADC, /* 12, port P3.2 */
    NOT_ON_ADC, /* 13, port P3.3 */
    NOT_ON_ADC, /* 14, port P3.4 */
    NOT_ON_ADC, /* 15, port P2.3 */
    NOT_ON_ADC, /* 16, P2.4 */
    NOT_ON_ADC, /* 17, P2.5 */
    NOT_ON_ADC, /* 18, P3.5 */
    NOT_ON_ADC, /* 19, P3.6 */
    NOT_ON_ADC, /* 20, P3.7 */
    6, /* 21, A6 */
    7, /* 22, A7 */
    NOT_ON_ADC, /* 23, RST */
    NOT_ON_ADC, /* 24, TEST */
    NOT_ON_ADC, /* 25, P2.7 */
    NOT_ON_ADC, /* 26, P2.6 */
    NOT_ON_ADC, /* 27, GND */
    NOT_ON_ADC, /* 28, GND */
    NOT_ON_ADC, /* 29, VCC */
    NOT_ON_ADC, /* 30, VCC */
    0, /* 31, A0 */
    NOT_ON_ADC /* 32, NC */
    };

    #endif
    #endif