DAVE I2C Driver - DMA Support missing, Direct mode busy loops forever

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
User10538
Level 3
Level 3
Altough DMA Mode is selectable in the current DAVE App 4.1.12, it does not work.
Looking into the code


#if (I2C_MASTER_DMA_RX_ENABLED == 1)
status = I2C_MASTER_STATUS_UNSUPPORTED_MODE;
#endif

Was this just forgotten? When do you plan to add this?

Also your implementation of DIRECT Mode is horribly flawed:
When NACK is received because the slave is for example not plugged in, the driver gets stuck polling the ACK register forever.

while (I2C_MASTER_GetFlagStatus(handle, (uint32_t)XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}

This should not happen, instead the NACK should be reported to the caller, maybe a I2C_MASTER_STATUS_NODEVICE.
0 Likes
4 Replies
User7921
Level 3
Level 3
Hi,

I had the same problem.
Please see my thread and it's answers: https://www.infineonforums.com/threads/4040-I2C-Master-App-Error

Michael
0 Likes
User10538
Level 3
Level 3
Thx, this answers the first part of my question and makes sense. This curiousity should in my opinion be documented in the app help by infineon with a big expression mark and/or examples.

The DIRECT Mode however is definetly a bug and should be fixed somehow.
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

DMA is supported but using a different API (see below). Unfortunately is not described in the help documentation. This is issue is going to be solved in the next release en of August.
Actually in the documentation of the I2C_MASTER_Transmit() it is written that only Interrupt and direct mode are supported.

Regarding the direct mode issue we are analysing a possible fix for the I2C_MASTER_Transmit() to avoid blocking, in the mean time you can use other non blocking APIs i.e. I2C_MASTER_SendStart(), I2C_MASTER_TransmitByte(), ...

Best regards,
Jesus

/**
* @brief Registers a request for transmitting data over I2C channel using DMA.
*
* @param handle I2C_MASTER APP handle pointer of type @ref I2C_MASTER_t
* @param block_size size of the block
* @param addr address\n
* \b Range: minimum= 1, maximum= 4095.
*
* @return I2C_MASTER_STATUS_t: Status of transmit request.\n
* @ref I2C_MASTER_STATUS_SUCCESS if the request is accepted.\n
* @ref I2C_MASTER_STATUS_BUSY if a transmission is in progress.\n
*
* Imp Note: Return value should be validated by user to ensure that the
* request is registered.
*
* \parDescription:

* The data transmission is accomplished using DMA. User can configure a callback function in the APP UI.
* When the data is fully transmitted, the callback function will be executed. The function uses APP handle's runtime
* structure to store the status of transmission.
* This function only registers a data transmission request, if there is no active transmission in progress.
* Actual data transmission happens through DMA channel.
* A maximum of 4095 bytes can be transmitted in one API call. This limit is because of the DMA single block size.
* Callback function is executed when all the data bytes are transmitted.
* If a callback function is not configured, user has to poll for the value of \a tx_busy flag of
* the APP handle structure( \a handle->runtime->tx_busy ) to check for
* the completion of data transmission.
* If data more than the block size of 4095 have to be transmitted, user will have to transmit them using multiple
* calls to this API.
* \parNOTE:

* I2C_MASTER_StartTransmitDMA API can be used in DMA mode.
* Transmit should be configured as "DMA" mode in advanced settings tab.

* Example Usage:
*
* @code
*
* #include //Declarations from DAVE Code Generation (includes SFR declaration)
* #define SLAVE_ADDRESS 0xA0
* uint8_t Send_Data[] = "Infineon Technologies";
* int main(void)
* {
* DAVE_STATUS_t init_status;
*
* init_status = DAVE_Init();
* if(init_status == DAVE_STATUS_SUCCESS)
* {
* I2C_MASTER_SendStart(&I2C_MASTER_0, SLAVE_ADDRESS, XMC_I2C_CH_CMD_WRITE);
* while(I2C_MASTER_GetFlagStatus(&I2C_MASTER_0, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
* {
* // wait for ACK
* }
* I2C_MASTER_ClearFlag(&I2C_MASTER_0,XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);
* // write to address 0
* I2C_MASTER_TransmitByte(&I2C_MASTER_0, 0x00);
* while(I2C_MASTER_GetFlagStatus(&I2C_MASTER_0, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
* {
* // wait for ACK
* }
* I2C_MASTER_ClearFlag(&I2C_MASTER_0,XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);
* // trigger the DMA
* I2C_MASTER_StartTransmitDMA(&I2C_MASTER_0, sizeof(Send_Data), Send_Data);
* while(I2C_MASTER_IsTxBusy(&I2C_MASTER_0));
* }
* else
* {
* XMC_DEBUG("main: Application initialization failed");
* while(1U)
* {
* }
* }
* return 1U;
* }
* @endcode
*
*/
I2C_MASTER_STATUS_t I2C_MASTER_StartTransmitDMA(const I2C_MASTER_t *const handle, uint32_t block_size, uint8_t *addr);
0 Likes
User10538
Level 3
Level 3
Thanks for the answer Jesus.

I've been looking into the code in I2C_MASTER_lStartTransmitPolling() and thought about a solution:
In the direct Mode you must poll on the TBIF flag, after that you can evaluate NACK and ACK (not while loop on ACK-Flag but on TBIF). If ACK=1 continue with the remaining Data. If NACK=1 you must return and not continue with the Data (possibly flush fifo?).
The enum I2C_MASTER_STATUS should have an I2C_MASTER_STATUS_ACK, I2C_MASTER_STATUS_NACK, instead of success and failure - the caller must be able to discern if transfer worked or not because of the device not answering OR if there was another error like a blocked bus, arbitration lost etc.


This bug occurs numerous times throughout i2c_master.c, basically at every comment /* wait for ACK */ (also in DMA mode! Only Interrupt Mode seems not to block).

Generally the usage of while in your drivers without a timeout is a problem throughout most of your DAVE APP drivers - you should definitly add those in the longterm.
0 Likes