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.

HMC5883L i2c problem

Other Parts Discussed in Thread: MSP430F5529

Hi,

I am using msp430f5529 and I have some communicate  problem with the HMC5883L magnetometer via i2C. I had made a lot of tries but I can not read any data from it.  I tried to write the next OPERATIONAL EXAMPLES that writen in the datasheet but it dosent work. I would like to hear ideas what is the problem in my code.

here is my code:

#include <msp430.h>
#include <msp430f5529.h>


#define NUM_BYTES_TX 3 // How many bytes?

#define NUM_BYTES_RX 6

#define HMC_5883 0x1E //address for write

int RXByteCtr, RPT_Flag = 0;

volatile unsigned char RxBuffer[6]; // Allocate 6 byte of RAM

unsigned char *PRxData; // Pointer to RX data

unsigned char TXByteCtr, RX = 0;

unsigned char MSData[4];

int magnetometer_data[3];

void Setup_TX(unsigned char);

void Setup_RX(unsigned char);

void Transmit(unsigned char,unsigned char,unsigned char);
void TransmitN(unsigned char,unsigned char);

void Receive(void);

int main(void)

{
int i;

WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P4SEL |= BIT1 + BIT2; // Assign I2C pins to USCI_B1
P1DIR |=BIT5;
P1DIR |=BIT1;
P1OUT |=BIT5;

// Init sequence for hmc5883l

//Transmit process

Setup_TX(HMC_5883);

RPT_Flag = 1;

Transmit(0x3C,0x00,0x70);

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent


Setup_TX(HMC_5883);

RPT_Flag = 1;

Transmit(0x3C,0x01,0xA0);

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

Setup_TX(HMC_5883);

RPT_Flag = 1;

Transmit(0x3C,0x02,0x00); // Request Data from HMC5883

Setup_RX(0x1E);
while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent


while(1){

//Transmit process


Setup_TX(HMC_5883);

RPT_Flag = 1;

TransmitN(0x3D,0x06); // Request Data from HMC5883

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

//Receive process

Setup_RX(0x1E);

Receive();

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

for ( i=0;i<3;i++)
{
magnetometer_data[i] = (int)RxBuffer[2*i + 1] + ((int)RxBuffer[2*i]<<8);

}


__delay_cycles(10000); // sample rate ~100 samples/sec

// you can change by changing delay

}


}

//-------------------------------------------------------------------------------

// The USCI_B0 data ISR is used to move received data from the I2C slave

// to the MSP430 memory. It is structured such that it can be used to receive

// any 2+ number of bytes by pre-loading RXByteCtr with the byte count.

//-------------------------------------------------------------------------------

#pragma vector = USCI_B1_VECTOR

__interrupt void USCI_B1_ISR(void)

{

if(RX == 1){ // Master Recieve?

RXByteCtr--; // Decrement RX byte counter

if (RXByteCtr)

{

*PRxData++ = UCB1RXBUF; // Move RX data to address PRxData

}

else

{

if(RPT_Flag == 0)

UCB1CTL1 |= UCTXSTP; // No Repeated Start: stop condition

if(RPT_Flag == 1){ // if Repeated Start: do nothing

RPT_Flag = 0;

}

*PRxData = UCB1RXBUF; // Move final RX data to PRxData

__bic_SR_register_on_exit(CPUOFF); // Exit LPM0

}}

else{ // Master Transmit

if (TXByteCtr) // Check TX byte counter

{

UCB1TXBUF = MSData[TXByteCtr]; // Load TX buffer

TXByteCtr--; // Decrement TX byte counter

}

else

{

if(RPT_Flag == 1){

RPT_Flag = 0;

TXByteCtr = NUM_BYTES_TX; // Load TX byte counter

__bic_SR_register_on_exit(CPUOFF);

}

else{

UCB1CTL1 |= UCTXSTP; // I2C stop condition

UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag

__bic_SR_register_on_exit(CPUOFF); // Exit LPM0

}

}

}

}

void Setup_TX(unsigned char Dev_ID){

_DINT();

RX = 0;

UCB1IE &= ~UCRXIE;

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent// Disable RX interrupt

UCB1CTL1 |= UCSWRST; // Enable SW reset

UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode

UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset

UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz

UCB1BR1 = 0;

UCB1I2CSA = Dev_ID; // Slave Address is 048h

UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation

UCB1IE |= UCTXIE; // Enable TX interrupt

}

void Setup_RX(unsigned char Dev_ID){

_DINT();

RX = 1;

UCB1IE &= ~UCTXIE;

UCB1CTL1 |= UCSWRST; // Enable SW reset

UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode

UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset

UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz

UCB1BR1 = 0;

UCB1I2CSA = Dev_ID; // Slave Address is 048h

UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation

UCB1IE |= UCRXIE; // Enable RX interrupt

}

void Transmit(unsigned char Reg_ADD,unsigned char Reg_DAT,unsigned char Reg_DAT2){

MSData[3]= Reg_ADD;

MSData[2]= Reg_DAT;
MSData[1]= Reg_DAT2;

TXByteCtr = NUM_BYTES_TX; // Load TX byte counter

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

}
void TransmitN(unsigned char Reg_ADD,unsigned char Reg_DAT){

MSData[2]= Reg_ADD;

MSData[1]= Reg_DAT;
//MSData[1]= Reg_DAT2;

TXByteCtr = 2; // Load TX byte counter

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

}

void Receive(void){

PRxData = (unsigned char *)RxBuffer; // Start of RX buffer

RXByteCtr = NUM_BYTES_RX; // Load RX byte counter

while (UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent

UCB1CTL1 |= UCTXSTT; // I2C start condition

__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

}

  • It looks like you are sending the start byte (0x3c) as data. You must not do it. The UCB1I2CSA register gets the slave address. When setting the UCTXSTT bit, the USCI will automatically assemble the proper start byte and send it. The TXBUF only takes plain data.

  • So I should not suppose to use the start bit in anyway?  Does it done automatically? 

    I will try it tomorrow.

    Thanks

  • Also, please use the code formatter when posting code to the forum.

  • Hi ,

    Thanks for your help. I tried what you said and I stopped sending the start byte (0x3c, 0x3d), and I rearrange my code a little bit but, I am still receiving constant data that does not change. I would like to hear any  ideas what may be the problem in my code (my source code is below).

    #include <msp430.h>
    #include <msp430f5529.h>
    #include <inttypes.h>
    
    #define NUM_BYTES_TX 2                         // How many bytes?
    
    #define NUM_BYTES_RX 6
    
    #define HMC5883     0x1E
    
    int RXByteCtr, RPT_Flag = 0;       // enables repeated start when 1
    
    volatile unsigned char RxBuffer[6];         // Allocate 6 byte of RAM
    
    unsigned char *PRxData;                     // Pointer to RX data
    
    unsigned char TXByteCtr, RX = 0;
    unsigned int magnetometer_data[3];
    unsigned char MSData[3];
    
    
    
    void Setup_TX(unsigned char);
    
    void Setup_RX(unsigned char);
    
    void Transmit(unsigned char,unsigned char);
    
    uint8_t Receive(unsigned char);
    
    
    
    int main(void)
    
    {
    	int i;
    	WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
    	P4SEL |= BIT1 + BIT2;                            // Assign I2C pins to USCI_B1
    	P1DIR |=BIT5;
    	P1DIR |=BIT1;
    	  P1OUT |=BIT5;
    
    	  Setup_TX(HMC5883);
    	  RPT_Flag = 0;
    	  Transmit(0x00,0x70);
    	  while (UCB1CTL1 & UCTXSTP);              // Ensure stop condition got sent
    
    	  Setup_TX(HMC5883);
    	  RPT_Flag = 0;
    	  Transmit(0x01,0xA0);
    	  while (UCB1CTL1 & UCTXSTP);
    
    	  Setup_TX(HMC5883);
    	  RPT_Flag = 0;
    	  Transmit(0x02,0x00);
    	  while (UCB1CTL1 & UCTXSTP);
    
    
      while(1){
    
    
    
      //Receive process
    	      RxBuffer[0]= Receive(0x03);			//Data Output X MSB Register
    	      RxBuffer[1]=Receive(0x04);			//Data Output X LSB Register
    	      RxBuffer[2]=Receive(0x07);			//Data Output Y MSB Register
    	      RxBuffer[3]=Receive(0x08);			//Data Output Y LSB Register
    	      RxBuffer[4]=Receive(0x05);			//Data Output Z MSB Register
    	      RxBuffer[5]=Receive(0x06);			//Data Output Z LSB Register
      while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
    
      for ( i=0;i<3;++i) {
    	  magnetometer_data[i] = (int)RxBuffer[2*i + 1] + (((int)RxBuffer[2*i]) << 8);
        }
    
    
    
    
    
      __delay_cycles(10000);  // sample rate ~100 samples/sec
    
                                                // you can change by changing delay
    
      }
    
    }
    
    
    
    //-------------------------------------------------------------------------------
    
    // The USCI_B1 data ISR is used to move received data from the I2C slave
    
    // to the MSP430 memory. It is structured such that it can be used to receive
    
    // any 2+ number of bytes by pre-loading RXByteCtr with the byte count.
    
    //-------------------------------------------------------------------------------
    
    #pragma vector = USCI_B1_VECTOR
    
    __interrupt void USCI_B1_ISR(void)
    
    {
    
      if(RX == 1){                              // Master Recieve?
    
      RXByteCtr--;                              // Decrement RX byte counter
    
      if (RXByteCtr)
    
      {
    
        *PRxData++ = UCB1RXBUF;                 // Move RX data to address PRxData
    
      }
    
      else
    
      {
    
        if(RPT_Flag == 0)
    
            UCB1CTL1 |= UCTXSTP;                // No Repeated Start: stop condition
    
          if(RPT_Flag == 1){                    // if Repeated Start: do nothing
    
            RPT_Flag = 0;
    
          }
    
        *PRxData = UCB1RXBUF;                   // Move final RX data to PRxData
    
        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
    
      }}
    
    
    
      else{                                     // Master Transmit
    
          if (TXByteCtr)                        // Check TX byte counter
    
      {
    
        UCB1TXBUF = MSData[TXByteCtr];          // Load TX buffer
    
        TXByteCtr--;                            // Decrement TX byte counter
    
      }
    
      else
    
      {
    
        if(RPT_Flag == 1){
    
        RPT_Flag = 0;
    
        TXByteCtr = NUM_BYTES_TX;                // Load TX byte counter
    
        __bic_SR_register_on_exit(CPUOFF);
    
        }
    
        else{
    
        	UCB1CTL1 |= UCTXSTP;                  // I2C stop condition
    
        UCB1IFG &= ~UCTXIFG;                     // Clear USCI_B1 TX int flag
    
        __bic_SR_register_on_exit(CPUOFF);      // Exit LPM0
    
        }
    
      }
    
     }
    
    
    
    }
    
    
    
    void Setup_TX(unsigned char Dev_ID){
    
      _DINT();
    
      RX = 0;
    
      UCB1IE &= ~UCRXIE;
    
      while (UCB1CTL1 & UCTXSTP);               // Ensure stop condition got sent// Disable RX interrupt
    
      UCB1CTL1 |= UCSWRST;                      // Enable SW reset
    
      UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC;     // I2C Master, synchronous mode
    
      UCB1CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
    
      UCB1BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
    
      UCB1BR1 = 0;
    
      UCB1I2CSA = Dev_ID;                         // Slave Address is 048h
    
      UCB1CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
    
      UCB1IE |= UCTXIE;                          // Enable TX interrupt
    
    }
    
    
    
    void Transmit(unsigned char Reg_ADD,unsigned char Reg_DAT){
    
        MSData[2]= Reg_ADD;
    
           MSData[1]= Reg_DAT;
    
        TXByteCtr = NUM_BYTES_TX;                  // Load TX byte counter
    
        while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
    
        UCB1CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts
    
    }
    
    uint8_t Receive(unsigned char Reg_AD){
    		uint8_t receivedByte;
    		Setup_TX(HMC5883);
    	    while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
    	    UCB1CTL1 |= UCTR + UCTXSTT;             // I2C TX, start condition
    	    while((UCB1IFG & UCTXIFG)==0);
    	    UCB1TXBUF = Reg_AD;          // Load TX buffer
    	    while((UCB1IFG & UCTXIFG)==0);
    	    UCB1CTL1 &= ~UCTR;
    	    UCB1CTL1 |= UCTXSTT + UCTXNACK;
    	    while (UCB1CTL1 & UCTXSTT);
    	    receivedByte=UCB1RXBUF;
    	    UCB1CTL1 |=UCTXSTP;
    	    return receivedByte;
    
    
    }
    

    
    

     

     

     

  • roy mintz said:
    So I should not suppose to use the start bit in anyway?  Does it done automatically? 

    Yes, the USCI assembles and sends the start byte(!) and check the ACK on its own when you set the UCTXSTT bit. TXBUF is only for plain data.
    More (and some other things) are found in my answer to your other thread here: http://e2e.ti.com/support/microcontrollers/msp430/f/166/p/351928/1235278.aspx#1235278

**Attention** This is a public forum