2024-12-01 04:34 PM - edited 2024-12-01 04:45 PM
MCU: STM32L476RGT6
Hello,
I am able to communicate with the MPU6050 via I2C with DMA and read the WHO_AM_I register, but only one transmit and receive transaction occurs even though I put my transmission and receive code in a while loop.
When using regular I2C transmission (no DMA), multiple transactions are performed (as expected). This tells me that there may be some flags I need to reset or functions I need to call between transmission. However, when comparing my code to this example, I could not tell what I was missing.
My code is getting stuck on line 61 here. That tells me that an internal process is occurring, so the MCU is never ready for another transmission.
Below is my driver code. What am I missing?
Thanks.
#define MPU6050ADDR 0b11010010
int main(void)
{
uint8_t WHO_AM_I[1] = {0x75};
HAL_Init();
SystemClock_Config();
I2C_Init();
DMA_Init();
while (1)
{
if(HAL_I2C_Master_Transmit_DMA(&hI2C, MPU6050ADDR, WHO_AM_I, 1,100) != HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&hI2C) != HAL_I2C_STATE_READY);
while(HAL_I2C_GetError(&hI2C) == HAL_I2C_ERROR_AF);
if(HAL_I2C_Master_Receive_DMA(&hI2C, MPU6050ADDR, Buffer_Dest,1,100) != HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&hI2C) != HAL_I2C_STATE_READY);
while(HAL_I2C_GetError(&hI2C) == HAL_I2C_ERROR_AF); }
}
2024-12-05 08:19 AM
Hello @HamzaBeder
I recommend referring to the I2C example available in the STM32CubeL4 firmware package instead of the STM32F0 example.
The STM32L4 series provides distinct interrupt handler for I2C events and errors, as well as for I2C DMA TX and RX.
/**
* @brief This function handles I2C event interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to I2C data transmission
*/
void I2Cx_EV_IRQHandler(void)
{
HAL_I2C_EV_IRQHandler(&I2cHandle);
}
/**
* @brief This function handles I2C error interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to I2C error
*/
void I2Cx_ER_IRQHandler(void)
{
HAL_I2C_ER_IRQHandler(&I2cHandle);
}
/**
* @brief This function handles DMA interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to DMA Channel
* used for I2C data transmission
*/
void I2Cx_DMA_RX_IRQHandler(void)
{
HAL_DMA_IRQHandler(I2cHandle.hdmarx);
}
/**
* @brief This function handles DMA interrupt request.
* @param None
* @retval None
* @Note This function is redefined in "main.h" and related to DMA Channel
* used for I2C data reception
*/
void I2Cx_DMA_TX_IRQHandler(void)
{
HAL_DMA_IRQHandler(I2cHandle.hdmatx);
}
Please review the example and update your implementation accordingly. If you have any further questions or need additional assistance, feel free to ask.
2024-12-13 08:11 AM
you can set a flag in the RxCpltCallback and check this flag in the while(1) of main, so that you dont call the DMA immediately after a DMA call. DMA call returns immediately and making further calls will create error. in the below example I have used a flag for the DMA receive, and DMA transmit is blocking type. you can extend this idea if you want to transmit also in DMA.
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
dmaCompleteFlag = 1;
}
in your while(1)
if ( dmaCompleteFlag)
{
dmaCompleteFlag = 0;
if(HAL_I2C_Master_Transmit(&hI2C, MPU6050ADDR, WHO_AM_I, 1,100) != HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&hI2C) != HAL_I2C_STATE_READY);
while(HAL_I2C_GetError(&hI2C) == HAL_I2C_ERROR_AF);
if(HAL_I2C_Master_Receive_DMA(&hI2C, MPU6050ADDR, Buffer_Dest,1,100) != HAL_OK)
Error_Handler();
while (HAL_I2C_GetState(&hI2C) != HAL_I2C_STATE_READY);
while(HAL_I2C_GetError(&hI2C) == HAL_I2C_ERROR_AF); }
}