Hi @carlos_o ,
The following codes are implementation of Blocking API GetStatus
get_status(uint8_t address, uint16_t& status)
{
constexpr uint8_t BoradcastAddress = 0x7EU;
constexpr uint8_t CccGetStatus = 0x90U;
constexpr uint16_t WordMask = 0xFFFF;
I3cBuffer buffer{};
i3c_master_transfer_t xfer{};
xfer.slaveAddress = BoradcastAddress;
xfer.subaddress = CccGetStatus;
xfer.subaddressSize = 1U;
xfer.direction = kI3C_Write;
xfer.busType = kI3C_TypeI3CSdr;
xfer.flags = kI3C_TransferNoStopFlag;
xfer.ibiResponse = kI3C_IbiRespAckMandatory;
auto result = I3C_MasterTransferBlocking(_i3c_m_handle.base, &xfer);
if (result != kStatus_Success) {
I3C_MasterEmitRequest(_i3c_m_handle.base, kI3C_RequestForceExit);
const logger::EventData data = {
CccGetStatus,
static_cast<uint8_t>(result >> 0 & 0xFF),
static_cast<uint8_t>(result >> 8 & 0xFF),
static_cast<uint8_t>(result >> 16 & 0xFF),
static_cast<uint8_t>(result >> 24 & 0xFF),
};
logger::info(logger::Event::I3CCccError, data);
auto driver_status = to_driver_status(static_cast<uint32_t>(result));
if (driver_status != Status::Success) {
const auto& task = *static_cast<nv::i3c::Task*>(_task);
task.record_error(static_cast<uint8_t>(driver_status));
}
return false;
}
memset(&xfer, 0, sizeof(xfer));
xfer.slaveAddress = address;
xfer.data = buffer.data();
xfer.dataSize = 2;
xfer.direction = kI3C_Read;
xfer.busType = kI3C_TypeI3CSdr;
xfer.flags = kI3C_TransferDefaultFlag;
xfer.ibiResponse = kI3C_IbiRespAckMandatory;
result = I3C_MasterTransferBlocking(_i3c_m_handle.base, &xfer);
if (result != kStatus_Success) {
I3C_MasterStop(_i3c_m_handle.base);
const logger::EventData data = {
CccGetStatus,
static_cast<uint8_t>(result >> 0 & 0xFF),
static_cast<uint8_t>(result >> 8 & 0xFF),
static_cast<uint8_t>(result >> 16 & 0xFF),
static_cast<uint8_t>(result >> 24 & 0xFF),
};
logger::info(logger::Event::I3CCccError, data);
auto driver_status = to_driver_status(static_cast<uint32_t>(result));
if (driver_status != Status::Success) {
const auto& task = *static_cast<nv::i3c::Task*>(_task);
task.record_error(static_cast<uint8_t>(driver_status));
}
return false;
}
status = (buffer[0] << 8 | buffer[1]) & WordMask;
return true;
}
SDK version: SDK_25_09_00_MCXN556S
Role and configuration:
Master Mode - The I3C controller is configured as a master device.
The I3C master configuration is set up as follows:
i3c_master_config_t _master_config;
// Configuration settings:
_master_config.baudRate_Hz.i2cBaud = freq.i2c; // I2C baud rate (typically 400 kHz)
_master_config.baudRate_Hz.i3cPushPullBaud = freq.i3c_pp; // I3C push-pull baud rate (typically 12.5 MHz)
_master_config.baudRate_Hz.i3cOpenDrainBaud = freq.i2c_od; // I3C open-drain baud rate (typically 2.5 MHz)
_master_config.enableOpenDrainStop = false;
_master_config.disableTimeout = true; // Timeout disabled
_master_config.enableOpenDrainHigh = is_gpu ? true : false; // GPU-specific: 50:50 duty cycle
_master_config.hKeep = kI3C_MasterHighKeeperNone;
```
Transfer Mode:** SmartDMA and EDMA (Enhanced DMA) based transfersDMA Configuration
- **TX DMA Channel:** Channel 0 (DMA0 for I3C0, DMA1 for I3C1)
- **RX DMA Channel:** Channel 1 (DMA0 for I3C0, DMA1 for I3C1)
- **DMA Mux:** Configured for I3C TX/RX requests
Hardware
MCU/Board Part Numb
MCXN556 (MCXN556SCDF variant)
The code supports two I3C ports:
- **I3C0:** Base address `I3C0`, uses `DMA0`
- **I3C1:** Base address `I3C1`, uses `DMA1`
The I3C bus is used to communicate with GPU devices
Bus Frequency
- **Master Clock:** 25 MHz (`Clock = 25000000UL`)
- **I3C Push-Pull Baud Rate:** 12.5 MHz (typical)
- **I3C Open-Drain Baud Rate:** 2.5 MHz (typical)
- **I2C Baud Rate:** 400 kHz (typical)
### Clock Stretching and Retries
- **Timeout:** Disabled (`disableTimeout = true`)
- **Retry Mechanism:** Implemented in software with 5 retry attempts for failed transfers
Nack occurred when MCU read/write data to the slave.
MCU send GetStatus command to GPU to recover it.
for (uint8_t i = 0; i < recover_retry; i++) {
bool success = get_status(address, value);
if (success && value == 0) {
return true;
}
task->delay(10ms);
}