Skip to main content
Graduate II
June 11, 2025
Solved

[STM32F103C8T6 + ICM20948] IMU not detected when using FreeRTOS with I2C.

  • June 11, 2025
  • 3 replies
  • 1974 views

Hi everyone,

I'm working on a project using the STM32F103C8T6 microcontroller and the ICM-20948 IMU sensor, connected via I2C. I'm using STM32CubeIDE with FreeRTOS integration.

In a bare-metal (non-RTOS) project, the IMU communicates correctly. The device address is detected properly, and I get valid accel/gyro data.

When I move to a FreeRTOS-based project using the same I2C configuration, the IMU fails to respond.The device address is not found, and I get errors from HAL_I2C_Mem_Read().I've confirmed that I2C are initialized before osKernelStart().

 want to reliably read IMU data (ICM20948) using I2C  + FreeRTOS on STM32F103C8T6.
Can anyone who has done this successfully share suggestions or example code?

 

    This topic has been closed for replies.
    Best answer by Andrew Neil

    @Piyoosh wrote:

    what should i check now ?


    You need to check why it's not initialising!

     

    PS:

    eg, is the initialisation even being called at all?

    are you getting errors in the initialisation?

     

    Again, you have working code as a reference - so compare & contrast what happens in that working code to what happens in the non-working code ...

    3 replies

    Explorer
    June 11, 2025

    The timing differs, and FreeRTOS grabs and manages interrupts.

    You need to take a scope / logic analyser, and find out where it fails.

    Technical Moderator
    June 11, 2025

    If it works in baremetal that's definitely not a hardware issue, but something related to your integration and how are you implementing the sensor reading in the task.

    As @Ozone said, most probably it's a timing issue. Check the task priority versus others. Check the interrupt priorities versus others. 

    PiyooshAuthor
    Graduate II
    June 11, 2025

    Thanks for responding

    I am using only one task in setup. 

    this line --- HAL_I2C_Mem_Read(&hi2c1, (0x69 << 1), 0x00, 1, &check,1, 100); is properly return check value "234"(0xEA) in bare-metal (non-RTOS) project which is show that sensor is available  to read data, but in RTOS project (i include Free Rtos code bellow) it is reading 8 value of check.Screenshot (213).jpg

    /* USER CODE BEGIN Header */
    /**
     ******************************************************************************
     * @file : main.c
     * @brief : Main program body
     ******************************************************************************
     * @attention
     *
     * Copyright (c) 2025 STMicroelectronics.
     * All rights reserved.
     *
     * This software is licensed under terms that can be found in the LICENSE file
     * in the root directory of this software component.
     * If no LICENSE file comes with this software, it is provided AS-IS.
     *
     ******************************************************************************
     */
    /* USER CODE END Header */
    /* Includes ------------------------------------------------------------------*/
    #include "main.h"
    #include "cmsis_os.h"
    
    /* Private includes ----------------------------------------------------------*/
    /* USER CODE BEGIN Includes */
    #include "i2c.h"
    /* USER CODE END Includes */
    
    /* Private typedef -----------------------------------------------------------*/
    /* USER CODE BEGIN PTD */
    
    /* USER CODE END PTD */
    
    /* Private define ------------------------------------------------------------*/
    /* USER CODE BEGIN PD */
    
    /* USER CODE END PD */
    
    /* Private macro -------------------------------------------------------------*/
    /* USER CODE BEGIN PM */
    
    /* USER CODE END PM */
    
    /* Private variables ---------------------------------------------------------*/
    CRC_HandleTypeDef hcrc;
    
    I2C_HandleTypeDef hi2c1;
    I2C_HandleTypeDef hi2c2;
    
    UART_HandleTypeDef huart1;
    
    osThreadId defaultTaskHandle;
    /* USER CODE BEGIN PV */
    
    /* USER CODE END PV */
    
    /* Private function prototypes -----------------------------------------------*/
    void SystemClock_Config(void);
    static void MX_GPIO_Init(void);
    static void MX_I2C2_Init(void);
    static void MX_CRC_Init(void);
    static void MX_USART1_UART_Init(void);
    static void MX_I2C1_Init(void);
    void StartDefaultTask(void const * argument);
    
    /* USER CODE BEGIN PFP */
    
    /* USER CODE END PFP */
    
    /* Private user code ---------------------------------------------------------*/
    /* USER CODE BEGIN 0 */
    
    /* USER CODE END 0 */
    
    /**
     * @brief The application entry point.
     * @retval int
     */
    int main(void)
    {
    
     /* USER CODE BEGIN 1 */
    
     /* USER CODE END 1 */
    
     /* MCU Configuration--------------------------------------------------------*/
    
     /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
     HAL_Init();
    
     /* USER CODE BEGIN Init */
    
     /* USER CODE END Init */
    
     /* Configure the system clock */
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
    
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_I2C2_Init();
     MX_CRC_Init();
     MX_USART1_UART_Init();
     MX_I2C1_Init();
     /* USER CODE BEGIN 2 */
    
     /* USER CODE END 2 */
    
     /* USER CODE BEGIN RTOS_MUTEX */
     /* add mutexes, ... */
     /* USER CODE END RTOS_MUTEX */
    
     /* USER CODE BEGIN RTOS_SEMAPHORES */
     /* add semaphores, ... */
     /* USER CODE END RTOS_SEMAPHORES */
    
     /* USER CODE BEGIN RTOS_TIMERS */
     /* start timers, add new ones, ... */
     /* USER CODE END RTOS_TIMERS */
    
     /* USER CODE BEGIN RTOS_QUEUES */
     /* add queues, ... */
     /* USER CODE END RTOS_QUEUES */
    
     /* Create the thread(s) */
     /* definition and creation of defaultTask */
     osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
     defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
    
     /* USER CODE BEGIN RTOS_THREADS */
     /* add threads, ... */
     /* USER CODE END RTOS_THREADS */
    
     /* Start scheduler */
     osKernelStart();
    
     /* We should never get here as control is now taken by the scheduler */
    
     /* Infinite loop */
     /* USER CODE BEGIN WHILE */
     while (1)
     {
     /* USER CODE END WHILE */
    
     /* USER CODE BEGIN 3 */
     }
     /* USER CODE END 3 */
    }
    
    /**
     * @brief System Clock Configuration
     * @retval None
     */
    void SystemClock_Config(void)
    {
     RCC_OscInitTypeDef RCC_OscInitStruct = {0};
     RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
     /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
     RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
     RCC_OscInitStruct.HSEState = RCC_HSE_ON;
     RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
     RCC_OscInitStruct.HSIState = RCC_HSI_ON;
     RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
     RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
     RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
     if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
     {
     Error_Handler();
     }
    
     /** Initializes the CPU, AHB and APB buses clocks
     */
     RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
     |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
     RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
     RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
     RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
     RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
     {
     Error_Handler();
     }
    }
    
    /**
     * @brief CRC Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_CRC_Init(void)
    {
    
     /* USER CODE BEGIN CRC_Init 0 */
    
     /* USER CODE END CRC_Init 0 */
    
     /* USER CODE BEGIN CRC_Init 1 */
    
     /* USER CODE END CRC_Init 1 */
     hcrc.Instance = CRC;
     if (HAL_CRC_Init(&hcrc) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN CRC_Init 2 */
    
     /* USER CODE END CRC_Init 2 */
    
    }
    
    /**
     * @brief I2C1 Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_I2C1_Init(void)
    {
    
     /* USER CODE BEGIN I2C1_Init 0 */
    
     /* USER CODE END I2C1_Init 0 */
    
     /* USER CODE BEGIN I2C1_Init 1 */
    
     /* USER CODE END I2C1_Init 1 */
     hi2c1.Instance = I2C1;
     hi2c1.Init.ClockSpeed = 100000;
     hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
     hi2c1.Init.OwnAddress1 = 0;
     hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
     hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
     hi2c1.Init.OwnAddress2 = 0;
     hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
     if (HAL_I2C_Init(&hi2c1) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN I2C1_Init 2 */
    
     /* USER CODE END I2C1_Init 2 */
    
    }
    
    /**
     * @brief I2C2 Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_I2C2_Init(void)
    {
    
     /* USER CODE BEGIN I2C2_Init 0 */
    
     /* USER CODE END I2C2_Init 0 */
    
     /* USER CODE BEGIN I2C2_Init 1 */
    
     /* USER CODE END I2C2_Init 1 */
     hi2c2.Instance = I2C2;
     hi2c2.Init.ClockSpeed = 100000;
     hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
     hi2c2.Init.OwnAddress1 = 0;
     hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
     hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
     hi2c2.Init.OwnAddress2 = 0;
     hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
     hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
     if (HAL_I2C_Init(&hi2c2) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN I2C2_Init 2 */
    
     /* USER CODE END I2C2_Init 2 */
    
    }
    
    /**
     * @brief USART1 Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_USART1_UART_Init(void)
    {
    
     /* USER CODE BEGIN USART1_Init 0 */
    
     /* USER CODE END USART1_Init 0 */
    
     /* USER CODE BEGIN USART1_Init 1 */
    
     /* USER CODE END USART1_Init 1 */
     huart1.Instance = USART1;
     huart1.Init.BaudRate = 115200;
     huart1.Init.WordLength = UART_WORDLENGTH_8B;
     huart1.Init.StopBits = UART_STOPBITS_1;
     huart1.Init.Parity = UART_PARITY_NONE;
     huart1.Init.Mode = UART_MODE_TX_RX;
     huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
     huart1.Init.OverSampling = UART_OVERSAMPLING_16;
     if (HAL_UART_Init(&huart1) != HAL_OK)
     {
     Error_Handler();
     }
     /* USER CODE BEGIN USART1_Init 2 */
    
     /* USER CODE END USART1_Init 2 */
    
    }
    
    /**
     * @brief GPIO Initialization Function
     * @PAram None
     * @retval None
     */
    static void MX_GPIO_Init(void)
    {
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     /* USER CODE BEGIN MX_GPIO_Init_1 */
    
     /* USER CODE END MX_GPIO_Init_1 */
    
     /* GPIO Ports Clock Enable */
     __HAL_RCC_GPIOC_CLK_ENABLE();
     __HAL_RCC_GPIOD_CLK_ENABLE();
     __HAL_RCC_GPIOA_CLK_ENABLE();
     __HAL_RCC_GPIOB_CLK_ENABLE();
    
     /*Configure GPIO pin Output Level */
     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
    
     /*Configure GPIO pin : PA7 */
     GPIO_InitStruct.Pin = GPIO_PIN_7;
     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
     /* USER CODE BEGIN MX_GPIO_Init_2 */
    
     /* USER CODE END MX_GPIO_Init_2 */
    }
    
    /* USER CODE BEGIN 4 */
    
    /* USER CODE END 4 */
    
    /* USER CODE BEGIN Header_StartDefaultTask */
    /**
     * @brief Function implementing the defaultTask thread.
     * @PAram argument: Not used
     * @retval None
     */
    /* USER CODE END Header_StartDefaultTask */
    void StartDefaultTask(void const * argument)
    {
    	uint8_t check;
     /* USER CODE BEGIN 5 */
    	HAL_I2C_Mem_Read(&hi2c1, (0x69 << 1), 0x00, 1, &check,1, 100);
    	if (check==234)
    	{
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
    	}
    	else
    	{
    		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_RESET);
    	}
    
    
     /* Infinite loop */
     for(;;)
     {
    	 ICM20948_Read_Accel(&hi2c1, &ICMData, ICM20948_ADDR);
     osDelay(100);
     }
     /* USER CODE END 5 */
    }
    
    /**
     * @brief Period elapsed callback in non blocking mode
     * @note This function is called when TIM1 interrupt took place, inside
     * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
     * a global variable "uwTick" used as application time base.
     * @PAram htim : TIM handle
     * @retval None
     */
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
     /* USER CODE BEGIN Callback 0 */
    
     /* USER CODE END Callback 0 */
     if (htim->Instance == TIM1)
     {
     HAL_IncTick();
     }
     /* USER CODE BEGIN Callback 1 */
    
     /* USER CODE END Callback 1 */
    }
    
    /**
     * @brief This function is executed in case of error occurrence.
     * @retval None
     */
    void Error_Handler(void)
    {
     /* USER CODE BEGIN Error_Handler_Debug */
     /* User can add his own implementation to report the HAL error return state */
     __disable_irq();
     while (1)
     {
     }
     /* USER CODE END Error_Handler_Debug */
    }
    
    #ifdef USE_FULL_ASSERT
    /**
     * @brief Reports the name of the source file and the source line number
     * where the assert_param error has occurred.
     * @PAram file: pointer to the source file name
     * @PAram line: assert_param error line source number
     * @retval None
     */
    void assert_failed(uint8_t *file, uint32_t line)
    {
     /* USER CODE BEGIN 6 */
     /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
     /* USER CODE END 6 */
    }
    #endif /* USE_FULL_ASSERT */

     

    Technical Moderator
    June 11, 2025

    You need to probe what is going-on on the bus using an oscilloscope or a logic analyzer.

    You need also to refer to the sensor datasheet to know what that "8" value means!

    Try also to declare uint8_t check; global and test.

    Visitor II
    October 23, 2025

    Hello Piyoosh,

    this is Rajkumar STM32H562RGT6: ICM‑20948 & ICP201xx init() hangs only when FreeRTOS is enabled — works in bare-metal same help me solve this problem 

    Super User
    October 23, 2025

    @Devirajkumar17 wrote:

    this is Rajkumar STM32H562RGT6: ICM‑20948 & ICP201xx init() hangs only when FreeRTOS is enabled — works in bare-metal same help me solve this problem 


    You have a separate thread on this here.

    The key difference between your situation and this thread is that you are using Arduino - that's an entirely different setup!