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.

f5529 I2C Interrupt

Other Parts Discussed in Thread: ENERGIA

Hello


I am trying to communicate with a 9DoF stick using I2C on the f5529. I was able to do the same thing using the g2553, but decided to switch to the 5529 because of its higher speed. Therefore, a lot of my code is patched together from my previous work using the 2553. The problem that I am having is that the code never enters the 2nd if statement (tx counter = 1) in the interrupt. What could be causing this? Code is posted below. I am using Energia.

Thanks

#include <msp430f5529.h>

#define ADXL345_ADDRESS (0xA6 >> 1)

//There are 6 data registers, they are sequential starting with th LSB of X.
//We'll read all 6 in a burst and won't address them individually
#define ADXL345_REGISTER_XLSB (0x32)

//Need to set power control bit to wake up the adxl345
#define ADXL_REGISTER_PWRCTL (0x2D)
#define ADXL_PWRCTL_MEASURE (1 << 3)

#define ITG3200_ADDRESS (0xD0 >> 1)
//request burst of 6 bytes from this address
#define ITG3200_REGISTER_XMSB (0x1D)
#define ITG3200_REGISTER_DLPF_FS (0x16)
#define ITG3200_FULLSCALE (0x03 << 3)
#define ITG3200_42HZ (0x03)

#define HMC5843_ADDRESS (0x3C >> 1)
//First data address of 6 is XMSB. Also need to set a configuration register for continuous measurement.

#define HMC5843_REGISTER_XMSB (0x03)
#define HMC5843_REGISTER_MEASMODE (0x02)
#define HMC5843_MEASMODE_CONT (0x00)

int accelerometer_data[3];
int gyro_data[3];
int magnetometer_data[3];

byte i2c_tx_reg;
byte i2c_tx_data;

int tx_counter;
int rx_counter;

int i;

volatile boolean i2c_busy;

byte read_data[6];

#pragma vector= USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void){
  
  if(UCB0IFG & UCTXIFG){                  //Tx interrupt
    
    if(tx_counter == 2){
      
      UCB0TXBUF = i2c_tx_reg;
      tx_counter--;
    }
    
    else if(tx_counter == 1){
      
      UCB0TXBUF = i2c_tx_data;
      tx_counter--;
    }
    
    else if(tx_counter == 0){
      
      UCB0CTL1 |= UCTXSTP;                  //Stop condition
      UCB0IFG &= ~UCTXIFG;                    //Clear interrupt flag
      i2c_busy = false;
    }
  }
}

void init_i2c(void){
  
  UCB0IE &= ~(UCRXIE + UCTXIE);            //Disable RX and TX interrupt

  UCB0CTL1 |= UCSWRST;                       // Enable SW reset
  UCB0CTL0 |= 0x0F;      // I2C Master, synchronous mode
  UCB0CTL1 |= UCSSEL_2 + UCSWRST;             // Use SMCLK, keep SW reset
  UCB0BR0 = 0x80;                              
  UCB0BR1 = 0x00;
  UCB0CTL1 &= ~UCSWRST;                      // Clear SW reset, resume operation
  UCB0IE |= UCRXIE + UCTXIE;                //Enable RX and TX interrupt
  
}

void i2c_write(int address, byte reg, byte data){
  
  while(UCB0CTL1 & UCTXSTP);                //Wait for stop condition to clear
  
  tx_counter = 2;
  
  i2c_busy = true;
  
  UCB0I2CSA = address;                       //Write slave address
  i2c_tx_reg = reg;
  i2c_tx_data = data;
  UCB0CTL0 &= ~UCSLA10;                       //Set size of address to 7-bit
  
  UCB0CTL1 |= UCTR;
  UCB0CTL1 |= UCTXSTT;                //Set for transmitter mode and generate a start condition
  
  while(i2c_busy);                    //Wait for i2c to finish
}

void init_itg3200(){
  
  //Set DLPF to 42 Hz and set the scale to "Full Scale"
  i2c_write(ITG3200_ADDRESS, ITG3200_REGISTER_DLPF_FS, ITG3200_FULLSCALE | ITG3200_42HZ);
}

int main(void){
  
  WDTCTL = WDTPW + WDTHOLD;                  // Stop WDT
    
  P4SEL |= BIT1 + BIT2;
  P4REN |= BIT1 + BIT2;
  init_i2c();
  
  __bis_SR_register(GIE); 
  
  i2c_busy = false;
    
  while(1){
    
   init_itg3200();
  }
}

  •   P4SEL |= BIT1 + BIT2;
      P4REN |= BIT1 + BIT2;

    The internal pull resistors are probably too weak.

    In any case, the default value of P4OUT is undefined, so it's possible you have enabled pull-down resistors.

  • As Clemens pointed out. This might be to do with Pull up resistors. From my experience, I have found that the internal pull ups are weak in Msp430's. It is advisable to have 10k on SDA and SDL as pull ups.

    if you intend to try your luck with internall pull up's. you should be doing some thing like

    P1OUT |= BIT6 + BIT7; // We can enable internal pull-ups
    P1REN |= BIT6 + BIT7; // This line only enables internal resistors.
    the staus in POUT defines, weather pull /pull down.
  • I tried connecting 10k resistors to the 3.3V bus and that didn't work. I also tried doing what you suggested with internal pull ups and that didn't work either. Any other ideas? It's going into the 1st interrupt, but it doesn't seem like the first byte of data is being sent, since I can't pick anything up on my logic analyzer.
  •   UCB0CTL0 |= 0x0F;      // I2C Master, synchronous mode

    If you used the proper symbols instead of a magic number, you wouldn't need the comment.

    Anyway, the reason that the logic analyzer doesn't pick up anything at pins P4.1 and P4.2 is that the UCB0 I²C signals would be at pins P3.0 and P3.1.

  • Absolutely, you are right Clemens. I have just checked the pinout snad the USCI_BO is on p3.0 and P3.1.
    Gabe:
    Either you might have to rewire your board, or swith to USCI_B1.

    here is the sample library that I have used long back for a project of mine. Hope you can use it as it fis developed for F5510.

    #include "I2CMaster.h"
    //#include <msp430f5510.h>
    
    volatile uint16_t 	I2CNumBytes;
    volatile uint16_t	Ack;
    volatile uint8_t	   *I2CRxBuffer, *I2CTxBuffer;
    
    volatile uint16_t	I2CStop;
    volatile uint16_t	Stop_Ticks = 0, Start_Ticks = 0, I2C_Ticks = 0;
    
    void I2CInit( void )
    {
    	P4SEL  |= BIT2 + BIT1;					// Assign I2C pins to USCI_B1
    
    	P4OUT |= BIT2 + BIT1;					// We can enable internal pull-ups
    	P4REN |= BIT2 + BIT1;
    
    	UCB1CTL1    |= UCSWRST;												// Enable SW reset
    	UCB1CTL0    = UCMST + UCMODE_3 + UCSYNC;		    // 7-bit addressing, single-master environment, I2C Master, synchronous mode
    	UCB1CTL1    = UCSSEL_2 + UCSWRST;							// Use SMCLK, keep SW reset
    	UCB1BR0      = I2C_400KHZ;												// fSCL = SMCLK/UCB0BR0
    	UCB1BR1      = 0;
    	UCB1CTL1 &= ~UCSWRST;												// Clear SW reset, resume operation
    	UCB1IE        |= UCNACKIE + UCTXIE + UCRXIE;    // Enable not-acknowledge interrupt TX&RX interrupts
    }
    
    uint16_t I2CWrite( uint8_t sladdr , uint8_t *data , uint16_t n )
    {
    	Ack = 1;							// Return value
        I2CTxBuffer = data;					// TX array start address
        I2CNumBytes = n;                  	// Update counter
    	UCB1I2CSA = sladdr;  				// Slave address (Right justified, bits6-0)
        //
    	while( (UCB1CTL1 & UCTXSTP));
        UCB1CTL1 |= UCTR + UCTXSTT;			// Send I2C start condition, I2C TX mode
        //
        do{
        	_BIS_SR(LPM0_bits + GIE);
        		_DINT();
          }while( I2CNumBytes && Ack );
         	_EINT();
       	//SetUp WDT with 2ms Interval, don't enable Interrupts, we are monitoring WDTInettupt flag here for condition.
    	SFRIFG1    &= ~WDTIFG;
    	SFRIE1 	   &= ~WDTIE;
    	WDTCTL   = WDT_MDLY_32;
    	while( (UCB1CTL1 & UCTXSTP) && (!(SFRIFG1 & WDTIFG)) );		// I2C stop condition sent?
    	Stop_WDT();
    	UCB1CTL1 &= ~UCTXSTP;
    
    	return Ack;
    }
    
    uint16_t I2CRead( uint8_t sladdr , uint8_t *data , uint16_t n )
    {
    	//
    	Ack = 1;							// Return value
    	// 
        I2CRxBuffer = data;					// Start of RX buffer
        UCB1I2CSA = sladdr;					// Slave address (Right justified, bits6-0)
        //
        UCB1CTL1 &= ~UCTR;			// I2C RX mode
        //
        if( n == 1 )
        {
        	I2CNumBytes = 0;				    // Update counter
    
        	_DINT();
        	UCB1CTL1 |= UCTXSTT;			// Send I2C start condition, I2C RX mode
       		while( (UCB1CTL1 & UCTXSTT) );		// I2C start condition sent?
        	UCB1CTL1 |= UCTXSTP;			// Send I2C stop condition
        	I2CStop = 1;					// I2C stop condition sent
        	_BIS_SR(LPM0_bits + GIE);
        }
        else if( n > 1 )
        {
        	I2CStop = 0;					// I2C stop condition not sent yet
        	I2CNumBytes = n - 2;			// Update counter
    		//SetUp WDT with interval of 2ms (default)
    		__disable_interrupt();
        	UCB1CTL1 |= UCTXSTT;			// Send I2C start condition
        	//We are looking for NACK Interrupt. THis interrupt will make ACK = 0 if there is no Acknowledge.
        	do
        	{
        		_BIS_SR(LPM0_bits + GIE);
        		_DINT();
        	}while( I2CNumBytes && Ack );
        	_EINT();
    
        	SFRIFG1  &= ~WDTIFG;
        	SFRIE1 &= ~WDTIE;
        	WDTCTL = WDT_MDLY_32;
        	while( (UCB1CTL1 & UCTXSTP) && (!(SFRIFG1 & WDTIFG) ));		// I2C stop condition sent?
        	Stop_WDT();
       		UCB1CTL1 &= ~UCTXSTP;
        }//else if( n > 1 )
    	return Ack;
    }
    
    #pragma vector = USCI_B1_VECTOR
    __interrupt void USCI_B1_ISR(void)
    {
    	switch(__even_in_range(UCB1IV,0x0C)) {
    		case 0x00: // Vector 0: No interrupts
    						break;
    		case 0x02: // Vector 2: UCALIFG
    						// Arbitration-lost. When UCALIFG is set the UCMST bit is cleared and the I2C
    						// controller becomes a slave. This can only happen in a multimaster environment
    						break;
    		case 0x04: // Vector 4: UCNACKIFG  ---> Not-acknowledge interrupt.
    						// This flag is set when an acknowledge is expected, but is not received.
    						// UCNACKIFG is automatically cleared when a START condition  is received.
    						UCB1CTL1 |= UCTXSTP;			// I2C stop condition
    						Ack = 0;						// Return value
    						UCB1IFG &= ~UCNACKIFG;			// Clear interrupt flag
    						_low_power_mode_off_on_exit( );		// Exit LPM0
    						break;
    		case 0x06:  // Vector 6: UCSTTIFG
    						  // Start condition detected interrupt. UCSTTIFG only used in slave mode.
    					   break;
    		case 0x08:  // Vector 8: UCSTPIFG
    			              // Stop condition detected interrupt. UCSTPIFG only used in slave mode.
    			           break;
    	    //------------------------------------------------------------------------------------------------------------------------------------------------
    		case 0x0a:  // Vector 10: UCRXIFG
    						if( I2CNumBytes == 0 )
    						{
    							// I2CStop is used just to make sure that we leave LPM0 at the right time and not before
    							if( I2CStop )
    							{
    								_low_power_mode_off_on_exit( );		// Exit LPM0
    							}
    							else
    							{
    								UCB1CTL1 |= UCTXSTP;                // I2C stop condition
    								I2CStop = 1;						                // I2C stop condition sent
    							}
    						}
    						else
    						{
    							I2CNumBytes--;							// Decrement counter
    						}
    						*I2CRxBuffer++ = UCB1RXBUF;					// Read RX data. This automatically clears UCB0RXIFG
    						break;
    		//------------------------------------------------------------------------------------------------------------------------------------------------
    		case 0x0c:  // Vector 14: UCTXIFG
    						if( I2CNumBytes )							// Check counter
    						{
    							UCB1TXBUF = *I2CTxBuffer++;         	// Load TX buffer. This automatically clears UCB0TXIFG
    							I2CNumBytes--;							// Decrement counter
    						}
    						else
    						{
    							UCB1CTL1 |= UCTXSTP;                    // I2C stop condition
    							UCB1IFG &= ~UCTXIFG;                     // Clear USCI_B0 TX int flag
    							_low_power_mode_off_on_exit( );			// Exit LPM0
    						}
    						break;
    		//------------------------------------------------------------------------------------------------------------------------------------------------
    		default: break;
    	}
    }
    
    #pragma vector=WDT_VECTOR
     __interrupt void WDT_ISR(void)
    {
        /* clear the interrupt flag for Watchdog timer */
        SFRIFG1 &= ~WDTIFG;
        Ack = 0;
        _low_power_mode_off_on_exit( );			// Exit LPM0
    }
    
    
    #ifdef	I2C_PING
    uint16_t I2CPing( uint8_t sladdr )
    {
    	//
        UCB0I2CSA = sladdr;  					// Slave address (Right justified, bits6-0)
        //
        __disable_interrupt();
        UCB0CTL1 |= UCTR + UCTXSTT + UCTXSTP;	// I2C start condition, I2C TX mode, I2C stop condition
        while( UCB0CTL1 & UCTXSTP );			// I2C stop condition sent?
        Ack = !(UCB0STAT & UCNACKIFG);			// I2C start condition akd'd or not?
        __enable_interrupt();
    	//
    	return Ack;
    }
    #endif	/* !I2C_PING */
    

    here is I2CMaster.h

    #ifndef I2C_MASTER_H_
    #define I2C_MASTER_H_
    
    #include <msp430.h>
    
    #define	INLINE		inline
    
    #include <stdint.h>
    
    // Clock pre-scaler values, assuming F_CPU=16MHz
    #define	I2C_50KHZ		320 //need to update this value
    #define	I2C_100KHZ		160
    #define	I2C_400KHZ		40
    #define	I2C_800KHZ		20
    #define	I2C_615KHZ		26
    #define	I2C_593KHZ		27
    #define	I2C_1MHZ		16
    
    // Device addresses, right justified
    //--------------------ACCELEROMETER----------------------------------
    #define	LIS3DH_ADDR			0x19
    //--------------------DAC----------------------------------
    #define	DAC_ADDR			0x4D
    //-----------------------EEPROM--------------------------------------
    #define	EEPROM_ADDR			0x50 //STARTING ADDRESS 0X0 00 00
    
    #define	EEPROM_ADDR_64KB	0x51 //STARTING ADDRESS 0X1 00 00
    
    #define	EEPROM_ADDR_128KB	0x52 //STARTING ADDRESS 0X2 00 00
    
    #define	EEPROM_ADDR_256KB	0x53 //STARTING ADDRESS 0X3 00 00
    //--------------------aUDIENCE ES310----------------------------------
    #define	ES310_I2CADDR	    0x3E
    
    #define I2CReset() UCB0CTL1 &= ~UCSWRST; UCB0CTL1 |= UCSWRST;
    
    #define set_1MHZ() 				UCB0BR0 = I2C_1MHZ;
    #define set_800KHZ() 			UCB0BR0 = I2C_800KHZ;
    #define set_615KHZ() 			UCB0BR0 = I2C_615KHZ;
    #define set_593KHZ() 			UCB0BR0 = I2C_593KHZ;
    #define set_400KHZ() 			UCB0BR0 = I2C_400KHZ;
    
    //Configure WatchDog timer
    /*
     * 15 14 13 12 11 10 9 8
    WDTPW, Read as 069h Must be written as 05Ah
    7 		6 		 5		4 		 3 		  2 	  1- 0
    WDTHOLD WDTNMIES WDTNMI WDTTMSEL WDTCNTCL WDTSSEL WDTISx
    rw-0 	rw-0 	 rw-0 	rw-0 	 r0(w) 	  rw-0 	  (rw-0 rw-0)
    WDTPW Bits 15-8 Watchdog timer+ password. Always read as 069h. Must be written as 05Ah, or a PUC is generated.
    WDTHOLD Bit 7 Watchdog timer+ hold. This bit stops the Watchdog timer+. Setting WDTHOLD = 1 when the WDT+ is not in use conserves power.
     	 	 	 0 Watchdog timer+ is not stopped
     	 	 	 1 Watchdog timer+ is stopped
    WDTNMIES Bit 6 Watchdog timer+ NMI edge select. This bit selects the interrupt edge for the NMI interrupt when WDTNMI = 1.
    			  Modifying this bit can trigger an NMI. Modify this bit when WDTIE = 0 to avoid triggering an accidental NMI.
    			 0 NMI on rising edge
    			 1 NMI on falling edge
    WDTNMI Bit 5 Watchdog timer+ NMI select. This bit selects the function for the RST/NMI pin.
    			 0 Reset function
    			 1 NMI function
    WDTTMSEL Bit 4 Watchdog timer+ mode select
    			 0 Watchdog mode
    			 1 Interval timer mode
    WDTCNTCL Bit 3 Watchdog timer+ counter clear. Setting WDTCNTCL = 1 clears the count value to 0000h. WDTCNTCL is automatically reset.
    			 0 No action
    			 1 WDTCNT = 0000h
    WDTSSEL  Bit 2 Watchdog timer+ clock source select
    			 0 SMCLK
    			 1 ACLK
    WDTISx Bits  1-0 Watchdog timer+ interval select. These bits select the watchdog timer+ interval to set the WDTIFG flag and/or generate a PUC.
     	 	 	 FOr DC0 at 16MHZ (lets say we are using SMCLk) then the approx interval u get is
     	 	 	 For ACLK the approx interval u get is
     	 	 	 |----------------------------------------------------------------------------------------------|
     	 	 	 | ---------->BIT selection<----------	|         16MHZ SMCLK           |			ACLK        |
     	 	 	 |----------------------------------------------------------------------------------------------|
    			 |00 Watchdog clock source /32768  		|		 2ms(0.512ms * 4)       |						|
    			 |01 Watchdog clock source /8192		|		 0.512ms (32us * 16)    |						|
    			 |10 Watchdog clock source /512 		|		 32us (4us * 8)         |						|
    			 |11 Watchdog clock source /64			|		 4us                    |						|
    			 |----------------------------------------------------------------------------------------------|
    
     */
    //-------------------------------------------------------------------------------------------------------------
    //						<-- clear IFG -->  <Enable interrupt>  <-------SET-UP----->   						//|
    #define Start_WDT() 	IFG1  &= ~WDTIFG;     IE1|= WDTIE; 	   WDTCTL = WDT_MDLY_32;                        //|
    //					<---   STOP WDT   ----->  																//|
    #define Stop_WDT() 	WDTCTL = WDTPW + WDTHOLD;															    //|
    //-------------------------------------------------------------------------------------------------------------
    void I2CInit( void );
    void I2CInit_CM( void );
    void I2CClose( void );
    uint16_t I2CWrite( uint8_t , uint8_t * , uint16_t );
    uint16_t I2CRead( uint8_t , uint8_t * , uint16_t );
    
    #ifdef	I2C_PING
    uint16_t I2CPing( uint8_t );
    #endif	/* !I2C_PING */
    
    #endif /*I2C_MASTER_H_*/
    

  • Oops. I must have read the pinout diagram wrong. That definitely was the problem. Thanks!

**Attention** This is a public forum