I2C phantom issue. Bus Hangs Out and Stops communication

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C phantom issue. Bus Hangs Out and Stops communication

249 Views
lpcware
NXP Employee
NXP Employee
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.
Labels (1)
0 Kudos
0 Replies