37.2.5 Legacy I2C Transaction on I3C Bus
Until the Dynamic Address is assigned, the I3C Target operates in I2C Target
mode (OPMD =
0b00
) and uses the Static Address stored in the I3CxSADR register to
represent itself on the bus. When in this mode, the Controller can use an
I2C Write Transfer to write data to the Target directly and an
I2C Read Transfer to read data from the Target directly.Once the Target participates in the Dynamic Address
Assignment procedure and receives a Dynamic Address in its I3CxDADR
register, it starts to operate in I3C SDR Mode (OPMD = 0b01
). The
Target will then no longer respond to its Static Address in I3CxSADR register and will
NACK any request to its Static Address.
Important:
- The I3C Target module does not support 10-bit I2C addressing and clock stretching when operating in I2C mode. Refer to I2C Backward Compatibility for details.
- Additional pin configuration is required for the SDA and SCL pads to be I2C/SMBus-compatible. Refer to I3C Pad Compatibility with I2C/SMBus Levels for more information.
- It is possible for an
I2C Transaction to take place even when the bus is configured to
operate in I3C SDR Mode or when an I3C SDR Transaction is in progress. For
example, the Controller can choose to transmit I3C Broadcast Address
7’h7E
/W, followed by a Restart and I2C Static Address to begin an I2C Transaction while in I3C SDR Mode. - The Maximum Read and Write
Lengths specified in the I3CxMRL and I3CxMWL registers have no effect when the module is operating in
I2C Target mode (OPMD =
0b00
).
CAUTION: This Target device supports a special Static Address SDR
Mode where the module can operate in I3C SDR mode (OPMD =
0b01
) using its Static Address without requiring a Dynamic Address.
When this special mode is activated, the module will respond to the Static Address to
participate in an I3C SDR transaction and not in Legacy I2C
transaction.To address the Target directly, the Controller sends a Start or a Restart, followed by
the I2C Address Header. The address header consists of the Target’s
7-bit Static Address, followed by a R/W bit from the Controller
and an ACK/NACK bit from the Target. The
R/W bit is ‘
0
’ (write) for I2C
Write Transfer and ‘1
’ (read) for I2C Read Transfer. If the
Static Address in the address header matches with the Target’s Static Address in the
I3CxSADR register, the Target ACKs the request and sets the SADRIF interrupt flag bit. The RNW status bits are also set according to the R/W
bit in the address header. The Target NACKs the request if the Static Address in the
address header does not match the address in I3CxSADR register.When an I2C transaction is initiated, the ACK/NACK
response from the Target is controlled by the ACKP
and ACKPOS
bits and is also based on the status of the Transmit FIFO/Buffer. Refer to Table 37-6 for more information.
Important: The RNW status bits only apply to Private I3C/I2C Transfers. The
R/W bit in the address header is not captured during
non-Private Transactions (such as CCC, Hot-Join or IBI).
In I2C Write Transfer, following the address header, the Controller
will continue to send the 8-bit Data on the bus. The data become available for the user
to read from the I3CxRXB Receive Buffer and the Target sends an ACK
on the bus. This process continues until the Controller ends the transaction with a Stop
or Restart, after which the Transaction 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 general frame
format for I2C Write Transaction is shown in Figure 37-16 and a pseudo-code is shown in Pseudo-code for Legacy I2C Write Transaction below.
In I2C Read Transfer, following the address header from the Controller,
the Target sends an 8-bit Data on the bus. The user writes the data to be sent to the
I3CxTXB
Transmit Buffer. If the Controller accepts the data and sends an
ACK on the bus, I2CACKIF interrupt flag is set. If the Controller declines the data and
sends a NACK on the bus, I2CNACKIF interrupt flag is set, the Target stops sending data until the
Controller terminates the transaction with a Stop or Restart. The Transaction Complete
TCOMPIF flag is then set, and the RNW status bits continue to hold the
value until cleared by the user or are overwritten in the next transaction. The general
frame format for I2C Read Transaction is shown in Figure 37-17 and a pseudo-code is shown in Pseudo-code for Legacy I2C Read Transaction below.
Important: All the Transmit and Receive Buffers and FIFO
status and interrupt flags continue to operate as expected in I2C Target mode
as well. Refer to the Transmit and Receive Buffers and FIFO section for more
information.
Pseudo-code for Legacy I2C Write Transaction
uint8_t rxData[SIZE]; void I3C1_Target_I2CWrite_Setup() { // Default I2C Write ACK setting I3C1CON0bits.ACKP = 0; // 0=ACK; 1=NACK I3C1CON1bits.ACKPOS = 0; // 0=One-shot disabled; 1=enabled } void I3C1_Target_I2CWrite() { uint16_t i = 0; while(i < SIZE) { // Wait for data to become available in Rx Buffer while(!I3C1STAT0bits.RXBF); // Read data from Receive buffer and increment pointer rxData[i++] = I3C1RXB; // Perform error checking if desired // Check for Rx Overrun Error or Rx Read Error // if(I3C1ERRIR0bits.RXOIF || I3C1ERRIR1bits.RXREIF) { ... } // Check for End of Transaction if(I3C1PIR1bits.TCOMPIF) { return 0; // end of transaction } } // Code execution reaches here when I2C write has exceeded SIZE // Check for Rx errors and Transaction Complete // if(I3C1ERRIR0bits.RXOIF || I3C1ERRIR1bits.RXREIF) { ... } if(I3C1PIR1bits.TCOMPIF) { return 0; // end of transaction with SIZE overflow } } void main(void) { // Perform System and I3C Initialization SYSTEM_Initialize(); I3C1_Target_Setup(); // Private Write Setup I3C1_Target_I2CWrite_Setup(); while(1) { // Set one-shot of I2C Write ACK if applicable I3C1CON1bits.ACKPOS = 1; // Check if Static Address Match occured in Write mode if(I3C1PIR0bits.SADRIF && I3C1STAT0bits.RNW == 0b10) { I3C1_Target_I2CWrite(); } } }
Pseudo-code for Legacy I2C Read Transaction
uint8_t txData[SIZE]; void I3C1_Target_I2CRead_Setup() { // Initialize data to send for(uint8_t i=0; i<SIZE; i++) { txData[i] = i; } // Default I2C Read ACK setting I3C1CON0bits.ACKP = 0; // 0=ACK; 1=NACK I3C1CON1bits.ACKPOS = 0; // 0=One-shot disabled; 1=enabled } void I3C1_Target_I2CRead() { 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(I3C1ERRIR0bits.I2CNACKIF) { return 0; // end of transaction w Controller NACK } else return 0; // graceful end of transaction } } // Code execution reaches here when I2C read has exceeded SIZE // Check for Tx Errors or Transaction Complete // if(I3C1ERRIR0bits.TXUIF || I3C1ERRIR1bits.TXWEIF) { ... } if(I3C1PIR1bits.TCOMPIF) { return 0; // end of transaction with SIZE overflow } } void main(void) { // Perform System and I3C Initialization SYSTEM_Initialize(); I3C1_Target_Setup(); // Private Read Setup I3C1_Target_I2CRead_Setup(); while(1) { // Set one-shot of I2C Read ACK if applicable I3C1CON1bits.ACKPOS = 1; // Check if Static Address Match occured in Read mode if(I3C1PIR0bits.SADRIF && I3C1STAT0bits.RNW == 0b01) { I3C1_Target_I2CRead(); } } }