cancel
Showing results for 
Search instead for 
Did you mean: 

CMSIS-RTOS2 - I2C read/write

PNova.2
Associate II

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

 

1 ACCEPTED SOLUTION

Accepted Solutions
Saket_Om
ST Employee

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)
    {
    }
}

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

View solution in original post

2 REPLIES 2
Saket_Om
ST Employee

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)
    {
    }
}

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

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