Skip to main content
Visitor II
October 30, 2024
Solved

CMSIS-RTOS2 - I2C read/write

  • October 30, 2024
  • 1 reply
  • 1281 views

Hi
I use the HAL library and CMSIS-RTOS2

infinite loops should not be used in the thread, but I need to wait, for example, for the packet to be sent via I2C, because I need to write and read right after each other, and if I don't wait for the HAL_I2C_STATE_READY state, only writing is performed, but reading does not take place

is the solution to use osThreadYield() ?

static void Task1(void *argument)
{
	while(1)
	{
		HAL_I2C_Master_Transmit_IT(&hi2c1, I2C_addr, write_data_array,sizeof(write_data_array));
		while(hi2c1.State != HAL_I2C_STATE_READY)
		{
			osThreadYield() ;
		}
		HAL_I2C_Master_Receive_IT(&hi2c1, I2C_addr, read_data_array,sizeof(read_data_array));
		while(hi2c1.State != HAL_I2C_STATE_READY)
		{
			osThreadYield() ;
		}
	}
}

or set a semaphore(event) in the I2C interrupt handler and watch it in the thread?

osSemaphoreId_t I2C_semaphore;

void I2C1_EV_IRQHandler(void)
{
 HAL_I2C_EV_IRQHandler(&hi2c1);
 if(hi2c1.State == HAL_I2C_STATE_READY)
	 	 osSemaphoreRelease(I2C_semaphore);
}

static void Task1(void *argument)
{
	while(1)
	{
		HAL_I2C_Master_Transmit_IT(&hi2c1, I2C_addr, write_data_array,sizeof(write_data_array)); 
 osSemaphoreAcquire(I2C_semaphore, 100);
 HAL_I2C_Master_Receive_IT(&hi2c1, I2C_addr, read_data_array,sizeof(read_data_array));
 osSemaphoreAcquire(I2C_semaphore, 100);
	}
}

or not solve it, because it cannot happen that the I2C peripheral never reaches the Ready state?

static void Task1(void *argument)
{
	while(1)
	{
		HAL_I2C_Master_Transmit_IT(&hi2c1, I2C_addr, write_data_array,sizeof(write_data_array));
		while(hi2c1.State != HAL_I2C_STATE_READY);
		HAL_I2C_Master_Receive_IT(&hi2c1, I2C_addr, read_data_array,sizeof(read_data_array));
		while(hi2c1.State != HAL_I2C_STATE_READY);
	}
}

all variants work, but I'd like to get it right

 

    This topic has been closed for replies.
    Best answer by Saket_Om

    Hello @PNova.2 

    Using semaphores for synchronizing I2C operations in an RTOS environment is a more efficient and robust approach compared to using infinite loops or busy waiting. Semaphores allow the thread to block and wait for the I2C operation to complete, which is signaled by the I2C complete callback functions. This method avoids unnecessary CPU usage, ensuring that the system remains responsive and efficient. Below is an example of how to implement this approach:

    osSemaphoreId_t I2C_semaphore;
    I2C_HandleTypeDef hi2c1;
    
    void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
    {
     if(hi2c->State == HAL_I2C_STATE_READY)
     {
     osSemaphoreRelease(I2C_semaphore);
     }
    }
    
    void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
    {
     if(hi2c->State == HAL_I2C_STATE_READY)
     {
     osSemaphoreRelease(I2C_semaphore);
     }
    }
    
    static void Task1(void *argument)
    {
     while(1)
     {
     HAL_I2C_Master_Transmit_IT(&hi2c1, I2C_addr, write_data_array, sizeof(write_data_array));
     osSemaphoreAcquire(I2C_semaphore, 100);
     HAL_I2C_Master_Receive_IT(&hi2c1, I2C_addr, read_data_array, sizeof(read_data_array));
     osSemaphoreAcquire(I2C_semaphore, 100);
     }
    }
    
    int main(void)
    {
     HAL_Init();
     SystemClock_Config();
     MX_GPIO_Init();
     MX_I2C1_Init();
    
     I2C_semaphore = osSemaphoreNew(1, 0, NULL);
    
     osKernelInitialize();
     osThreadNew(Task1, NULL, NULL);
     osKernelStart();
    
     while (1)
     {
     }
    }

     

    1 reply

    Saket_OmAnswer
    Technical Moderator
    October 30, 2024

    Hello @PNova.2 

    Using semaphores for synchronizing I2C operations in an RTOS environment is a more efficient and robust approach compared to using infinite loops or busy waiting. Semaphores allow the thread to block and wait for the I2C operation to complete, which is signaled by the I2C complete callback functions. This method avoids unnecessary CPU usage, ensuring that the system remains responsive and efficient. Below is an example of how to implement this approach:

    osSemaphoreId_t I2C_semaphore;
    I2C_HandleTypeDef hi2c1;
    
    void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
    {
     if(hi2c->State == HAL_I2C_STATE_READY)
     {
     osSemaphoreRelease(I2C_semaphore);
     }
    }
    
    void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
    {
     if(hi2c->State == HAL_I2C_STATE_READY)
     {
     osSemaphoreRelease(I2C_semaphore);
     }
    }
    
    static void Task1(void *argument)
    {
     while(1)
     {
     HAL_I2C_Master_Transmit_IT(&hi2c1, I2C_addr, write_data_array, sizeof(write_data_array));
     osSemaphoreAcquire(I2C_semaphore, 100);
     HAL_I2C_Master_Receive_IT(&hi2c1, I2C_addr, read_data_array, sizeof(read_data_array));
     osSemaphoreAcquire(I2C_semaphore, 100);
     }
    }
    
    int main(void)
    {
     HAL_Init();
     SystemClock_Config();
     MX_GPIO_Init();
     MX_I2C1_Init();
    
     I2C_semaphore = osSemaphoreNew(1, 0, NULL);
    
     osKernelInitialize();
     osThreadNew(Task1, NULL, NULL);
     osKernelStart();
    
     while (1)
     {
     }
    }

     

    PNova.2Author
    Visitor II
    October 30, 2024

    Thanks for the explanation. I wasn't sure and I want to use the most efficient and secure code.