cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H503RB I3C target equivalent of HAL_I3C_Ctrl_MultipleTransfer_IT

Nick van IJzendoorn
Associate III

Hello,

Currently I'm playing around with the I3C peripheral and I try to implement a sort of "eeprom" interface on a I3C target where I have 10 slots which I want to be able to address separately.

So on the controller side I have this function:

 

 

int i3cc_target_read(int slot_id, uint8_t *buffer) { static uint8_t tx_buffer[I3C_SLOT_ADDRESS_LENGTH]; static uint8_t rx_buffer[I3C_SLOT_DATA_LENGTH_LENGTH + I3C_SLOT_BUFFER_LENGTH]; if (slot_id < 0 || slot_id >= I3C_SLOT_COUNT) return -1; if (_state != I3CS_IDLE) return -2; // prepare the tx frame buffer tx_buffer[I3C_SLOT_ADDRESS_OFFSET] = slot_id; // build the I3C transaction uint32_t ctrl_buffer[16]; I3C_PrivateTypeDef private_messages[2] = { { .TargetAddr = _targets[0].dynamic_address, .TxBuf = { tx_buffer, sizeof(tx_buffer) }, .RxBuf = { NULL, 0 }, .Direction = HAL_I3C_DIRECTION_WRITE }, { .TargetAddr = _targets[0].dynamic_address, .TxBuf = { NULL, 0 }, .RxBuf = { rx_buffer, sizeof(rx_buffer) }, .Direction = HAL_I3C_DIRECTION_READ } }; I3C_XferTypeDef transfer = { .CtrlBuf = { ctrl_buffer, 2 }, .StatusBuf = { NULL, 0 }, .TxBuf = { tx_buffer, sizeof(tx_buffer) }, .RxBuf = { rx_buffer, sizeof(rx_buffer) } }; HAL_StatusTypeDef status = HAL_I3C_AddDescToFrame( &hi3c1, NULL, private_messages, &transfer, transfer.CtrlBuf.Size, I3C_PRIVATE_WITH_ARB_RESTART); if (status != HAL_OK) { printf("! ERROR ! HAL_I3C_AddDescToFrame failed with status: %d\r\n", status); return -3; } status = HAL_I3C_Ctrl_MultipleTransfer_IT(&hi3c1, &transfer); if (status != HAL_OK) { printf("! ERROR ! HAL_I3C_Ctrl_MultipleTransfer_IT failed with status: %d\r\n", status); return -4; } while (HAL_I3C_GetState(&hi3c1) == HAL_I3C_STATE_BUSY_TX_RX) ; // copy the received data into the destination buffer memset(buffer, 0, I3C_SLOT_BUFFER_LENGTH); memcpy(buffer, &rx_buffer[1], rx_buffer[0]); return 0; }
View more

 

 

 

On the target side I have the following state process handling this request:

 

 

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)); memset(_tx_buffer, 0, sizeof(_tx_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; } HAL_I3C_StateTypeDef state = HAL_I3C_GetState(&hi3c1); if (state == HAL_I3C_STATE_BUSY_RX || state == HAL_I3C_STATE_BUSY_TX) 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; } void HAL_I3C_ErrorCallback(I3C_HandleTypeDef *hi3c) { printf("%s\r\n", __FUNCTION__); if (hi3c->ErrorCode == HAL_I3C_ERROR_DATA_HAND_OFF) { printf("HAL_I3C_ERROR_DATA_HAND_OFF\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_DATA_NACK) { printf("HAL_I3C_ERROR_DATA_NACK\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_ADDRESS_NACK) { printf("HAL_I3C_ERROR_ADDRESS_NACK\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_COVR) { printf("HAL_I3C_ERROR_COVR\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_DOVR) { printf("HAL_I3C_ERROR_DOVR\r\n"); _irq_send = 1; } else if (hi3c->ErrorCode == HAL_I3C_ERROR_STALL) { printf("HAL_I3C_ERROR_STALL\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_DMA) { printf("HAL_I3C_ERROR_DMA\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TIMEOUT) { printf("HAL_I3C_ERROR_TIMEOUT\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_DMA_PARAM) { printf("HAL_I3C_ERROR_DMA_PARAM\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_INVALID_PARAM) { printf("HAL_I3C_ERROR_INVALID_PARAM\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_SIZE) { printf("HAL_I3C_ERROR_SIZE\r\n"); // test if only 1 byte was written if ((hi3c->Instance->SR & I3C_SR_XDCNT_Msk) == 1) { // decode the received frame int slot_id = _rx_buffer[I3C_SLOT_ADDRESS_OFFSET]; // copy the data from the appropriate slot _tx_buffer[0] = _slots[slot_id].length; memcpy(&_tx_buffer[1], _slots[slot_id].data, sizeof(_slots[slot_id].data)); // prepare the transmit descriptor _transfer.TxBuf.pBuffer = _tx_buffer; _transfer.TxBuf.Size = sizeof(_tx_buffer); // start the transmit process HAL_StatusTypeDef status = HAL_I3C_Tgt_Transmit_IT(&hi3c1, &_transfer); if (status != HAL_OK) DBG_PRINTF("! ERROR ! HAL_I3C_Tgt_Transmit_IT failed with status %d\r\n", status); else DBG_PRINTF("started sending data for slot %d\r\n", slot_id); } } else if (hi3c->ErrorCode == HAL_I3C_ERROR_NOT_ALLOWED) { printf("HAL_I3C_ERROR_NOT_ALLOWED\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_DYNAMIC_ADDR) { printf("HAL_I3C_ERROR_DYNAMIC_ADDR\r\n"); } else if (hi3c->Mode == HAL_I3C_MODE_CONTROLLER) { if (hi3c->ErrorCode == HAL_I3C_ERROR_CE0) { printf("! ERROR ! illegal formatted CCC\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_CE1) { printf("! ERROR ! arbitrary loss\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_CE2) { printf("! ERROR ! broadcast address NACKed\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_CE3) { printf("! ERROR ! role swap failure\r\n"); } else { printf("! ERROR ! 0x%08lx\r\n", hi3c->ErrorCode); } } else if (hi3c->Mode == HAL_I3C_MODE_TARGET) { if (hi3c->ErrorCode == HAL_I3C_ERROR_TE0) { printf("! ERROR ! invalid broadcast address\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE1) { printf("! ERROR ! invalid CCC code\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE2) { printf("! ERROR ! write parity error\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE3) { printf("! ERROR ! DAA parity error\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE4) { printf("! ERROR ! missing broadcast after reset\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE5) { printf("! ERROR ! illegal formatted CCC\r\n"); } else if (hi3c->ErrorCode == HAL_I3C_ERROR_TE6) { printf("! ERROR ! arbitrary loss\r\n"); } else { printf("! ERROR ! 0x%08lx\r\n", hi3c->ErrorCode); } } else { printf("! ERROR ! 0x%08lx\r\n", hi3c->ErrorCode); } }
View more

 

 

 

Now in the error handler   i try to start the transfer belonging to that slot. But probably it finishes to late the peripheral already NACK's the read. Would it be possible to implement a HAL_I3C_Tgt_ReceiveTransmit_IT something?

 

PS. I tried removing the printf's in the interrupts to make it faster, but with no success.

 

PS2: while looking with the logic analyzer I see why it's not working. The TRIGGER_TRT high is when the interrupt / ErrorCallback is executed. So it's way to long and way to late for what I want to accomplish. I'll try and create my own function...

NickvanIJzendoorn_0-1703057876541.png

 

1 REPLY 1
Foued_KH
ST Employee

Hello @Nick van IJzendoorn , 

And if you try with DMA instead of the IT mode ?
Also remove the printf's in the target side .

Let me know if it works !
Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.