STM32H503RB I3C Abort HAL_I3C_Tgt_Receive_IT
Hello,
I'm trying to implement an I3C target device which sends inband interrupts when I push the blue Nucleo button.
But I also want it to be ready to receive data via a private message.
To do this I call `HAL_I3C_Tgt_Receive_IT` after receiving a dynamic address. But to send an inband interrupt I must abort this action and before being able to call `HAL_I3C_Tgt_IBIReq_IT`.
The problem I'm facing is that the abort only finalizes if the controller tries to send a private command. My expectation is that `HAL_I3C_Abort_IT` would abort the pending receive action right away so I can send an inband interrupt.
Is there any way to realize this by modifying the HAL library? Or am I using the HAL library in a faulty manner?
The state process I'm currently using to implement the target.
int i3ct_poll(void)
{
switch (_state)
{
case I3CS_WAITING_FOR_ADDRESS:
{
if (_got_address)
{
DBG_PRINTF("goto state idle\r\n");
_state = I3CS_IDLE;
}
} break;
case I3CS_IDLE:
{
// check if we must send an inband interrupt
if (_irq_pending)
{
// mark the interrupt as not send
_irq_send = 0;
// queue the interrupt
HAL_StatusTypeDef status = HAL_I3C_Tgt_IBIReq_IT(&hi3c1, _irq_data, _irq_data_len);
if (status != HAL_OK)
{
DBG_PRINTF("! ERROR ! failed to send interrupt (status: %d)\r\n", status);
break;
}
DBG_PRINTF("sending inband interrupt\r\n");
// change the state
_irq_pending = 0;
_state = I3CS_INTERRUPTING;
}
else
{
// reset the receive buffer
memset(_rx_buffer, 0, sizeof(_rx_buffer));
// prepare the receive descriptor
_transfer.RxBuf.pBuffer = _rx_buffer;
_transfer.RxBuf.Size = sizeof(_rx_buffer);
// start the receive process
HAL_StatusTypeDef status = HAL_I3C_Tgt_Receive_IT(&hi3c1, &_transfer);
if (status != HAL_OK)
{
DBG_PRINTF("! ERROR ! HAL_I3C_Tgt_Receive_IT failed with status %d\r\n", status);
break;
}
DBG_PRINTF("started listening for incoming data\r\n");
_state = I3CS_WAITING_FOR_DATA;
}
} break;
case I3CS_WAITING_FOR_DATA:
{
if (_irq_pending)
{
HAL_StatusTypeDef status = HAL_I3C_Abort_IT(&hi3c1);
if (status != HAL_OK)
DBG_PRINTF("! ERROR ! HAL_I3C_Abort_IT failed with status %d\r\n", status);
else
DBG_PRINTF("aborting receive to interrupt\r\n");
_state = I3CS_ABORTING;
break;
}
if (HAL_I3C_GetState(&hi3c1) == HAL_I3C_STATE_BUSY_RX)
break;
// decode the received frame
int slot_id = _rx_buffer[I3C_SLOT_ADDRESS_OFFSET];
int length = _rx_buffer[I3C_SLOT_DATA_LENGTH_OFFSET];
// copy the data to the appropriate slot
memset(_slots[slot_id].data, 0, sizeof(_slots[slot_id].data));
memcpy(_slots[slot_id].data, &_rx_buffer[I3C_SLOT_BUFFER_OFFSET], length);
DBG_PRINTF("received data (slot: %d - length: %d - message: %*s)\r\n", slot_id, length, length, &_rx_buffer[2]);
_state = I3CS_IDLE;
} break;
case I3CS_INTERRUPTING:
{
if (! _irq_send)
break;
DBG_PRINTF("interrupt send, goto state idle\r\n");
_state = I3CS_IDLE;
} break;
case I3CS_ABORTING:
{
if (HAL_I3C_GetState(&hi3c1) == HAL_I3C_STATE_ABORT)
break;
DBG_PRINTF("abort finished, goto state idle\r\n");
_state = I3CS_IDLE;
} break;
}
return 0;
}
The flow between the controller and the target is now as followed, I don't know if this gives a good impression of what is going on...: (lines starting with > are commands given via the console)
On the controller:
I3C-Controller v0.1.0
build on: Dec 19 2023 15:30:05
compiler: 11.3.1 20220712
console: initialized
rcc: reset causes
- PINRSTF
i3cc: assigning dynamic addresses
HAL_I3C_TgtReqDynamicAddrCallback
HAL_I3C_CtrlDAACpltCallback
i3cc: dynamic assigned targets:
i3cc: 0 = (manufacturer_id: 0x0104 - part_id: 0x1381 - dev_id: 0xc6)
On the target:
I3C-Target v0.1.0
build on: Dec 19 2023 16:29:21
compiler: 11.3.1 20220712
console: initialized
rcc: reset causes
- PINRSTF
HAL_I3C_NotifyCallback
EVENT_ID_DAU (address: 0x30)
i3ct: goto state idle
i3ct: started listening for incoming data
On the controller:
> send 1 test
HAL_I3C_CtrlTxCpltCallback
successfully stored the message on the target device
message: "test"
On the target:
HAL_I3C_ErrorCallback
HAL_I3C_ERROR_SIZE
i3ct: received data (slot: 1 - length: 4 - message: test)
i3ct: started listening for incoming data
<<< PRESSED THE BLUE NUCLEO BUTTON >>>
i3ct: aborting receive to interrupt
On the controller: (this is against my expectation, i would expect that this transfer should not be possible)
> send 1 test
HAL_I3C_CtrlTxCpltCallback
successfully stored the message on the slave device
message: "test"
On the target:
HAL_I3C_AbortCpltCallback
i3ct: abort finished, goto state idle
HAL_I3C_ErrorCallback
HAL_I3C_ERROR_DOVR
i3ct: sending inband interrupt
On the controller:
> send 1 test
HAL_I3C_ErrorCallback
HAL_I3C_ERROR_ADDRESS_NACK
successfully stored the message on the slave device
message: "test"
HAL_I3C_NotifyCallback
EVENT_ID_IBI
EVENT_ID_IBI
i3cc: IBI (address: 0x30 - len: 4 - payload: 0x12345678)
On the target:
i3ct: interrupt send, goto state idle
i3ct: started listening for incoming data
