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.
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
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:I checked with TI sample application but there is no any application which is demonstrate MSP430 as multi-master mode.
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.Krunal Patil said:What care I should take when arbitration occur
Yes. When another master was sending, then you might be the target, so the I2C module goes into slave mode.Krunal Patil said:My observation is that when arbitration occur my MSP430 become slave mode
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.Krunal Patil said:I am giving reset to I2C controller and set MSP as Master and giving STOP condition.
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
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