I tried simplifying my example to be even more minimal than the SDK example.
I found that the issue occurs on the Master side, rather than on the Slave side as originally assumed.
In summary, when implementing a Custom CCC with no data on the Master, using I3C_MasterTransferBlocking works correctly. However, when using I3C_MasterTransferNonBlocking, the waveform is incorrect.
The expected waveform sequence for a Custom CCC is: 0x7E -> 0xF0 (Custom CCC) -> 0x09 (Slave Address). Below, I only show the waveform for the Slave Address. The following three cases use the same Slave driver, but different Master driver APIs.
Test steps:
(1) Reset Slave
(2) Reset Master
(3) Click Master SW3
Case 1: I3C_MasterTransferBlocking (from fsl_i3c API)
-> The waveform is correct.
uint8_t cmdId = 0xF0;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = 0x7E;
masterXfer.data = &cmdId;
masterXfer.dataSize = 1;
masterXfer.direction = kI3C_Write;
masterXfer.busType = kI3C_TypeI3CSdr;
masterXfer.flags = (uint32_t)kI3C_TransferNoStopFlag;
result = I3C_MasterTransferBlocking(EXAMPLE_MASTER, &masterXfer);
if (result != kStatus_Success)
PRINTF("I3C_MasterTransferBlocking Write cmdId failed: %d\r\n", result);
uint8_t data[10];
memset(data, 0, sizeof(data));
data[0] = 0x01;
data[1] = 0x02;
data[2] = 0x03;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = slaveAddr;
masterXfer.data = data;
masterXfer.dataSize = 0;
masterXfer.direction = kI3C_Write;
masterXfer.busType = kI3C_TypeI3CSdr;
masterXfer.flags = (uint32_t)kI3C_TransferRepeatedStartFlag;
result = I3C_MasterTransferBlocking(EXAMPLE_MASTER, &masterXfer);
if (result != kStatus_Success)
PRINTF("I3C_MasterTransferBlocking Write data failed: %d\r\n", result);

Case 2: I3C_MasterTransferNonBlocking (from fsl_i3c API)
-> The Slave Address sent is incorrect, resulting in a NACK.
uint8_t cmdId = 0xF0;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = 0x7E;
masterXfer.data = &cmdId;
masterXfer.dataSize = 1;
masterXfer.direction = kI3C_Write;
masterXfer.busType = kI3C_TypeI3CSdr;
masterXfer.flags = (uint32_t)kI3C_TransferNoStopFlag;
g_masterCompletionFlag = false;
I3C_MasterTransferNonBlocking(EXAMPLE_MASTER, &masterHandle, &masterXfer);
while (!g_masterCompletionFlag)
{
__NOP();
}
if (g_completionStatus != kStatus_Success)
PRINTF("I3C_MasterTransferNonBlocking Write cmdId failed: %d\r\n", g_completionStatus);
uint8_t data[10];
memset(data, 0, sizeof(data));
data[0] = 0x01;
data[1] = 0x02;
data[2] = 0x03;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = slaveAddr;
masterXfer.data = data;
masterXfer.dataSize = 0;
masterXfer.direction = kI3C_Write;
masterXfer.busType = kI3C_TypeI3CSdr;
masterXfer.flags = (uint32_t)kI3C_TransferRepeatedStartFlag;
g_masterCompletionFlag = false;
I3C_MasterTransferNonBlocking(EXAMPLE_MASTER, &masterHandle, &masterXfer);
while (!g_masterCompletionFlag)
{
__NOP();
}
if (g_completionStatus != kStatus_Success)
PRINTF("I3C_MasterTransferNonBlocking Write data failed: %d\r\n", g_completionStatus);

If you change dataSize from 0 to 1, the waveform of Slave Address will be correct.

Case 3: I3C_BusMasterSendCCC (from fsl_component_i3c_adapter API)
-> Internally uses I3C_MasterTransferNonBlocking, so the behavior is the same as Case 2.
uint8_t cmdId = 0xF0;
i3c_ccc_cmd_t cmd = {0};
uint8_t data[10];
memset(data, 0, sizeof(data));
data[0] = 0x01;
data[1] = 0x02;
data[2] = 0x03;
cmd.isRead = false;
cmd.cmdId = 0xF0;
cmd.destAddr = slaveAddr;
cmd.data = data;
cmd.dataSize = 0;
status_t result = I3C_BusMasterSendCCC(&masterDev, &cmd);
if (result != kStatus_Success)
PRINTF("I3C_BusMasterSendCCC failed: %d\r\n", result);