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.

MSP430 I2C multi master mode



Hi All,

I am working on I2C multi master mode of MSP430. I checked with TI sample application but there is no any application which is demonstrate MSP430 as multi-master mode.

Can any body give me sample application which is demonstrate MSP430 in multi master mode? What care I should take when arbitration occur? I developed my application which is runs MSP430 in multi-master moder. In my application I am taking care of arbitration but it is some time hang when it read data from i2c slave.

My observation is that when arbitration occur my MSP430 become slave mode, so I am giving reset to I2C controller and set MSP as Master and giving STOP condition.

Here is the code for arbitration interrupt.

        UCB0IFG &= ~UCALIFG; 
        UCB0CTL1 |= UCSWRST;                      // Enable SW reset
        UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC+ UCMM;     // I2C Master, synchronous mode
        UCB0I2COA = 0x24;
        UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
        UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
        UCB0BR1 = 0;
        UCB0I2CSA = 0x09;                         // Slave Address is 048h
        UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation     
       // __delay_cycles(20);                     // Delay required between transaction
          UCB0CTL1 |= UCTXSTP;
          __delay_cycles(30);                     // Delay required between transaction

What I am missing for I2C multi -Master mode of MSP430? Can any body help me?  My ultimate goal is read/write on slave using MSP430 in multi-master mode.

 

Thanks & Regards

Hitesh Patel

  • Krunal Patil said:
    I checked with TI sample application but there is no any application which is demonstrate MSP430 as multi-master mode.

    For a reason. This is rather complex and subject for an appnote rather than a simple example. And it is so uncommon that maybe nobody bothered to invest his time writing one.

    Krunal Patil said:
    What care I should take when arbitration occur

    Arbitration occurs (or is detected) when your master wants to send a high bit but detects a low bit on the data line. Then someone else must have put this bit there (another master). Since until this point the data (actually the slave address) was identical, no harm is done and the 'loser' simply aborts its operation, silently for the bus.
    You need to wait then until a stop condition is detected, and you can try anew.

    Krunal Patil said:
    My observation is that when arbitration occur my MSP430 become slave mode

    Yes. When another master was sending, then you might be the target, so the I2C module goes into slave mode.

    Krunal Patil said:
    I am giving reset to I2C controller and set MSP as Master and giving STOP condition.

    No. Forcibly sending a stop will interrupt the other masters transfer. You rather need to wait for a stop being detected, then reset the I2C module and restart the transfer.

  • Thanks Jens-Michael fro your quick response,

    So when I get arbitration flag, My MSP become slave and check for STOP condition,when stop condition flag is set, I have to reset my MSP and then start to read/write data on my slave.

    I will check it and get back to you if I have any query,,,

    Here I am attaching the code which I have implemented. It works for few arbitration then gets hang.

    //******************************************************************************
    //  MSP430F54x Demo - USCI_B0 I2C Master RX multiple bytes from MSP430 Slave
    //
    //  Description: This demo connects two MSP430's via the I2C bus. The slave
    //  transmits to the master. This is the MASTER CODE. It continuously
    //  receives an array of data and demonstrates how to implement an I2C
    //  master receiver receiving multiple bytes using the USCI_B0 TX interrupt.
    //  ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.045MHz
    //
    //                                /|\  /|\
    //                MSP430F5438     10k  10k     MSP430F5438
    //                   slave         |    |         master
    //             -----------------   |    |   -----------------
    //           -|XIN  P3.1/UCB0SDA|<-|----+->|P3.1/UCB0SDA  XIN|-
    //            |                 |  |       |                 |
    //           -|XOUT             |  |       |             XOUT|-
    //            |     P3.2/UCB0SCL|<-+------>|P3.2/UCB0SCL     |
    //            |                 |          |                 |
    //
    //   M Smertneck / W. Goh
    //   Texas Instruments Inc.
    //   September 2008
    //   Built with CCE Version: 3.2.2 and IAR Embedded Workbench Version: 4.11B
    //******************************************************************************
    
    #include "msp430x54x.h"
    
    char temp_Rx=0;
    
    unsigned char *PTxData;                     // Pointer to TX data
    unsigned char TXByteCtr;
    
    const unsigned char TxData[] =              // Table of data to transmit
    {
      0xff,
      0xff,
      
     
    };
    int flag =0;
    int count = 0;
    void main(void)
    {
    
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P3SEL |= 0x06;                            // Assign I2C pins to USCI_B0
     while(1)
     {
     	
     start:
       	  //Mater mode
       UCB0CTL1 |= UCSWRST;                      // Enable SW reset
       UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC+ UCMM;     // I2C Master, synchronous mode
       UCB0I2COA = 0x24;
       UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
       UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
       UCB0BR1 = 0;
       UCB0I2CSA = 0x09;                         // Slave Address is 048h
       UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
       
        __delay_cycles(50);
    #if 1
       // Writing register adress 
       PTxData = (unsigned char *)TxData;      // TX array start address
                                                // Place breakpoint here to see each
                                                // transmit operation.
       TXByteCtr = sizeof TxData;              // Load TX byte counter
       UCB0IE|=UCTXIE+UCALIE+UCNACKIE+UCSTPIE+UCSTTIE;
       UCB0CTL1 |= UCTR + UCTXSTT; 
         	
        __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
        __no_operation();                       // Remain in LPM0 until all data
        count =0;
        do{
        	count++;
        	if(count > 20)
        	{
        		goto start;
        	}
        }while (UCB0CTL1 & UCTXSTP);
    #endif
       // Reading data from register
     UCB0CTL1 |= UCSWRST;                      // Enable SW reset
       UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC+ UCMM;     // I2C Master, synchronous mode
       UCB0I2COA = 0x24;
       UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
       UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
       UCB0BR1 = 0;
       UCB0I2CSA = 0x09;                         // Slave Address is 048h
       UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
         __delay_cycles(50);
       
       UCB0IE|=UCRXIE + UCALIE+UCNACKIE+UCSTPIE+UCSTTIE;
       UCB0CTL1 &= ~UCTR;    
      count =0; 
      do{
       	count++;
       	if(count > 20)
       	{
       		goto start;
       	}
        }while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        
       UCB0CTL1 |= UCTXSTT;                    // I2C start condition
       count =0;
       do{
       		count++;
       		if(count > 20)
       		{
       			goto start;
       		}
       	}while (UCB0CTL1 & UCTXSTT);              // Start condition sent?
       __bis_SR_register(LPM0_bits + GIE);     // Enter LPM0, enable interrupts
       __no_operation();                       // For debugger  
      
       
        __delay_cycles(300);                     // Delay required between transaction
    
    
     }
    
      
    }
    //------------------------------------------------------------------------------
    // The USCIAB0TX_ISR is structured such that it can be used to transmit any
    // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData
    // points to the next byte to transmit.
    //------------------------------------------------------------------------------
    #pragma vector = USCI_B0_VECTOR
    __interrupt void USCI_B0_ISR(void)
    {
      switch(__even_in_range(UCB0IV,12))
      {
      case  0:							 // Vector  0: No interrupts
    		UCB0CTL1 |= UCTXSTP;
       		__bic_SR_register_on_exit(LPM0_bits); 
      		break;                          
      case  2:							// Vector  2: ALIFG
           
    		UCB0IFG &= ~UCALIFG;  
    	    UCB0CTL1 |= UCSWRST;                      // Enable SW reset
    	    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC+ UCMM;     // I2C Master, synchronous mode
    	    UCB0I2COA = 0x24;
    	    UCB0CTL1 = UCSSEL_2 + UCSWRST;            // Use SMCLK, keep SW reset
    	    UCB0BR0 = 12;                             // fSCL = SMCLK/12 = ~100kHz
    	    UCB0BR1 = 0;
    	    UCB0I2CSA = 0x09;                         // Slave Address is 048h
    	    UCB0CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation      
            __delay_cycles(20);                     // Delay required between transaction
      		UCB0CTL1 |= UCTXSTP;
      		__delay_cycles(20);                     // Delay required between transaction
      	
      		  		
      	    __bic_SR_register_on_exit(LPM0_bits); 
      		break;                           
      case  4:						   // Vector  4: NACKIFG
       		UCB0IFG &= ~UCNACKIFG;
       		UCB0CTL1 |= UCTXSTP;  
       		__delay_cycles(20);
       		//UCB0CTL1 |= UCTXSTT;  
       		
            __bic_SR_register_on_exit(LPM0_bits); 
       
      		break;                           
      case  6:							// Vector  6: STTIFG
      		UCB0CTL1 |= UCTXSTT;
            UCB0IFG &= ~UCSTTIFG;        // Clear start condition int flag   
      	     __bic_SR_register_on_exit(LPM0_bits); 
      	    break;                           	
      case  8:  									// Vector  8: STPIFG
    	     UCB0CTL1 |= UCTXSTP;  
    	     UCB0IFG &= ~UCSTPIFG;                   // Clear stop condition int flag
    	     __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0 if data was transmitted
         	 break;
      
                               
      case 10:                          // Vector 10: RXIFG
      
            temp_Rx= UCB0RXBUF;
            UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
            UCB0IFG &= ~UCRXIFG;                  // Clear USCI_B0 TX int flag
            __bic_SR_register_on_exit(LPM0_bits);
    
      
    	   break;  
      case 12:                                  // Vector 12: TXIFG
     
    	    if (TXByteCtr)                          // Check TX byte counter
    	    {
    	      UCB0TXBUF = *PTxData++;               // Load TX buffer
    	      TXByteCtr--;                          // Decrement TX byte counter
    	     }
    	    else
    	    {
    	      UCB0CTL1 |= UCTXSTP;                  // I2C stop condition
    	      UCB0IFG &= ~UCTXIFG;                  // Clear USCI_B0 TX int flag
    	      __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
    	    }
      		break;
    	 
      default: break;
      }
    }
    

    Thanks & Regards,

    Hitesh Patel

  • I'm in the same situation. It's strange TI doesn't support with better documentation this situation.
  • You can't write complete and exhaustive documentation for every possible application. This is like buying a PC for applicaiton development and askign for a complete documentation on how to write any thinkable PC program. Maybe including complete source code for all programs anyone could ever write.

    However, I agree that the multi master operation is a very rare case and neither documentation nor the code examples provide a step-by-step walkthough.
    But this is the job of engineers: implementing the application based on the description of the hardware. And the description is fairly complete.


    About the code posted above (somehow I never answered this back in 2011)
    1) I see a label and goto statements. These are a proper source of problems. And not necessary in this case at all. To jump to the start of the while(1) loop, a simple continue would do, as long as it does not happen inside another while or for loop.
    2) a while loop that incremens a variable for a delay/timing is really nto a good idea. COmpiler optimization and other influences may lead to unpredictable results. In any case, the tiem needed for 20 loops isvery very short. Maybe way shorter than the time needed to jsu tsend a single bit though I2C, let alone a complete start sequence.
    3) in the ISR, the USCI is reset and a stop is sent on arbitration lost. That's bad. If arbitration is lost, the USCI shall not continue. Someone else is using the bus. If you reset the bus and then send a stop, thsi will break the other one's communication. All slaves shall reset their communication when detecting a stop OR start condition. So if arbitration is lost, either wait for detecting a stop or just wait some time and try again. And don't wake from LPM, as main doesn't know that the transfer was aborted due to arbitration loss.
    In general, your ISR doesn't tell main why it was exiting LPM, so main can only guess. You should set a global flag with the result (and maybe leave it to main to retry in case of arbitration loss). Remember to mark this global flag as volatile.

    Regarding the label thing: If you want to jump to the start of an outer loop by a condition inside an inner loop, this can be done this way:
    while(1){
    count = 0;
    do {
    count++;
    if(count==20) break;
    } while (condition1);
    if(count == 20) continue;
    }

    However, it is better to use a timer timeout instead of counting up a variable. More predictable and reliable and not subject to current MCLK speed, interruptions or compiler optimizations.
    Oh, and UCB0I2CSA = 0x09 won't address a slave with 048h. It will generate a start byte of 0x12 for write and 0x13 for read operations. :)

**Attention** This is a public forum