Two LPC5536-EVK boards were connected for I3C communication, with one configured as the I3C Master and the other as the I3C Slave.
When the Master sends a custom CCC with a data length of 0, the Slave misses to receive the kI3C_SlaveCompletionEvent.
Notes:
The CCC waveform output from the Master has been verified and is correct.
If the CCC includes data with length greater than 0, the Slave is able to receive the kI3C_SlaveCompletionEvent as expected.
Case: data length = 1
// Private Write
transfers[7]. event: TransmitEvent
transfers[8]. event: AddressMatchEvent
transfers[9]. event: ReceiveEvent
transfers[10]. event: CompletionEvent. status: 0, count: 6
// Private Read
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: CompletionEvent. status: 0, count: 5
// Custom CCC
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: ReceivedCCCEvent
transfers[3]. event: AddressMatchEvent
transfers[4]. event: ReceiveEvent
transfers[5]. event: CompletionEvent. status: 0, count: 1
// Private Write
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: CompletionEvent. status: 0, count: 6
// Private Read
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: CompletionEvent. status: 0, count: 5
Case: data length = 0
// Private Write
transfers[7]. event: TransmitEvent
transfers[8]. event: AddressMatchEvent
transfers[9]. event: ReceiveEvent
transfers[10]. event: CompletionEvent. status: 0, count: 6
// Private Read
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: CompletionEvent. status: 0, count: 5
// Private Write (mix with some events from previous Custom CCC)
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: TransmitEvent
transfers[3]. event: ReceivedCCCEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: ReceiveEvent
transfers[6]. event: ReceiveEvent
transfers[7]. event: CompletionEvent. status: 0, count: 0
// Private Read
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: CompletionEvent. status: 0, count: 5
已解决! 转到解答。
Hi @bell_huang
Thanks for your information.
I have tested it.
I tested it based on the
Case 2: I3C_MasterTransferNonBlocking (from fsl_i3c API)
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);
I can reproduce this issue.
So i try to add some debug code.
In fsl_i3c.c
When Master send the RepeatStart. it will enter while(1);
And i checked the logic analyze.
The waveform is correct.
So currently, when you want to write date through nonblocking. The SDK only support the DataSize >0.
May I ask if you have datasize=0 with write based on the nonblocking Related requirements?
If yes, you need modify related code.
BR
Harry
Hi @Harry_Zhang ,
Test steps:
(1) Reset slave board
(2) Reset master board
At this step, it can be observed that after the Slave receives the CCC, the callback does not trigger the kI3C_SlaveCompletionEvent.
(3, Optional) Click SW3 on master board
Master read register
Also check out the configuration of CCC data length in I3C_BusMasterCustomCCC function of master code:
cmd.dataSize = 1;
==============================
Case: data length = 1
--- Master log ---
data: 0x0
Write Custom CCC
Click SW3 to start
data: 0x65 // ---> Indicate that the slave received CCC successfully, so that the master can read the correct value
--- Slave log ---
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: TransmitEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: TransmitEvent
transfers[5]. event: TransmitEvent
transfers[6]. event: TransmitEvent
transfers[7]. event: TransmitEvent
transfers[8]. event: AddressMatchEvent
transfers[9]. event: ReceiveEvent
transfers[10]. event: TransmitEvent
transfers[11]. event: AddressMatchEvent
transfers[12]. event: CompletionEvent. status: 0, count: 0
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: ReceivedCCCEvent
transfers[3]. event: AddressMatchEvent
transfers[4]. event: ReceiveEvent
transfers[5]. event: CompletionEvent. status: 0, count: 1 // ---> Received kI3C_SlaveCompletionEvent after received CCC event
// After clicked on master SW3
transfers[0]. event: TransmitEvent
transfers[1]. event: AddressMatchEvent
transfers[2]. event: ReceiveEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: AddressMatchEvent
transfers[5]. event: CompletionEvent. status: 0, count: 0
==============================
Case: data length = 0
--- Master log ---
data: 0x0
Write Custom CCC
Click SW3 to start
data: 0x90 // ---> Wrong value
--- Slave log ---
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: TransmitEvent
transfers[3]. event: TransmitEvent
transfers[4]. event: TransmitEvent
transfers[5]. event: TransmitEvent
transfers[6]. event: TransmitEvent
transfers[7]. event: TransmitEvent
transfers[8]. event: AddressMatchEvent
transfers[9]. event: ReceiveEvent
transfers[10]. event: TransmitEvent
transfers[11]. event: AddressMatchEvent
transfers[12]. event: CompletionEvent. status: 0, count: 0
// ---> Miss kI3C_SlaveCompletionEvent here after receiving CCC event.
// After clicked on master SW3
transfers[0]. event: TransmitEvent
transfers[1]. event: TransmitEvent
transfers[2]. event: TransmitEvent
transfers[3]. event: AddressMatchEvent
transfers[4]. event: ReceivedCCCEvent
transfers[5]. event: ReceiveEvent
transfers[6]. event: TransmitEvent
transfers[7]. event: ReceivedCCCEvent
transfers[8]. event: AddressMatchEvent
transfers[9]. event: CompletionEvent. status: 7904
transfers[10]. event: TransmitEvent
transfers[11]. event: CompletionEvent. status: 0, count: 5
Hi @bell_huang
Would it be possible to make minimal modifications based on the i3c SDK example to verify the this functionality?
Additionally, could you provide the waveform data?
BR
Harry
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);
Hi @bell_huang
Thanks for your information.
I have tested it.
I tested it based on the
Case 2: I3C_MasterTransferNonBlocking (from fsl_i3c API)
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);
I can reproduce this issue.
So i try to add some debug code.
In fsl_i3c.c
When Master send the RepeatStart. it will enter while(1);
And i checked the logic analyze.
The waveform is correct.
So currently, when you want to write date through nonblocking. The SDK only support the DataSize >0.
May I ask if you have datasize=0 with write based on the nonblocking Related requirements?
If yes, you need modify related code.
BR
Harry
Hi @Harry_Zhang ,
I’m not sure how to modify the code related to the non-blocking function. Fortunately, it is confirmed that the blocking function works correctly, so for now, I will use I3C_MasterTransferBlocking to implement the Custom CCC.
Since I typically use the higher-level API (fsl_component_i3c_adapter), it would be ideal if the NXP SDK team could address this issue in a future update. Once it is fixed, I will switch back to using I3C_BusMasterSendCCC for Custom CCC implementation.