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;
}

 

 

 

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);
    }
}

 

 

 

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.