Private Transaction

Once the Dynamic Address is assigned and the Target is operating in I3C SDR Mode (OPMD = 0b01), the Controller can communicate to the Target directly by specifying the Target’s Dynamic Address. The Controller uses a Private Write Transfer to write data to the Target directly and a Private Read Transfer to read data from the Target directly.
To address the Target directly, the Controller sends a Start or a Restart(1), followed by the 9-bit I3C Address Header. The address header consists of the Target’s Dynamic Address, followed by a R/W bit and an ACK/NACK bit. The R/W bit is ‘0’ (write) for Private Write Transfer and ‘1’ (read) for Private Read Transfer. If the Dynamic Address in the address header matches with the Target’s Dynamic Address in the I3CxDADR register, the Target ACKs the request and sets the DADRIF interrupt flag bit. The RNW status bits are also set according to the R/W bit in the address header(2). The Target NACKs the request if the Dynamic Address in the address header does not match the address in I3CxDADR register.
Important:
  1. 1.The Controller can choose to begin an I3C SDR Transaction by transmitting Start and 7'h7E/W Broadcast Address followed by a Restart before addressing the Target’s Dynamic Address. This allows the Controller to avoid any unnecessary address arbitration issues following a Start condition.
  2. 2.The RNW status bits in the I3CxSTAT register only apply to Private I3C/I2C Transfers. The R/W bit in the address header is not captured during non-Private Transactions (like CCC, IBI, or Hot-Join).

In Private Write Transfer, following the address header, the Controller will continue to send 9-bit I3C Data Words (8-bit Data and a Parity T-bit). The data becomes available for the user to read from the I3CxRXB Receive Buffer. The Controller can continue to send data until it reaches the maximum data write length specified in the I3CxMWL register, and then ends the transaction with a Stop or Restart. The Controller determines the maximum data write length by using the SETMWL CCC. The Controller can read back this data using the GETMWL CCC.

The Private Write Transaction Flow is shown in Figure 1. The general frame format for Private Write Transaction is shown in Figure 2 and a pseudo-code is shown in Pseudo-code for Private Write Transaction below.

Important:
  1. 1.The minimum I3CxMWL Maximum Write Length value the Controller can set is eight.
  2. 2.If the Controller exceeds the Maximum Write Length while writing to the Target, the MWLOEIF interrupt flag is set, it is recommended for the Target to continue to receive data, if possible, until the Controller terminates the transaction with a Stop or Restart.
Tip: It is recommended for the user to check the Maximum Write Length value stored in I3CxMWL to properly prepare the Target to receive data from the Controller.
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. The Target continues to send the data until the Transmit FIFO becomes empty, after which the Target generates an End-of-Data signal (End-of-Data = 0) using the T-bit indicating to the Controller to end the transaction. The Controller can also choose to abort the transaction by asserting the T-bit (End-of-Data = 0), which is equivalent to a Restart condition on the bus, represented through the RSCIF interrupt flag. (Refer to Transition Bit (T-Bit) for more details.)

Before sending any data, it is recommended to check the maximum data read length that the Controller will accept by reading the value in the I3CxMRL register. The Controller determines the maximum data read length, if possible, by using the SETMRL CCC. The Controller can read back this data using the GETMRL CCC.

The Private Read Transaction Flow is shown in Figure 3. The general frame format for Private Read Transaction is shown in Figure 4 and a pseudo-code is shown in Pseudo-code for Private Read Transaction below.

A Private Transaction ends with a Stop or a Restart from the Controller, after which the RNW status bits reset to 0b00.
Important:
  1. 1.The minimum I3CxMRL Maximum Read Length value the Controller can set is 16.
  2. 2.If the Target continues to send data that exceeds the Maximum Read Length set by the Controller, the Controller may either accept or terminate the transaction depending upon any private contract between the Target and the Controller or the Controller’s ability to receive them.
Tip: It is recommended for the user to check the Maximum Read Length value stored in I3CxMRL to properly prepare the Target to send data to the Controller.
Tip: It is recommended for the user to use DMA to read and write from the I3C Transmit and Receive Buffers to ensure that the CPU is able to keep up with the higher I3C speeds. Refer to section Interrupts and DMA Triggers and "DMA - Direct Memory Access" chapter for more information.
Figure 1. Private Write Transaction Flow
Figure 2. Private Write Transfer Frame Format

Pseudo-code for Private Write Transaction

uint8_t rxData[SIZE];

uint8_t I3C1_Target_PrivateWrite()
{
    uint16_t i = 0;

    // Check Target's operating mode first
    if(I3C1STATbits.OPMD != 0b01) {
        return 1;   // Target is operating in I2C mode, abort
    }

    // Check if Dynamic Address Match occured in Write mode
    if(!I2C1STATbits.DADRIF || !I3C1STATbits.RNW == 0b10) {
        return 1;   // abort if no dynamic address match or Read mode
    }

    while(i < SIZE) {
        // Wait for data to become available in Rx Buffer
        while(!I3C1STATbits.RXBF);

        // Read data from Receive buffer and increment pointer
        rxData[i++] = I3C1RXB;

        // Check if maxWrLen overflow
        if(I3C1ERRIR1bits.MWLOEIF) {
            // Controller has exceeded Max Write Length
            // Take appropriate action
        }

        // Perform error checking if desired
        // Check for Rx Overrun Error or Rx Read Error
        // if(I3C1ERRIR0bits.RXOIF || I3C1ERRIR1bits.RXREIF) { ... }

        // Check for Stop or Restart for End of Transaction
        if(I3C1PIR0bits.PCIF || I3C1PIR0bits.RSCIF || I3C1PIR1bits.TCOMPIF) {
            return 0;  // end of transaction with successful write
        }
    }

    // Code execution reaches here when rxData[] is full 
    // Wait for Stop or Restart for End of Transaction
    while(!I3C1PIR0bits.PCIF && !I3C1PIR0bits.RSCIF && !I3C1PIR1bits.TCOMPIF) {
        // While waiting, check for additional errors (optional)
        // if(I3C1ERRIR1bits.MWLOEIF || I3C1ERRIR0bits.RXOIF || I3C1ERRIR1bits.RXREIF) { ... }
    }

    return 1;   // end of transaction with possible data overflow
}
Figure 3. Private Read Transaction Flow
Figure 4. Private Read Transfer Frame Format

Pseudo-code for Private Read Transaction

uint8_t txData[SIZE];

uint8_t I3C1_Target_PrivateRead()
{
    uint16_t i = 0;

    // Check Target's operating mode first
    if(I3C1STATbits.OPMD != 0b01) {
        return 1;   // Target is operating in I2C mode, abort
    }

    // Check if Dynamic Address Match occured in Read mode
    if(!I2C1STATbits.DADRIF || !I3C1STATbits.RNW == 0b01) {
        return 1;   // abort if no dynamic address match or Write mode
    }

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

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

        // Check if maxRdLen overflow
        if(i >= I3C1MRL) {
            // Software has exceeded Max Read Length set by the Controller
            // Take appropriate action
        }

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

        // Check for Controller abort (possibly premature)
        if(I3C1PIR0bits.PCIF || I3C1PIR0bits.RSCIF || I3C1PIR1bits.TCOMPIF) {
            return 1;  // end of transaction with Controller abort
        }
    }

    // Code execution reaches here when all data from txData[] has been sent 
    // Wait for Stop or Restart for End of Transaction
    while(!I3C1PIR0bits.PCIF && !I3C1PIR0bits.RSCIF && !I3C1PIR1bits.TCOMPIF) {
        // While waiting, check for additional errors (optional)
        // if(I3C1ERRIR0bits.TXUIF || I3C1ERRIR1bits.TXWEIF) { ... }
    }

    return 0;   // end of transaction with possible data underflow
}