Part Number: MSP430F5529
Other Parts Discussed in Thread: LM75A
Hi, I'm using a custom board with msp430f5529. The msp has multiple i2c slave devices (single on-board LM75A and two off-board LM75A connected via LTC4315f bus buffer).
The MSP itself is also a slave for Raspberry Pi4. I2c master and slave are USCI_B0 and B1 correspondingly.
The issue is: Raspberry launches a cyclic (while true) command, asking, for example, an off-board LM75A. System works properly for some time (like 5 cycles or 6 minutes non-stop, it's not fixed) and then it hangs. Host waits for 10 sec timeout, but msp hangs busy.
I2C_master code for msp is copied from MSP430F55xx_usci_i2c_standard_master.c from official library.
Master Init code below. clock is sourced from SMCLK:
void I2C_init()
{
//initClockTo16MHz();
I2C_init_GPIO();
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 10;//160; //1.01/10 ~100khz // fSCL = SMCLK/160 = ~100kHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0IE |= UCNACKIE;
}
I2C slave is custom:
void initGPIO()
{
//I2C Pins
P4SEL |= BIT1 | BIT2;
}
void initI2C()
{
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 = UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB1I2COA = SLAVE_ADDR; // Own Address
UCB1BR0 = 1;//160;
UCB1BR1 = 0;
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB1IE |= (UCRXIE | UCTXIE| UCSTPIE | UCSTTIE | UCALIE | UCNACKIE);
}
int I2C_slave_init(void) {
initGPIO();
initI2C();
return 0;
}
//******************************************************************************
// I2C Interrupt ***************************************************************
//******************************************************************************
enum i2c_slave_stage{WAITING_FOR_START, RECEIVE_REG_ADDR,
WAITING_FOR_DATA_OR_RESTART, TRANSMIT_DATA, WAITING_FOR_STOP};
enum i2c_slave_stage stage = WAITING_FOR_START;
void read_i2c_data() {
uint8_t temp = UCB1RXBUF;
if (stage == RECEIVE_REG_ADDR) {
i2c_offset = (temp > sizeof(i2c_interface_struct))? sizeof(i2c_interface_struct) : temp;
stage = WAITING_FOR_DATA_OR_RESTART;
} else if (stage == WAITING_FOR_DATA_OR_RESTART) {
(*(((uint8_t*)(&i2c_interface_struct))+i2c_offset)) = temp;
stage = WAITING_FOR_STOP;
} else {
// generate NAK
UCB1CTL1 |= UCTXNACK;
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_B1_VECTOR
__interrupt void USCI_B1_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B1_VECTOR))) USCI_B1_ISR (void)
#else
#error Compiler not supported!
#endif
{
volatile uint8_t temp;
switch(__even_in_range(UCB1IV,0xC))
{
case USCI_NONE:
break; // Vector 0 - no interrupt
case USCI_I2C_UCALIFG:
break; // Interrupt Vector: I2C Mode: UCALIFG
case USCI_I2C_UCNACKIFG:
break; // Interrupt Vector: I2C Mode: UCNACKIFG
case USCI_I2C_UCSTTIFG:
if (stage == WAITING_FOR_DATA_OR_RESTART)
stage = TRANSMIT_DATA;
else
stage = RECEIVE_REG_ADDR;
break; // Interrupt Vector: I2C Mode: UCSTTIFG
case USCI_I2C_UCSTPIFG:
// Fix: STOP in write transaction could come before DATA
if (UCB1IFG & UCRXIFG) {
//(*(((uint8_t*)(&i2c_interface_struct))+i2c_offset)) = UCB1RXBUF;
read_i2c_data();
}
i2c_offset=0;
stage = WAITING_FOR_START;
break; // Interrupt Vector: I2C Mode: UCSTPIFG
case USCI_I2C_UCRXIFG:
read_i2c_data();
break; // Interrupt Vector: I2C Mode: UCRXIFG
case USCI_I2C_UCTXIFG:
// Fix: Don't check stage==TRANSMIT_DATA (reSTART in write transaction could come before regAddr)
UCB1TXBUF = *( ((uint8_t*)(&i2c_interface_struct)) + i2c_offset);
while (UCB1IFG & UCTXIFG);
break; // Interrupt Vector: I2C Mode: UCTXIFG
default: break;
}
}
The code hangs on line 88 ( while (UCB1IFG & UCTXIFG); ) *didn't figure out how highlight works*
Below's the code for sensor check. First the line is established via buffer, then I read sensor, then I close the bus.
if(LTC4315_bus_enable(LTC4315_I2C_ADDRESS, LTC4315_BUS2)){ // 41 - ltc
if(LM75A_read_temperature1(&temp)){
temp_storage.device2_temperature_storage = (uint32_t)temp;
}
}
LTC4315_bus_disable(LTC4315_I2C_ADDRESS, LTC4315_BUS2);
The hang is caught both with and without debugger being connected. Sometimes I caught debugger stuck on __bis_SR_register(LPM0_bits + GIE); string of I2C_Master_WriteReg, unable to close the LTC line, but the debugger said that UCB1_ISR is in use (which is slave). So I wonder, wether it can be that there is a conflict between UCB0_ISR and UCB1_ISR? Or is it smth else that I just don't see?
Maybe it's important: system works in while(1) loop in main. there are also UART, SPI and RTC_A working. Also, I tried to remove LPM0 from I2C Master, but then I failed to do read operations with LTC and couldn't open the link.
I appreciate your help.