lpcware

I2C phantom issue. Bus Hangs Out and Stops communication

Discussion created by lpcware Employee on Jun 15, 2016
Content originally posted in LPCWare by epilonsonia on Thu Jul 31 13:59:22 MST 2014
Hi,

So the issue I have is basically that, sometimes (sorry for the lack of precision but I haven't been able to reproduce the bug), the bus just "Hangs Out" and I'm unable to communicate with it.

To describe the actual system :
- Autonomous Submarine
- The Computer communicates CAN/TCP with a Navigation Card which handle all devices
- I2C is used for our thrusters (7 in total) from the Navigation Card (MASTER) to a power board (SLAVE)
- SPI interface for communication with a depthSensor on the Navigation Card

It works properly but, like mentioned, it hangs out sometimes (hence the thrusters are unresponsive) and the only way I have to recover  the communication is to power off/on to reset the MASTER (Navigation Card).

My first guess was that some Interupts with higher priority were affecting the communication in some ways but since I haven't modified the Vector Table, no Interupt with Higher Priorities (besides Timer0 which simply increment a counter every 1 ms) are really used.

I'm clueless about how to debug this / any possible cause and hence have no way of fixing it for now!
Any help would be awesome,

P.s. Here is the I2C state machine :

void I2C0_IRQHandler(void){
    uint8_t done = 0;
    volatile static struct I2C_MESSAGE rx_msg;
    volatile static uint8_t data_ptr = 0;
    uint8_t error_flag = 0;
    switch(LPC_I2C0->I2STAT){
    case I2C_START:
    case I2C_REP_START:
        //Send address
        LPC_I2C0->I2DAT = (twi_msg.address << 1) | ((twi_msg.rw == I2C_READ) ? 1 : 0);
        //Send SLA + R or W
        if(twi_msg.rw == I2C_READ){
        //Signal read
            //LPC_I2C0->I2CONCLR = ((1<<I2C_SI)|(1<<I2C_STA));
            LPC_I2C0->I2CONCLR = ((1<<I2C_SI)|(1<<I2C_STO));
        }else{
            //Reset data pointer
            data_ptr = 0;
            //LPC_I2C0->I2CONCLR = ((1<<I2C_SI)|(1<<I2C_STA));
            LPC_I2C0->I2CONCLR = ((1<<I2C_SI)|(1<<I2C_STO));
        }
    break;
    case I2C_MT_SLA_ACK:
        if((data_ptr < TWI_DATA_SIZE) && (--twi_msg.size >= 0)){
        LPC_I2C0->I2DAT = twi_msg.data[data_ptr++];
        LPC_I2C0->I2CONCLR = (1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI);
        }else{
            //flag error
            twi_error = TWI_TX_SIZE_MISMATCH;
            //load next message
            if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
            I2C_GEN_I2C_START();
            }else{
I2C_GEN_I2C_STOP();
                in_use = 0;
            }
        }
    break;
    case I2C_MT_SLA_NACK:
        //flag error
        twi_error = TWI_WRITE_ADDRESS_NACK;
        error_flag = 1;

    case I2C_MR_SLA_NACK:
        //flag error
        if(!error_flag){
            twi_error = TWI_READ_ADDRESS_NACK;
        }
        //load next message
        if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
        I2C_GEN_I2C_START();
        }else{
        I2C_GEN_I2C_STOP();
            in_use = 0;
        }
    break;
    case I2C_MT_DATA_ACK:
        if(((--twi_msg.size) >= 0) && (data_ptr < TWI_DATA_SIZE)){
        LPC_I2C0->I2DAT = twi_msg.data[data_ptr++];
        LPC_I2C0->I2CONCLR = (1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI);
        }else if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
            //flag error because the size expected did not match
            twi_error = TWI_TX_SIZE_MISMATCH;
            I2C_GEN_I2C_START();
        }else{
            //flag error because the size expected did not match
            twi_error = TWI_TX_SIZE_MISMATCH;
            I2C_GEN_I2C_STOP();
            in_use = 0;
        }
    break;
    case I2C_MT_DATA_NACK:
        //Check if nack is normal
        if(twi_msg.size != 0){
            //flag error
            twi_error = TWI_TX_SIZE_MISMATCH;
        }
        //load next message
        if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
        I2C_GEN_I2C_START();
        }else{
        I2C_GEN_I2C_STOP();
            in_use = 0;
        }
    break;
    case I2C_MT_ARB_LOST:
    //case I2C_MR_ARB_LOST:
        //flag error
        twi_error = TWI_ARBITRATION_LOST;
        //Try transmission again
        I2C_GEN_I2C_START();
    break;
    case I2C_MR_SLA_ACK:
        if(twi_msg.size > 1){
        LPC_I2C0->I2CONSET = (1<<I2C_AA);
        LPC_I2C0->I2CONCLR = (1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI);
        }else{
        LPC_I2C0->I2CONCLR = ((1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI) | (1 << I2C_AA));
        }
        rx_msg.address = twi_msg.address;
    break;
    case I2C_MR_DATA_ACK:
        //Save message data
        rx_msg.data[rx_msg.size++] = LPC_I2C0->I2DAT;
        //Reduce size to receive
        if(--twi_msg.size){
            if(twi_msg.size > 1){
            LPC_I2C0->I2CONSET = (1<<I2C_AA);
            LPC_I2C0->I2CONCLR = (1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI);
            }else{
            LPC_I2C0->I2CONCLR = ((1 << I2C_STA) | (1 << I2C_STO) | (1 << I2C_SI) | (1 << I2C_AA));
            }
        }else if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
            //flag error because the size expected did not match
            twi_error = TWI_RX_SIZE_MISMATCH;
            //Flag rx message done
            done = 1;
            //Restart
            I2C_GEN_I2C_START();
        }else{
            //flag error because the size expected did not match
            twi_error = TWI_RX_SIZE_MISMATCH;
            //Flag rx message done
            done = 1;
            //Stop
            I2C_GEN_I2C_STOP();
            in_use = 0;
        }
        if(done){
            write_rx_queue((struct I2C_MESSAGE*)&rx_msg);
            rx_msg.size = 0;
        }
    break;
    case I2C_MR_DATA_NACK:
        //Store data
        rx_msg.data[rx_msg.size++] = LPC_I2C0->I2DAT;
        //Check if all expected data was received
        if(--twi_msg.size){
            twi_error = TWI_RX_SIZE_MISMATCH;
        }
        //Push rx message in queue
        write_rx_queue((struct I2C_MESSAGE*)&rx_msg);
        rx_msg.size = 0;
        //load next message
        if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
        I2C_GEN_I2C_START();
        }else{
        I2C_GEN_I2C_STOP();
            in_use = 0;
        }
    break;
    default:
        //Save message data
        rx_msg.data[rx_msg.size++] = LPC_I2C0->I2DAT;
        //flag error
        twi_error = TWI_UNEXPECTED_ERROR;
        //load next message
        if(read_tx_queue(&twi_msg) == I2C_SUCCESS){
        I2C_GEN_I2C_START();
        }else{
        I2C_GEN_I2C_STOP();
            in_use = 0;
        }
    break;
    }

Here I2C_GEN_I2C_STOP() and I2C_GEN_I2C_START() are Macros that Set Stop and Start bit and Clear the rest of the bits.

Outcomes