大家@@ 好 , 从我们的实验中,我们观察到 MSTATUS 仍然停留在 SLVREQ 状态 ,这导致 MCU 将 I3C 总线视为繁忙 状态。
Bruce_Teng_1-1770985476588.png
我们发现,在某些情况下,调用阻塞的 GetStatus API 会触发此问题。我们认为,根本原因是混用阻塞和非阻塞 API,这会导致 IBI 处理不正确。我们想实现一个非阻塞的 GetStatus 来解决这个问题。你能帮忙实施吗?
MCU: MCXN556 和 MCXN236
bool i3c_write(uint8_t address, uint8_t* data, size_t length) {
i3c_master_transfer_t xfer = {};
xfer.slaveAddress = address;
xfer.data = data;
xfer.dataSize = length;
xfer.direction = kI3C_Write;
xfer.busType = kI3C_TypeI3CSdr;
xfer.flags = kI3C_TransferDefaultFlag;
xfer.ibiResponse = kI3C_IbiRespAckMandatory;
status_t status = I3C_MasterTransferEDMA(I3C0, &i3c_handle, &xfer);
return (status == kStatus_Success);
}
```
### Read Operation
```cpp
bool i3c_read(uint8_t address, uint8_t* data, size_t length) {
i3c_master_transfer_t xfer = {};
xfer.slaveAddress = address;
xfer.data = data;
xfer.dataSize = length;
xfer.direction = kI3C_Read;
xfer.busType = kI3C_TypeI3CSdr;
xfer.flags = kI3C_TransferDefaultFlag;
xfer.ibiResponse = kI3C_IbiRespAckMandatory;
status_t status = I3C_MasterTransferEDMA(I3C0, &i3c_handle, &xfer);
return (status == kStatus_Success);
}
如果我们使用这个 blocking API get_status来实现恢复或私有读/写 NACK似乎似乎会导致似乎会导致 MCU进入错误状态(如我所述)。
了恢复方法,并进行了压力测试这个版本;它不会再发生再次发生。
感谢您的来信,并对延迟回复表示歉意。
能否请您提供有关测试内容的更多详细信息(测试步骤、预期行为与观察到的行为,以及任何日志或跟踪记录)?
我假定 MCU 配置为主设备,因为您检查的是 MSTATUS 而不是 SSTATUS。如果不是这样,请告诉我。
根据参考手册,该条件下的接口行为描述如下:
carlos_o_0-1771349361781.png
你可以尝试启用自动发射 IBI,这样总线就不会保持该状态。
请做一些说明,以帮助我们重现您的设置:
您指的是哪个 GetStatus API(完整的函数名称和模块/驱动程序)?
您使用的 SDK 版本(确切的版本字符串)。
角色和配置:主控与从属,以及任何相关寄存器设置(如先进先出阈值、中断掩码)。
硬件:MCU/主板部件号和总线上的任何外部元器件。
定时:总线频率、IBI 配置以及是否启用时钟扩展或重试。
展示如何配置和调用应用程序接口的简短代码片段。
你好@carlos_o,
以下代码实现了阻塞 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(result >> 0 & 0xFF),
static_cast(result >> 8 & 0xFF),
static_cast(result >> 16 & 0xFF),
static_cast(result >> 24 & 0xFF),
};
logger::info(logger::Event::I3CCccError, data);
auto driver_status = to_driver_status(static_cast(result));
if (driver_status != Status::Success) {
const auto& task = *static_cast<:i3c::task>(_task);
task.record_error(static_cast(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(result >> 0 & 0xFF),
static_cast(result >> 8 & 0xFF),
static_cast(result >> 16 & 0xFF),
static_cast(result >> 24 & 0xFF),
};
logger::info(logger::Event::I3CCccError, data);
auto driver_status = to_driver_status(static_cast(result));
if (driver_status != Status::Success) {
const auto& task = *static_cast<:i3c::task>(_task);
task.record_error(static_cast(driver_status));
}
return false;
}
status = (buffer[0] << 8 | buffer[1]) & WordMask;
return true;
} SDK 版本: SDK_25_09_00_MCXN556S
角色和配置:
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);
}在我们的系统中,MCU 是 I3C 主设备,GPU 是 I3C 从设备。
因此,看来我们无法修改寄存器设置来决定 GPU 如何检测总线可用状态。对不对?
如果是,我们是否应该关注 GPU 的行为?
你好 @Bruce_Teng,
根据 I3C 标准,总线必须保持IDLE状态至少 1 微秒,然后才能发布 IBI。为确保满足此定时要求,设备使用 CLK_SLOW。当 IBI 请求处于待处理状态时,由 CLK_SLOW 驱动的内部计数器必须完成一个或多个计数,然后才能将总线视为完全空闲并生成 IBI。如下图所示,该图像来自 RM (MCXN236):
image.png
另外,为了更好地为您提供支持,您能否提供以下信息?
- 能否请您说明一下您以前是否获得过该特定部件 MCXN556 的支持?
- 我很难看到您在上一篇文章中分享的图片,您能否分享给我更高分辨率的图片?
- 您能否提供复制此行为的步骤?
BR
Habib
你好,
,我还有一个问题。
如果 f 从站在 STOP 状态后立即将 SDA 拉至低电平,如图所示。
MCXN556/236 I3C IP 似乎无法检测到 SDA 失效边沿,因此不会切换 SCL 线以产生 START。
是否符合您的期望?
如果是,是不是因为从机违反了总线可用条件?
image.png@Smartling Language Service
你好@Habib_MS
没有,我还没有收到任何关于 MCXN556 这一特定部件的支持。
Screenshot 2026-02-25 131322.png
背景:在我们的系统
中,微控制器在USB和下游设备(GPU)之间起着桥梁的作用,
因此,微控制器负责将数据从USB转发到GPU或从GPU转发到USB。
一旦 GPU 需要向 USB 传递数据,GPU 就会发出 IBI 请求,然后 MCU 对其进行服务并从 GPU 读取数据,然后将其转发到 USB。
实验:
在每个事务(读/写)之前发送 GetStatus 命令。
我获取 GPU 信息或更新 GPU 固件以触发读/写交易。
注:GPU 的 I3C IP 不是恩智浦产品
你好@Bruce_Teng、
谢谢您的答复。根据您的评论,从机 (CPU) 不符合 I3C 的要求,即在发出 IBI 请求之前,总线至少保持 IDLE状态 1 µs。我的理解正确吗?如果是这样,这就可以解释为什么主站(MCU)无法处理 IBI。
另一方面,AN14434 确切描述了 MCU 在您的应用中的预期行为类型。我强烈建议查看该文件,以确保 MCU 正常工作。
如果您还有其他问题,请告诉我。
BR
Habib