MSP-EXP430G2 I2C Master Examples

Last week, I mentioned that in order for the I2C bus to function correctly when using the MSP430 Launchpad you might need to remove the jumper on P1.6. This is because P1.6 is the SCL pin and the connected LED may cause the output voltage to stray from the desired logic voltage levels. In this post, I will show a couple of examples of using the MSP430 Launchpad as an I2C master to communicate with slave devices. The library code can be downloaded towards the end.

The I2C code I am using is adapted from the I2C Explorer project on 43oh forum. In both examples, the MCU is configured as I2C master. For more detailed background information on implementing I2C on MSP430G2 devices, you can check out this TI Wiki. Also you can refer to TI’s MSP430x2xx Family User’s Guide for more details. The code examples included here are built under TI’s Code Composer Studio V5.1 for MSP430G2231. But the same code can be used with any chips within the MSP430G2 family that supports the I2C functionality by simply changing the header file in the include statement.

My first example shows how to set the output frequency of the programmable oscillator LTC6904. If you are interested in the Arduino implementation, you can check out this post from last year. The full code listings can be found at the end.

#include <msp430g2231.h>
#include "i2c.h"

unsigned char i2cAddress = 0x17;

void setFreq() //~4158 Hz
{
  unsigned int oct = 2;
  unsigned int dac = 1;

  //f=2^oct*2078/(2-dac/1024)
  unsigned int reg = oct << 12 | dac << 2;

  unsigned char high = (reg >> 8) & 0xff;
  unsigned char low = reg & 0xff;

  i2c_start();
  i2c_write8(i2cAddress << 1);
  i2c_write8(high);
  i2c_write8(low);
  i2c_stop();
}

void main(void) {
	WDTCTL = WDTPW + WDTHOLD;

	i2c_init();
	setFreq();
}

As you can see, the implementation is pretty straightforward. The I2C communication begins by initiating a start condition. The slave 7-bit address is then followed. Note that the LSB indicates whether the operation is a read or write. In our case, we wanted to write to the configuration register and thus the address was simply left shifted by one leaving the LSB zero. Then the desired register content was sent over in two writes, first the high byte and then the low byte. Finally, a stop condition is issued to indicate the end of the communication.

The following table compares the I2C library calls used here with those in the standard Arduino library:

Arduino MSP430G2
Write to address Wire.beginTransmission(I2C addr); i2c_start();
i2c_write8(I2C addr << 1);
Write data Wire.write(data byte); i2c_write8(data byte);
Read from address Wire.requestFrom(I2C addr, number of bytes); i2c_start();
i2c_write8(I2C addr << 1 | 1);
*note that the number of bytes is determined by the number of reads followed
Read data Wire.read(); i2c_read8(0x0);
End communication Wire.endTransmission(); i2c_stop();

The second example shows how to interface with a digital thermometer DS7505. The code listed below are translated from the Arduino library I created earlier. You can check the table above to see how the I2C communications are implemented.

#include <msp430g2231.h>
#include "i2c.h"

//Resolution Definition
//R1 R0
unsigned char RES_09 = 0x0; // 9 bit res;
unsigned char RES_10 = 0x1; //10 bit res;
unsigned char RES_11 = 0x2; //11 bit res;
unsigned char RES_12 = 0x3; //12 bit res;

//Fault Tolerance Configuration
//F1 F0
unsigned char FT_1 = 0x0; //fault tolerance consecutive out of limits 1
unsigned char FT_2 = 0x1; //fault tolerance consecutive out of limits 2
unsigned char FT_4 = 0x2; //fault tolerance consecutive out of limits 4
unsigned char FT_6 = 0x3; //fault tolerance consecutive out of limits 6

//Register Pointer Definition
//P1 P0
unsigned char P_TEMP = 0x0; //temperature
unsigned char P_CONF = 0x1; //configuration
unsigned char P_THYST = 0x2; //Thyst
unsigned char P_TOS = 0x3; //Tos

//command set
unsigned char CMD_RECALL_DATA = 0xB8;
unsigned char CMD_COPY_DATA = 0x48;
unsigned char CMD_POR = 0x54;

unsigned char Resolution;
unsigned char A2, A1, A0;
unsigned char I2CAddr;
unsigned char ConfigByte;

float t;

//set configuration byte
//bit 7: NVB (NV Memory Status), read-only
//bit 6: R1 (Conversion Resolution Bit 1)
//bit 5: R0 (Conversion Resolution Bit 0)
//bit 4: F1 (Thermostat Fault Tolerance Bit 1)
//bit 3: F0 (Thermostat Fault Tolerance Bit 0)
//bit 2: POL (Thermostat Output Polarity)
//bit 1: TM (Thermostat Operating Mode)
//bit 0: SD (Shutdown)
void DS7505_setConfigRegister(unsigned char configByte)
{
	i2c_start();
	i2c_write8(I2CAddr << 1);
	i2c_write8(P_CONF);
	i2c_write8(ConfigByte);
	i2c_stop();
}

//get temperature in Celsius
float DS7505_getTemp(unsigned char regPdef)
{
  float temp = 0.0;
  float s = 1.0;

  unsigned char h = 0, l = 0;

  i2c_start();
  i2c_write8(I2CAddr << 1);
  i2c_write8(regPdef);
  i2c_stop();

  i2c_start();
  i2c_write8(I2CAddr << 1  | 1);
  h = i2c_read8(0x0);
  l = i2c_read8(0x0);
  i2c_stop();

  if (h & 0x80 == 0x80) {
    s = -1.0;
    h = h & 0x7f;
  }
  else {
    s = 1.0;
  }

  temp = s * 0.5 * ((l & 0x80 )>> 7) + 0.25 * ((l & 0x40 )>> 6)+ 0.125 * ((l & 0x20 )>> 5) + 0.0625 * ((l & 0x10 )>> 4) + (float) h;

  return temp;
}

//Initialize DS7505
//a2, a1, a0 are either HIGH (1) or LOW (0) depending
//on the pin setup.
//res: temperature resolution. 9, 10, 11, 12 (default is 12)
void DS7505_init(unsigned char a2, unsigned char a1, unsigned char a0, unsigned char res)
{
  A2 = a2;
  A1 = a1;
  A0 = a0;
  Resolution = res;
  ConfigByte = 0;

  //1001A2A1A0
  I2CAddr = 0x48 | (A2 << 2 | A1 << 1 | A0);

  switch (Resolution)
  {
  case 9:
    ConfigByte = RES_09 << 5;
    break;
  case 10:
    ConfigByte = RES_10 << 5;
    break;
  case 11:
    ConfigByte = RES_11 << 5;
    break;
  case 12:
    ConfigByte = RES_12 << 5;
    break;
  default:
    ConfigByte = RES_12 << 5;
  }

  DS7505_setConfigRegister(ConfigByte);
}

float getTemp()
{
	 t =  9.0/5.0 * DS7505_getTemp(P_TEMP) + 32.0;
	return t;
}

void main(void) {
	WDTCTL = WDTPW + WDTHOLD;
	
	i2c_init();

	DS7505_init(0, 0, 0, 12);

	while (1) {
		getTemp();
	}
}

Downloads

MSP430G2231 I2C library: msp430g2231_i2c_lib.tar.gz
I2C example (LTC6904): I2C_LTC6904_2231.tar.gz
I2C example (DS7505): I2C_DS7505_2231.tar.gz

More Examples

Reading SHT21 Using TI MSP430 LaunchPad
Interfacing DS3232 RTC With MSP430G2452

Be Sociable, Share!

23 Comments

  1. Anindo Ghosh says:

    Hi,

    I am pretty new to the Launchpad, and am struggling to make it talk to an i2c OLED display based on an SSD1308 controller. I picked the display up off eBay, and it came with no documentation. I was looking for a way to scan the i2c bus for the display’s address, which brought me to your blog.

    I notice that you use CCS for your builds, would you have ported the i2c explorer’s port scanning code to CCS by any chance? I could really do with some help there.

    Thanks in advance.

  2. aalani says:

    Hi Mr. wong,

    This is very helpful. I had a quick question have you used this with msp430g2553 – that uses USCI? I’m new to the microcontroller world and i2c. would these commands work the same for example having the 2 launch pads talk to each other?

    Also can you explain little more what P_TEMP, P_CONFIG is doing?
    If I had to guess:

    you sending “hey let me read the temp value”
    the temp sensor says “dude its XYZ”

    and then your taking that data and doing some math to it to make it look pretty. Correct?

    • kwong says:

      The examples shown here are for I2C master only. If you need to have two Launchpads talking to each other you will need to configure one as slave.

      P_TEMP, P_CONF, P_THYST and P_TOS are register pointers telling the chip what command the next byte is. Please refer to DS7505’s datasheet for more detailed information.

  3. Kevin says:

    How would the i2c.c library be translated if I have the USCI peripheral instead of the USI?
    Is it possible? Has someone done it already?

    Thanks, Kevin

  4. Varol Okan says:

    […] Once I had my development environment back up I went ahead and build a LCD driver and started working on the I2C communication between two devices. After a lot of trial and error I came across this link . […]

  5. Y.Ramesh says:

    Hai……
    Iam trying to communicate both master and slave(i2c communication) with two msp430g2553 launchpads. I have wired pin1.7 and pin 1.6 as scl and sda lines between master and slave with 10k pullup resistors. I also removed the jumpers of p1.6(led2). but still data was not transmitting from master to slave. iam using the sample code given by the ti i.e msp430g2xx3_uscib0_i2c_06.c(master) and msp430g2xx3_uscib0_i2c_07.c(slave). plz help me where did i mistake…..

    thanks in advance……..!

    • kwong says:

      I would start by checking whether you get any signals on the SDA or SCL lines (this would be easiest if you have a logic analyzer, but you could use a scope as well). TI’s sample code simply sends a byte over to the slave repetitively, so at the very least, you should see the clock line being toggled when you run the sample code.

  6. Ajit says:

    HI, Any one has code for interfacing ds1307 with MSPg4302553 Series

  7. Barışcan Kayaoğlu says:

    Hello Mr. Kwong. I wanted to try out your code and changed a little for my ITG3200 breakout gyro. Not much change on the protocol except i think you need to send slave address everytime on temperature. In gyro user guide, it indicates that send the start condition, 7 bit slave addr, 1 R/W, an ACK then stop. After that it’s all Start-8bit Data-Stop repeatition. Anyway what i was wondering is, after i debugged the code, in “i2c.c” all of my registers were undefined. I thought that it was because i changed the library to 430g2553 but then i tried with just “MSP430.h” still no luck. Is there something i’m missing or these registers are different on 2553?

    • kwong says:

      Did you change your compiler settings after including 4553 header file? If not sure, I’d recommend start a new project in CCS and make sure the target MCU is 4553. After you create the empty project, you can include i2c.h and i2c.c in the project directory and include in your project.

  8. Barışcan Kayaoğlu says:

    I double checked and it is on MSP family and MSP430g2553 and the two files inside the project. I also added the i2c.h into ti/ccv5/ccs_base/msp430/include aswell

  9. Omri Berg says:

    Hi,
    Great post (along with other great posts you had,it’s been helpful in the past).

    I’m trying to use this library on an msp430g2744 as noted that it should work with just changing the header.
    Unfortunately most of the definitions are missing from the header (just not part of this ucpu although from the same family) – USICTL0, USIPE7, USIPE6, USIMST, USIOE, USISWRST, USILSB, USICKCTL, USIDIV_2, USISSEL_2, USICKPL, USICTL1, USII2C, USISRL,USIGE, USICNT, USIIFG all missing from msp430g2744.h
    Was wondering if you could help me import the library as I’m not sure where to start (or should I leave this library all together)
    Thanks in advance,

  10. Ant says:

    Hi Kerry,

    Great website and know a few people who have used this code in projects now. I was wondering this is for a master, is it possible to modify your code easily so it can be used on a MSP430G2231 as a slave?

    Best regards,

    Ant

  11. Arvin Asokan says:

    Hi Kerry,
    I am currently trying to interface the gyroscope MPU6050 with MSP430G2553 and read the raw gyro values.
    It would be very much better if you could help me with that.

  12. Kevin Fernandes says:

    Hi I am facing a problem with communication.I am not able to detect any waveform on my CRO.Here is the code that i wrote which just sends the eeprom address and initializes start bit,but there is no waveform generated for start bit itself.

    int main(void)
    {

    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    BCSCTL1 = CALBC1_1MHZ;
    DCOCTL = CALDCO_1MHZ;

    P1SEL|=BIT6 + BIT7; //P1.6=SCL,P1.7=SDA
    P1SEL2|=BIT6+ BIT7;
    P1REN|=BIT6 + BIT7;
    P1OUT|=BIT6+ BIT7;

    init_i2c();

    i2c_start(SLAVE_ADDRS_WR);
    __delay_cycles(20000);

    return 0

    }

    void init_i2c()
    {

    UCB0CTL1|=UCSWRST;
    UCB0CTL0|=UCMST + UCMODE_3 + UCSYNC;
    UCB0CTL1|=UCSSEL_2 + UCSWRST;
    UCB0BR1=0;
    UCB0BR0=12; //SMCLK/10=100KHZ
    UCB0CTL1 &= ~UCSWRST ;

    }
    //———————————————————————
    void i2c_start(unsigned char addrs)
    {
    UCB0I2CSA=addrs;
    if(addrs == SLAVE_ADDRS_WR)
    UCB0CTL1| = UCTR; //ENABLE in Tx mode
    else if(addrs == SLAVE_ADDRS_RD)
    UCB0CTL1& = ~ UCTR; //ENABLE in Rx mode
    UCB0CTL1| = UCTXSTT; //set transmiter mode and enable start bit

    }

    It would be of great help to me if you could guide me.

  13. Binu Kutyadan says:

    Hi,
    what are the changes must be done when using msp430g2553 as controller. I simply change the headder controller name , but a lot of error. Is it possible to change the library for msp430g2553?
    I am trying other codes but problem in address shifting.Can you please help

  14. Prathyusha says:

    I have used the i2c library with msp430g2231 to communicate with eeprom 24lc512. The eeprom sends acknowledge signal and all but after writing a value into an address location, when I tried to read back all I get is FF. (I have also waited for the write cycles to complete). I got the same problem without using the library also. Has anyone encountered a similar problem? If so plz help!

Leave a Reply to Y.Ramesh