37.2.10.2 Private Read Transaction

In Private Read Transfer, following the address header, the Target continues to send 9-bit I3C Data Words (8-bit Data and an End-of-Data T-bit). The user writes the data to be sent to the I3CxTXB Transmit Buffer using the firmware or DMA, which feeds into the Transmit FIFO. The Target continues to send the data until one of the following conditions occurs:

  • Transmit FIFO becomes empty; Target pulls the End-of-Data T-bit low
  • Maximum Read Length (I3CxMRL) is reached; Target pulls the End-of-Data T-bit low despite Transmit FIFO not being empty (TXFNE = 1), refer to the Transmit Buffer and FIFO Operation section for more information
  • Controller aborts the data transaction by pulling the End-of-Data T-bit low (a Restart condition); Target sets the Abort Error ABEIF flag
Once the data transmission is completed by the Target (or aborted by the Controller), the Transmission Complete TCOMPIF flag is set and the RNW status bits continue to hold the value until cleared by the user or overwritten in the next transaction.

The Controller sets the Maximum Read Length using the SETMRL (Set Maximum Read Length) CCC, which is stored in the I3CxMRL register. The firmware can choose to override this value by writing to the I3CxMRL register. The Controller can use the GETMRL (Get Maximum Read Length) CCC to read the value of the Maximum Read Length size stored in the I3CxMRL register.

The Private Read Transaction Flow is shown in Figure 37-48. The general frame format for Private Read Transaction is shown in Figure 37-49 and a pseudo-code is shown in Pseudo-code for Private Read Transaction.

Important:
  1. It is highly recommended for the firmware to write to the I3CxMRL register when there are no transactions happening on the bus. In the event of a race condition when the I3CxMRL register is being written by both firmware and hardware (SETMRL CCC), firmware writes will always have precedence.
  2. If the user firmware or DMA is writing data to the I3CxTXB register at a slower rate than the rate at which the Target is sending data to the Controller (bus speed), there is a possibility that the Transmit FIFO will become empty before the entire data stream is sent. In this scenario, the Target will pull the End-of-Data T-bit low and the transaction will end prematurely.
Tip:
  1. It is recommended that the user check the Maximum Read Length value stored in I3CxMRL to properly prepare the Target to send data to the Controller.
  2. The user can override the Maximum Read Length value and set I3CxMRL = 0 to send unlimited data bytes.
Figure 37-48. Private Read Transaction Flow
Figure 37-49. Private Read Transfer Frame Format

Pseudo-code for Private Read Transaction

uint8_t txData[SIZE];

void I3C1_Target_PrivateRead_Setup()
{
    // Initialize data to send
    for(uint8_t i=0; i<SIZE; i++) {
        txData[i] = i;
    }

    // Validate Maximum Read Length
    if(I3C1MRL > SIZE || I3C1MRL == 0) { // 0=unlimited (16-bit value)
        I3C1MRL = SIZE;
    }

    // Default Private Read ACK setting
    I3C1CON0bits.ACKP = 0;      // 0=ACK; 1=NACK
    I3C1CON1bits.ACKPOS = 0;    // 0=One-shot disabled; 1=enabled

}

void I3C1_Target_PrivateRead()
{
    uint8_t i = 0; 

    while(i < SIZE) {
        // Wait for Tx Buffer to become empty
        while(!I3C1STAT0bits.TXBE);

        // Write data to Transmit buffer and increment pointer
        I3C1TXB = txData[i++];

        // Perform error checking if desired
        // Check for Tx Underrun Error or Tx Write Error
        // if(I3C1ERRIR0bits.TXUIF || I3C1ERRIR1bits.TXWEIF) { ... }

        // Check for End of Transaction
        if(I3C1PIR1bits.TCOMPIF) {
            if(I3C1STAT1bits.TXFNE) {  
                return 0;   // end of transaction due to MRL overflow
            }
            else if(I3C1ERRIR1bits.ABEIF) {
                return 0;   // end of transaction due to Controller abort
            }
            else return 0;  // end of transaction due to TXFIFO empty
        }
    }
}

void main(void) {
    // Perform System and I3C Initialization
    SYSTEM_Initialize();
    I3C1_Target_Setup();

    // Private Read Setup
    I3C1_Target_PrivateRead_Setup();

    while(1) {
        // Set one-shot of Private Read ACK if applicable
        I3C1CON1bits.ACKPOS = 1;

        // Check if Dynamic Address Match occured in Read mode
        if(I3C1PIR0bits.DADRIF && I3C1STAT0bits.RNW == 0b01) {
            I3C1_Target_PrivateRead();
        }
    }
}