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.

I2C Multi-Master Arbitration in MSP430f249

Other Parts Discussed in Thread: MSP430F249

Hello all,

I'm trying to implement a I2C multimaster protocol between two MSP430f249 and I'm having trouble when two masters try to start a communication at the same time. According to the user guide, when that happens the arbitration process determines who controls the bus, and the master that lost arbitration is automatically configured as a slave and the UCALIFG flag is set, but that is not happening. To debbug this, i adapted my code to do the following:

- Configure everything that is needed in the MSP (clock source, USCI mode, I2C mode, adresses, interrupts, etc)

- Ensure stop condition got sent

- Send start condition

- check UCALIFG, if it is set, then set P2.0.

- Trap the code

I'm checking the P2.0 pin in both msps using a oscilloscope, but they are never set.

To ensure that both masters are starting communication at the same time, I soldered the supply and GND pins of both msps together so when i reset the boards they start running code at the same time. Also, both codes are exactly the same except for the own adress and slave adress registers, which have to be different so the arbitration process can decide who controls the bus.

Another option I have tried is using the USCIB0RX interrupt to detected arbitration lost and create my own routine to configure as a slave receiver, but it never enters the interrupt. (which is somewhat expected since the UCALIFG flag is never set)

Am I missing some configuration that is needed for the arbitration process to happen? Or maybe there is some hardware problem? (the exactly same hardware works fine for a single master/slave I2C communication though)

The codes for both masters are in attachments.

I aprreciate any help.

2768.master1.c
Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <msp430.h>
int other_master = 0; // flag is set if another master is controlling the bus
int we_are_master = 0;
volatile int master_data = 0x01;
volatile int received_data = 0;
void arbitration_lost(void);
void config_slave_mode(void);
void config_master_mode(void);
void main(void){
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P3SEL |= 0x06; // Assign I2C pins to USCI_B0 ************************
P2DIR = 0xff;
P2OUT = 0x00;
config_master_mode();
__bis_SR_register(GIE);
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTXSTT; // start condition
// __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
if (UCB0STAT && UCALIFG)
P2OUT |= BIT0;
while(1);
}
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIABOTX_ISR(void){
if(we_are_master){
UCB0TXBUF = master_data;
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
else{
received_data = UCB0RXBUF;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR (void){
switch(UCB0STAT & (UCSTPIFG + UCSTTIFG + UCALIFG)){ // checks for start and stop conditions, as well as arbitration lost
case UCALIFG :
arbitration_lost();
UCB0STAT &= ~UCALIFG; // clear arbitration lost flag
break;
/* case UCSTTIFG :
/ start_condition_detected();
/ break;
case UCSTPIFG :
stop_condition_detected();
break;
*/
}
}
void arbitration_lost(void){
config_slave_mode();
we_are_master = 0;
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

1220.master2.c
Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <msp430.h>
int other_master = 0; // flag is set if another master is controlling the bus
int we_are_master = 0;
volatile int master_data = 0x01;
volatile int received_data = 0;
void arbitration_lost(void);
void config_slave_mode(void);
void config_master_mode(void);
void main(void){
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P3SEL |= 0x06; // Assign I2C pins to USCI_B0 ************************
P2DIR = 0xff;
P2OUT = 0x00;
__bis_SR_register(GIE);
config_master_mode();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTXSTT; // start condition
// __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
if (UCB0STAT & UCALIFG)
P2OUT |= BIT0;
// __bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
while(1);
}
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIABOTX_ISR(void){
if(we_are_master){
UCB0TXBUF = master_data;
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
else{
received_data = UCB0RXBUF;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR (void){
switch(UCB0STAT & (UCSTPIFG + UCSTTIFG + UCALIFG)){ // checks for start and stop conditions, as well as arbitration lost
case UCALIFG :
arbitration_lost();
UCB0STAT &= ~UCALIFG; // clear arbitration lost flag
break;
/* case UCSTTIFG :
/ start_condition_detected();
/ break;
case UCSTPIFG :
stop_condition_detected();
break;
*/
}
}
void arbitration_lost(void){
config_slave_mode();
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • As long as both masters send the same data, there is no arbitration conflict. UCALIFG happens only at the first difference. (See section 17.3.4.2.4 of the User's Guide.)
  • Hello Clemens,

    Thank you for your answer. Yes, if all data is the same there is no arbitration conflict, but in my code the adresses sent by the master are different, one is 0x50h and the other is 0x70h, so I assume that there will be a conflict when the masters send the adresses on the bus. Is the arbitration process only valid for data bits and not adress bits?
  • There are lots of errors. && is logical and, not bitwise and. Checking for UCALIFG in the main loop will not work because the interrupt handler will be run first. You must check TXIFG and RXIFG before handling them. The check for UCALIFG in the interrupt handler does not work if any of the other bits are set; do the checks separately. When you lose arbitration, you should not reinitialize the USCI module because that would throw away any data being received; see figure 17-12 in the User's Guide for how the configuration is automatically changed by the hardware in this case.

  • Soldering the supplies together does not ensure that they start the I²C transaction at the same time. Use a separate signal that both programs wait for.
  • Hello Clemens,

    sorry for the late response, I got caught up with some other work. I tried using a separated signal as you suggested, but the microcontrollers are still not synchronized. Running two code composer instances and using break points I can actually see one microcontroller start running code before the other. Do you have some other suggestion on how to synchronize the two? Also, i'm sending my revised code.

    Thank you.

    2335.main.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*
    FloripaSat I2C multi-mater
    Author: Bruno Eiterer
    Descripition: this code implements I2C multi-master protocol between a EPS Directly Coupled prototype board and a OBC prototype board. It checks if the bus is busy before
    attempting to start an i2c communication, if the bus is busy it reconfigures the microcontroller as a slave receiver and waits for another master to initiate communication. If the
    bus is not busy, it keeps sending start conditions and the slave andress until the slave send an ACK signal, this way it waits for a possible other master reconfiguring as a slave.
    To do: validade arbitration procedure when two masters start communication at the same time (implemented in hardware)
    */
    #include <msp430.h>
    //------------- GLOBAL VARIABLES -------------//
    unsigned char RXByteCtr;
    volatile unsigned char RxBuffer[5]; // Variable to save received data
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • I don't see any signal sent in this code.

    Those __delay_cycles() calls should not be needed; if you want to wait for some specific event, actually poll the corresponding status bit.

    Try lowering the I²C clock to make a conflict more probable.
  • This line is what I'm using to wait for the signal:

    while(P5IN == 1);					// used to debug the case which two masters start communication at the same time

    On the two MSP boards the P5.0 pins are connected to a 3.3V source. So when I turn off the source I expect the code to pass this test. Is this not what you meant by using a separated signal?

    Thank you

  • Yes, an external signal will work.

    How much is the difference?
  • It is around 1 second. I didn't implement a timer module to be able to replay faster, I just calculated mentally. Do you require a more precise measurement?

    Thank you
  • Do both MCUs execute the "while(P5IN" loop? Do they break out of it at the same time?
  • One code executes a loop on P5 and the other on P6, i'm assuming that makes no difference (the boards with the mcus are different so not the same pins are available). I put a breakpoint on the next line of code and the time difference I notice is in reaching that breakpoint so I think it's safe to assume that they don't break out at the same time.

    Thank you

  • There should be no difference if both MCUs are actually waiting for the signal. Can you make them blink a LED while they're waiting, to confirm that that is what they're doing?
  • Hello Clemens,

    I tested the code with leds and they both blink normally. Also, I can see that one of the leds stop before the other, so they are definetely not breaking out of the while loop at the same time. Do you think this could be a hardware problem? I'll see if I can get two equal boards and run this test again.

    Thank you

  • Both wait loops should stop exactly when the signal comes. Are you really using the same signal?
  • Yest, after all it is a very simple connection. I connect a 3.3V supply to a breadboard, and then connected the MCU's pins to the breadboard. The only way I see that the MCU's do not received the same signal is if the wires are influencing some way, or maybe the tracks on the PCB, but I think checking that would be a last solution.

    Thank you

**Attention** This is a public forum