Skip to main content
Graduate II
March 24, 2025
Question

I2C integration using DMA Driver

  • March 24, 2025
  • 2 replies
  • 446 views

Hi All,

I am integrating the IMU sensor Using I2C DMA in circular mode on stm32f103c8t6 using Hal Library, so facing an issue reading the address value.

In the below code "HAL_I2C_STATE_READY " this flag is not resetting after once function executes so in 2nd execution this HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size) function is not trigering to DMA Handler function. 

if (hi2c->State == HAL_I2C_STATE_READY)
 {
 /* Wait until BUSY flag is reset */
 count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U);
 do
 {
 count--;
 if (count == 0U)
 {
 hi2c->PreviousState = I2C_STATE_NONE;
 hi2c->State = HAL_I2C_STATE_READY;
 hi2c->Mode = HAL_I2C_MODE_NONE;
 hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;

 return HAL_BUSY;
 }
 }
 while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) != RESET);

 /* Process Locked */
 __HAL_LOCK(hi2c);

 /* Check if the I2C is already enabled */
 if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE)
 {
 /* Enable I2C peripheral */
 __HAL_I2C_ENABLE(hi2c);
 }

 /* Disable Pos */
 CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);

 hi2c->State = HAL_I2C_STATE_BUSY_RX;
 hi2c->Mode = HAL_I2C_MODE_MEM;
 hi2c->ErrorCode = HAL_I2C_ERROR_NONE;

 /* Prepare transfer parameters */
 hi2c->pBuffPtr = pData;
 hi2c->XferCount = Size;
 hi2c->XferSize = hi2c->XferCount;
 hi2c->XferOptions = I2C_NO_OPTION_FRAME;
 hi2c->Devaddress = DevAddress;
 hi2c->Memaddress = MemAddress;
 hi2c->MemaddSize = MemAddSize;
 hi2c->EventCount = 0U;

 /* Enable Acknowledge */
 SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);

 /* Generate Start */
 SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);

 /* Process Unlocked */
 __HAL_UNLOCK(hi2c);

 if (hi2c->XferSize > 0U)
 {
 /* Note : The I2C interrupts must be enabled after unlocking current process
 to avoid the risk of I2C interrupt handle execution before current
 process unlock */

 /* Enable EVT, BUF and ERR interrupt */
 __HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR);
 }
 return HAL_OK;
 }

 

    This topic has been closed for replies.

    2 replies

    Super User
    March 24, 2025

    How are you calling the HAL functions and what you're expecting to happen?

    Technical Moderator
    March 26, 2025

    Hello @Piyoosh 

    The HAL_I2C_STATE_READY flag is not reset immediately after the execution of HAL_I2C_Mem_Read_DMA(). Instead, the state remains busy until the transfer is complete. The end of the transfer is indicated by the invocation of the HAL_I2C_MemRxCpltCallback() function. To ensure that a subsequent transfer can be initiated successfully, you can either call the next transfer within the callback function or set a flag within this function and check it in the main loop before initiating the second transfer.

    Please refer to the implementation in the code snippet below:

    volatile uint8_t transferCompleteFlag = 0;
    
    void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c) {
     // Set the flag to indicate the transfer is complete
     transferCompleteFlag = 1;
    }
    
    void I2C_Read_DMA(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pData, uint16_t Size) {
     // Start the I2C memory read using DMA
     if (HAL_I2C_Mem_Read_DMA(&hi2c1, DevAddress, MemAddress, I2C_MEMADD_SIZE_8BIT, pData, Size) != HAL_OK) {
     // Handle error
     }
    }
    
    int main(void) {
     // HAL initialization
     HAL_Init();
     // System clock configuration
     SystemClock_Config();
     // I2C initialization
     MX_I2C1_Init();
    
     uint8_t data[10];
     uint16_t deviceAddress = 0x50;
     uint16_t memoryAddress = 0x00;
    
     // First I2C read transfer
     I2C_Read_DMA(deviceAddress, memoryAddress, data, sizeof(data));
    
     // Wait for the first transfer to complete
     while (transferCompleteFlag == 0) {
     // Optionally, you can add a timeout mechanism here
     }
    
     // Reset the flag for the next transfer
     transferCompleteFlag = 0;
    
     // Second I2C read transfer
     I2C_Read_DMA(deviceAddress, memoryAddress + 10, data, sizeof(data));
    
     // Main loop
     while (1) {
     // Application code
     }
    }