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.

NACK and AL with FIFO



Following the I2C example code for the F28027 i2c_eeprom example, I setup my I2C , as a master in a multi master system, to use the Tx FIFO to transmit 3 data bytes and interrupt, when finished, on ARDY.

But I am unsure what the sequence of events will be when a NACK or loss of arbitration occurs during addressing or data transmission.

  1. Will the STOP be automatically sent?
  2. Will the ARDY interrupt still occur?
  3. What will the state of the FIFOs be after?
  4. If they still have data remaining in them, what is the best method of clearing them?
  5. What is the best method of determining if a receiver has legally NACKed the last byte, rather than NACKed some preceding byte?

Currently my message start  code is as follows:

i2c->I2CMDR &= (~I2C_I2CMDR_IRS_BIT); /* Put I2C into reset. */
i2c->I2CMDR |= I2C_I2CMDR_FREE_BIT; /* Stop free run on breakpoint. */
i2c->I2CMDR &= ~I2C_I2CMDR_BC_BITS; /* Set bit count to 8 bits per byte. */
i2c->I2CMDR |= I2C_I2CMDR_MST_BIT;  /* Select master mode. */

i2c->I2CEMDR = 0x0U; /* Disable backwards compatibility mode. */

i2c->I2COAR  = addr; /* Set device address. */
 
i2c->I2CPSC  = 0x04U & I2C_I2CPSC_IPSC_BITS; /* Setup clock. */
i2c->I2CCLKL = 0x37U;
i2c->I2CCLKH = 0x37U;

i2c->I2CSTR = 0xFFFFU; /* Clear the I2C status register. */
 
i2c->I2CIER = 0; /* Clear past interrupt scheme. */
/* Enable interrupts ARDY, NACK, AL. */
i2c->I2CIER = (uint16_t) (I2C_IntEn_NACK | I2C_IntEn_Arb_Lost
            | I2C_IntEn_Reg_Rdy);

/* Enable FIFO and Tx FIFO. */
i2c->I2CFFTX = I2C_I2CFFTX_FFEN_BIT | I2C_I2CFFTX_TXFFRST_BIT;
i2c->I2CMDR |= I2C_I2CMDR_IRS_BIT; /* Release I2C from reset. */
 
/* Configure I2C interrupt. */
PIE_registerPieIntHandler(pie, PIE_GroupNumber_8, 
            PIE_SubGroupNumber_1, (intVec_t)&i2c_isr);
PIE_enableInt(pie, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1);
CPU_enableInt(cpu, CPU_IntNumber_8);
 
i2c->I2CSAR = 0x10U; /* Set slave address. */
i2c->I2CCNT = 3U; /* Specify 3 data bytes. */
 
i2c->I2CDXR = value1; /* Set data bytes to data. */
i2c->I2CDXR = value2;
i2c->I2CDXR = value3;
 
i2c->I2CMDR |= I2C_I2CMDR_STP_BIT; /* Finish with STOP condition. */
i2c->I2CMDR |= I2C_I2CMDR_TRX_BIT; /* Put device in transmitter mode. */
i2c->I2CMDR |= I2C_I2CMDR_STT_BIT; /* Begin with START condition. */

  • I note also that the arbitration section says

    "If the I2C module is the losing master, it switches to the slave-receiver mode, sets the arbitration lost (AL)
    flag, and generates the arbitration-lost interrupt request."

    Is this correct? The module will automatically change from a master to a slave (i.e. clear I2CMDR.MST bit)?

    What do I do if I just want the device to cease transmission and ignore communications until the bus is idle (when it can try again) if it loses arbitration?

    Ta, T

  • I have setup as above, but it seems like the ARDY interrupt never occurs. The data gets sent out as expected but the ARDY is expected to occur when it is finished so that a timeout timer can be stopped - but it never does :-(
  • Toby,

    I don't think using ARDY with the FIFOs makes sense. Why not use the FIFO interrupt instead?

    After a NACK is received, you can send either a repeated start or a stop condition. Write to the STT or STP bit to choose. The FIFO contents should be intact. You can reset the FIFO using the TXFFRST bit.

    Normally, slaves should never send a NACK. After the last transmitted byte, the master has to send a stop condition. If the master is a receiver, the master NACKs after the last byte. There's no way for a slave to tell why the master receiver sent a NACK. As with many things in I2C, that has to be implemented via a higher-level protocol.

    The I2C module is always in slave mode whenever it's not acting as a master. If you want the module to ignore other bus transactions, set the I2COAR register to an address that isn't used on the bus.
  • Hi Adam,

    Thanks for the info.

    I have indeed since switched to using the FIFO interrupt and so far it seems to be working OK. The reason I started with the ARDY is that I was following the usage in the F2802x i2c_eeprom example - but maybe I misunderstood how that was being used.

    Ta, T