Jump to content
_Murphy_

Need help with I2C using MSP430g2553

Recommended Posts

Over the past week I have been attempting to get my MSP430g2553 to act as the master and talk to an MPU-6050 which is the slave.

 

I have so far only been able to get it to receive an ACK to the slave, and the code indicates that it is present and listening. My attempts at writing and reading from the slave have produced no results.

 

Does anyone have any advice or recommendations on how to proceed with this?

Share this post


Link to post
Share on other sites

Ok. This is the code I have so far. I currently can verify that it is working up to the if statement that checks if the slave is present. I also have included an attachment of the Read sequence that is in the data sheet.

 

post-30754-0-67371700-1358279344_thumb.png

 

All comments are welcome.

 

#include "msp430g2553.h"
#include "TI_USCI_I2C_master.h"

#define MPU6050_I2C_ADDRESS 	0x68 // Confirmed correct address + communication
#define prescale 				0x14 // 400kHz
#define MPU6050_PWR_MGMT_1      0x6B // Power management register: write 0x00 to wake the device
#define MPU6050_ACCEL_XOUT_H    0x3B // Read
#define MPU6050_ACCEL_YOUT_H    0x3D // Read
#define MPU6050_ACCEL_YOUT_L    0x3E // Read
#define MPU6050_ACCEL_ZOUT_H    0x3F // Read
#define MPU6050_ACCEL_ZOUT_L    0x40 // Read
#define MPU6050_TEMP_OUT_H      0x41 // Read
#define MPU6050_TEMP_OUT_L      0x42 // Read
#define MPU6050_GYRO_XOUT_H     0x43 // Read
#define MPU6050_GYRO_XOUT_L     0x44 // Read
#define MPU6050_GYRO_YOUT_H     0x45 // Read
#define MPU6050_GYRO_YOUT_L     0x46 // Read
#define MPU6050_GYRO_ZOUT_H     0x47 // Read
#define MPU6050_GYRO_ZOUT_L     0x48 // Read

#define MPU6050_AD_R			0xD1
#define MPU6050_AD_W			0xD0

unsigned char timercounter;
unsigned char array[20] = { MPU6050_PWR_MGMT_1, 0x0};
unsigned char array2[20] = { MPU6050_AD_W, MPU6050_GYRO_XOUT_L};
unsigned char store[40] = { 0};


void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer. This line of code is needed at the beginning of most MSP430 projects.
	  	  	  								// This line of code turns off the watchdog timer, which can reset the device after a certain period of time.

  BCSCTL1 = CALBC1_8MHZ; 					// Set clock calibration to 8 MHz
  DCOCTL = CALDCO_8MHZ;						// Internal oscillator to 8 MHz

  _EINT();

  /* initialization of the I2C with the slave */
  TI_USCI_I2C_transmitinit(MPU6050_I2C_ADDRESS,prescale);	// init transmitting with USCI
  while ( TI_USCI_I2C_notready() );         				// wait for bus to be free
  if ( TI_USCI_I2C_slave_present(MPU6050_I2C_ADDRESS) )		// Allow communication if slave was present at address
  {
	  TI_USCI_I2C_transmitinit(MPU6050_I2C_ADDRESS,prescale);  	// Start initialization of the transmission using slave address and frequency using USCI
	  while ( TI_USCI_I2C_notready() );         // wait for bus to be free
	  TI_USCI_I2C_transmit(4,array);       		// start transmitting

	  while ( TI_USCI_I2C_notready() );         // wait for bus to be free between each different connection

	  TI_USCI_I2C_transmitinit(MPU6050_I2C_ADDRESS,prescale);  // Start initialization of the transmission using slave address and frequency using USCI
	  while ( TI_USCI_I2C_notready() );         // wait for bus to be free
	  TI_USCI_I2C_transmit(4,array2);       	// start transmitting

	  while ( TI_USCI_I2C_notready() );         // wait for bus to be free between each different connection

	  TI_USCI_I2C_receiveinit(MPU6050_I2C_ADDRESS,prescale);   // Start initialization of the receiving using slave address and frequency using USCI
	  while ( TI_USCI_I2C_notready() );         // wait for bus to be free
	  TI_USCI_I2C_receive(2,store);
  }
  

  LPM3;
 
}

 

 

Share this post


Link to post
Share on other sites

Hi Murphy! I've been trying to do the exact same thing for the past week with little progress. I Tried using the library provided by TI, but I never got it to read anything from the MPU. I took it upon myself to write the interrupt routines myself and so far I get a response, but sometimes it appears to be valid data, then others garbage. Here is the code I wrote. Can anyone spot where the error is? or have a working library to interface these two devices?

 

#include <msp430g2553.h>

// General Boolean  ///////////////
#define     False                 0
#define     True                  1
///////////////////////////////////

// I2C MPU definitions  ////////
#define		MPU_A			0x68	// MPU 6050 Slave Address
#define		PWR_MGMT_1		0x6B	// Power Management 1 Register Address
#define		SMPLRT_DIV		0x19	// Sample Rate Divider Register Address
#define		CONFIG			0x1A	// Configuration Register Addres
#define		GYRO_CONFIG		0x1B	// Gyroscope Configuration Register Address
#define		ACCEL_CONFIG	0x1C	// Accelerometer Configuration Register Address
#define		INT_ENABLE		0x38	// Interrupt Enable Register Address
#define		INT_PIN_CFG		0x37	// Interrupt Pin Configuration Register Address
////////////////////////////////

// UART definitions  //////////////////////
#define		TXBUF				  UCA0TXBUF	// UART Transfer Buffer
#define		RXBUF				  UCA0RXBUF	// UART Receive Buffer
///////////////////////////////////////////

// Function Prototypes

// I2C
void InitializeI2c(void);
void InitializeMpu(void);
void InitializeInt(void);
void WriteI2c(char MpuReg, char Data);
void ReadI2c(char MpuReg, char *Field, char ByteCnt);
//////////////////////////////////////////////////////

// UART
void SendUart(char *Data);
void InitializeUart(void);
//////////////////////////

// ASCii
void ConvertAscii(char* String);
////////////////////////////////

// Global Variables

// I2C
char I2c_Tx;
char AddSent;
char Register;
char ByteSent;
char RepStart;
char ReadWriteN;
char *I2c_Rx_Field;
signed char I2cByteCnt;
///////////////////////

// UART
char *UartTxStr;
char RxBuffer[14];
char UartRxFlag = False;
char *UartRxStr = RxBuffer;
///////////////////////////

// ASCii
char AsciiStr[12];
//////////////////

/*
 * main.c
 */
void main(void)
{
	
	//char Accel_T_Gyro[14];
	char RX[14];
	char Interrupt;
	WDTCTL = WDTPW + WDTHOLD;
	//DCOCTL = CALDCO_8MHZ;
	//BCSCTL1 = CALBC1_8MHZ;

	InitializeInt();
	//InitializeUart();
	InitializeI2c();
	InitializeMpu();

	for(;{

	LPM0;

	ReadI2c(0x3A,&Interrupt,1);
	if(Interrupt == 0x01)
		ReadI2c(0x42,RX,14);

	//LPM0;
	}
}

//////////////////////////////////////////
// InitializeInt Enables P1.3 Interrupt  /
//	- Hi/Lo Edge Trigger				 /
//////////////////////////////////////////
void InitializeInt(void)
{

	P1IE |= BIT3; // P1.5 interrupt enabled
	P1IES |= BIT3; // P1.5 Hi/lo edge
	P1IFG &= ~BIT3;
}

//////////////////////////////////////////////////////////
// InitializeI2c sets up UCB0 module for I2C operations  /
//	- P1.6 = SCL										 /
//	- P1.7 = SDA										 /
//	- Transfer Rate = 100kHz							 /
//////////////////////////////////////////////////////////
void InitializeI2c(void)
{

	P1SEL |= BIT6 + BIT7; // p1.6 SCL p1.7 SDA
	P1SEL2 |= BIT6 + BIT7;
	UCB0CTL1 |= UCSWRST;	// ensure SWRST high before configuration
	UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;	// Master, I^2C, Synchronous
	UCB0CTL1 = UCSSEL_2 + UCSWRST;	// SMCLK, keep SWRST high
	UCB0BR0 = 12;
	UCB0BR1 = 0;
	UCB0I2CSA = MPU_A;
	UCB0CTL1 &= ~UCSWRST;
	UCB0I2CIE = UCNACKIE;
	IFG2 &= ~(UCB0TXIFG + UCB0RXIFG);
	IE2 |= UCB0TXIE + UCB0RXIE;
}

//////////////////////////////////////////////////////
// InitializeMpu sets up the MPU-6050 for Operation  /
//	- Resets Device									 /
//	- Sample Rate = 10								 /
//	- Accell Full Range								 /
//	- Gyro Full Range								 /
//	- Data Ready Int Enable							 /
//////////////////////////////////////////////////////
void InitializeMpu(void)
{

	WriteI2c(PWR_MGMT_1, 0x80);	// Reset MPU
	__enable_interrupt();	// Wait for MPU to Reset
	TACCR0 = 2000;
	TACCTL0 |= CCIE;
	TA0CTL = TASSEL_2 + MC_1; // SMCLK, up mode
	LPM0;	// Enter low power mode
	TACCTL0 &= ~CCIE;
	__disable_interrupt();	// Done with Reset
	WriteI2c(PWR_MGMT_1, 0x00);
	//WriteI2c(INT_PIN_CFG,0x80);
	WriteI2c(SMPLRT_DIV, 99);	// Sample Rate Divider = 50
	//WriteI2c(CONFIG, 0x06);
	WriteI2c(GYRO_CONFIG, 0x18);	// Gyro Full Range
	WriteI2c(ACCEL_CONFIG, 0x18);	// Accel Full Range
	WriteI2c(INT_ENABLE, 0x01);		// Enable Data Ready Interrupt
}

///////////////////////////////////////////////////////////////////////////
// WriteI2c Writes a single Byte to the Internal Register Address MpuReg  /
//																		  /
// Parameters:															  /
//	- MpuReg = Internal Register Address								  /
//	- Data = Byte to be written to MpuReg								  /
///////////////////////////////////////////////////////////////////////////
void WriteI2c(char MpuReg, char Data)
{

	// Reset variables prior to Start of Transmission
	AddSent = False;
	ReadWriteN = False;
	ByteSent = False;
	I2c_Tx = Data;	// Load Byte to be written to MPU
	Register = MpuReg;	// Load Internal Register Address
	UCB0CTL1 |= UCTR + UCTXSTT;		// send I2C start condition
	__bis_SR_register(CPUOFF + GIE);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////
// Read I2c Reads a user specified number of Bytes and stores them in the String pointed to by *Field  /
//																									   /
// Parameters:																						   /
//	- MpuReg = Internal Register Address to be Read													   /
//	- *Field = Pointer to Storage String															   /
//	- ByteCnt = Number of Bytes to be Read															   /
////////////////////////////////////////////////////////////////////////////////////////////////////////
void ReadI2c(char MpuReg, char *Field, char ByteCnt)
{

	// Reset variables prior to Start of Transmission
	RepStart = False;
	AddSent = False;
	ReadWriteN = True;
	I2cByteCnt = ByteCnt;	// Load number of byte to be read to Global variable
	I2c_Rx_Field = Field;	// Copy pointer for String to be Read
	Register = MpuReg;	// Load Internal Register Address
	UCB0CTL1 |= UCTR + UCTXSTT;		// send I2C start condition
	__bis_SR_register(CPUOFF + GIE);
}

///////////////////////////////////////////////////////////////
// InitializeUart sets up the UCA0 module for UART operation  /
//	- P1.1 = RX												  /
//	- P1.2 = TX												  /
//	- SMLCK source											  /
//	- 9600 Baud												  /
///////////////////////////////////////////////////////////////
void InitializeUart(void)
{

	// UART SET UP P1.2 UCA0TXD P1.1 UCA0RXD
	P1SEL = BIT1 + BIT2;
	P1SEL2 = BIT1 + BIT2;
	UCA0CTL1 |= UCSSEL_2;	// select SMCLK as source
	UCA0BR0 = 104;			// 1MHz/9600 ~ 104.16667
	UCA0BR1 = 0;
	UCA0MCTL = UCBRS0;	// second stage modulation= 1 round((N-int(N))*8)
	UCA0CTL1 &= ~UCSWRST;
	IE2 |= UCA0RXIE;
}

///////////////////////////////////////////////////////////////
// SendUart sends a Null terminated String over the UART bus  /
//															  /
// Parameters:												  /
//	- *Data = Pointer to the Start of String to be sent		  /
///////////////////////////////////////////////////////////////
void SendUart(char *Data)
{

	UartTxStr = Data;
	TXBUF = *UartTxStr++;
	IE2 |= UCA0TXIE;
	__bis_SR_register(CPUOFF + GIE);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ConverAscii Converts a Null terminated string of Hex Values and outputs a string of its Ascii equivalent  /
//																											 /
// Parameters:																								 /
//	- *String = Pointer to beginning of String to be converted												 /
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ConvertAscii(char* String)
{

	char* Str = String;
	char Binary;
	char Ascii;
	char i = 0;

	while(*Str != '\0'){
		Str++;
		i++;
	}
	Str = String;

	char Length = i;

	for(i = 0;i < Length;i++)
	{

		Binary = *Str;
		Binary &= 0xF0;
		Binary =  Binary>>4;
		if(Binary < 10)
			Ascii = Binary + 0x30;
		else
			Ascii = Binary + 0x37;
		AsciiStr[i++] = Ascii;

		Binary = *Str++;
		Binary &= 0x0F;
		if(Binary < 10)
			Ascii = Binary + 0x30;
		else
			Ascii = Binary + 0x37;
		AsciiStr[i] = Ascii;
	}
	AsciiStr[i++] = 0x20;
	AsciiStr[i] = '\0';
}

/////////////////////////////////////////////////
//												/
// 					ISR							/
/////////////////////////////////////////////////
// USCIAB0RX Interrupt Service Routine
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{

	if (UCB0STAT & UCNACKIFG)
	{            // send STOP if slave sends NACK
		UCB0CTL1 |= UCTXSTP;
		UCB0STAT &= ~UCNACKIFG;
	}
	else
	{
		*UartRxStr = RXBUF;
		if(*UartRxStr == '\0')
		{
			UartRxStr = RxBuffer;
			UartRxFlag = True;
		}
		else
			UartRxStr++;
	}
}

// USCIAB0TX Interrupt Service Routine
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void){
	static unsigned char Index = 0;
	// Check Interrupt Source
	// If UCA0TXIE then UART Mode
	if(IE2 & UCA0TXIE)
	{
		if(*UartTxStr == '\0')
		{
			IE2 &= ~UCA0TXIE;
			__bic_SR_register_on_exit(CPUOFF);
		}
		else
			TXBUF = *UartTxStr++;
	}
	// Else I2C Mode
	else{
		// If ReadWriteN = True
		// Read Operation
		if (ReadWriteN)
		{
			// Check if Internal Register Address and Repeated Start have been sent
			// If True Start to Read UCB0RXBUF
			if(RepStart == True && AddSent == True)
			{
				// If Index is not equal to last byte to read
				// Keep reading
				if(Index != I2cByteCnt-1)
				{
					*I2c_Rx_Field++ = UCB0RXBUF;
					Index++;
				}
				// Else Read Last byte and send stop condition
				else
				{
					*I2c_Rx_Field = UCB0RXBUF;
					UCB0CTL1 |= UCTXSTP;	// send stop condition
					while(UCB0CTL1 & UCTXSTP);
					IFG2 &= ~UCB0RXIFG;
					Index = 0;
					__bic_SR_register_on_exit(CPUOFF);
				}
			}
			// Send the Register address Followed by the Repeated Start
			else
			{
				// If Register Address has not been sent. Send Register Address
				if(AddSent == False)
				{
					UCB0TXBUF = Register;
					AddSent = True;
				}
				// If Register Address have been sent. Send Repeated Start.
				else
				{
					IFG2 &= ~UCB0TXIFG;
					UCB0CTL1 &= ~UCTR;
					UCB0CTL1 |= UCTXSTT;
					RepStart = True;
				}
			}
		}
		// If ReadWriteN = False
		// Write Operation
		else
		{
			// Check if Register Address has been sent
			// If True Start Writing to UCB0TXBUF
			if(AddSent == True)
			{
				// Check if Data has been Written to UCB0TXBUF
				// If True the send STOP condition
				if(ByteSent == True)
				{
					UCB0CTL1 |= UCTXSTP;	// send stop condition
					IFG2 &= ~UCB0TXIFG;		// clear Tx flag
					__bic_SR_register_on_exit(CPUOFF);
				}
				// Else Write Data to UCB0TXBUF
				else
				{
					UCB0TXBUF = I2c_Tx;
					ByteSent = True;
				}

			}
			// If Register Address has not been sent. Send it
			else
			{
				UCB0TXBUF = Register;
				AddSent = True;
			}
		}
	}
}

// Timer A0 Interrupt Service Routine
#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER_A0(void){
		LPM0_EXIT;
}

// Port 1 Interrupt Service Routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void){
	LPM0_EXIT;
	P1IFG &= ~BIT3;
	//P1IE &= ~BIT3;
}





Share this post


Link to post
Share on other sites

The I2C code I have has been re-written and it may function correctly now. Once I complete testing on it I will know for sure. 

 

If I can verify my code to be working I will post it on this topic. 

Share this post


Link to post
Share on other sites

Have you managed to get it working?

 

I used the same library of you two and I'm getting confused because sometimes it works, sometimes not...

Share this post


Link to post
Share on other sites

Hello Phaelz,

 

I managed to get it working with the msp430, and recently with the Stellaris (much easier thanks the driverlib). Anyways, if you post your email I will send you my msp430 code which used the grace plug in.

 

Also, as a general note I've found that the debug circuit doesn't do well with any type of external communication. My suggestion is just use either the run to line command, or the reset button itself. (don't step through)

Share this post


Link to post
Share on other sites

What I currently am using I have based it off of another persons code.

 

It is able to compile but after stepping through the debugger I am not 100% certain that the IMU code is working properly.

 

If anyone who may be in the process of doing something similar to this is able to improve upon this code or has another approach please post it.

 

Attached Files:

main.c

I2C_MSP430.c

I2C_MSP430.h

MPU6050.h

MSP430_MPU6050.c

MSP430_MPU6050.h

 

Share this post


Link to post
Share on other sites

What I currently am using I have based it off of another persons code.

 

It is able to compile but after stepping through the debugger I am not 100% certain that the IMU code is working properly.

 

I m trying to interface with ds1307 .please let me know how can interface with g2553 kit.

 

If anyone who may be in the process of doing something similar to this is able to improve upon this code or has another approach please post it.

 

Attached Files:

attachicon.gifmain.c

attachicon.gifI2C_MSP430.c

attachicon.gifI2C_MSP430.h

attachicon.gifMPU6050.h

attachicon.gifMSP430_MPU6050.c

attachicon.gifMSP430_MPU6050.h

Share this post


Link to post
Share on other sites

Since you asked for more code via a Private message. I will share the project I used to test that the I2C was working using the MPU-6050. It has a printf script in it that someone on this forum created.

 

 

MSP430_MPU6050.rar

 

 

Just import this code and connect an MPU-6050 and you should be able to verify that your I2C lines are working through the printf.

Share this post


Link to post
Share on other sites

Since you asked for more code via a Private message. I will share the project I used to test that the I2C was working using the MPU-6050. It has a printf script in it that someone on this forum created.

 

 

attachicon.gifMSP430_MPU6050.rar

 

 

Just import this code and connect an MPU-6050 and you should be able to verify that your I2C lines are working through the printf.

Thanks for sharing.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×