How to manage tasks to manage I2C communication and the generation of a PWM signal

josantoniojl wrote on Tuesday, February 19, 2019:

Hello,

This is my first time using FREERTOS, the project I’m doing is the information retrieval of the LIS3DH sensor (i2c) and the control of 3 servomotors. The program is working correctly on while cycle. However I have to use the FREERTOS system for task management. I don’t know which is the best way to create tasks. What should i do?

  1. Generate a task that performs everything I have programmed
  2. Generate an i2c task and another PWM task
  3. Generate a time interruption that manages a semaphore and at the same time i2c communication.

Is there an example of creating an i2c task on the STM32 nucleo card?

rtel wrote on Wednesday, February 20, 2019:

You question is a bit open to be able to give a definitive suggestion,
but basically have two options (this is really oversimplifying):

  1. If you are not sending or receiving much data, and the task that does
    the sending and receiving is a low priority (so not starving more
    important tasks while the I2C transactions are in progress), then you
    can just use ST’s polling I2C driver inline in whichever function needs
    to do the I2C reads.

  2. If you need higher throughput, or your application can’t be blocked
    while I2C transactions are in progress, then have the task start an I2C
    transaction then block on something like a direct to task notification
    (which means the task is not using and CPU time and other tasks can run)
    until either an interrupt controller or DMA controlled I2C operation
    completes - then when the operation is complete, unblock the task that
    was waiting for it. This is more complex, but I think ST have callbacks
    in their drivers that would allow you to do this.

Then of course there are alternatives that are neither fully polling or
fully blocking…

richarddamon wrote on Wednesday, February 20, 2019:

Number 1 may be a reasonable starting point, create a task which just has all your existing working code, and put it in as a low priority task, initially not using much in the way of FreeRTOS and then you can incrementally improve things as you go. It is not the way you want to end up, in particular you want to get rid of as many ‘busy wait loops’ as possible out of the code.

As to Number 2, I find that making a task to handle I2C isn’t the best division. I tend to make a task for each thing that waits for some asyncronous input or that is on a distint timing interval. Being an I2C master, you don’t need to make that a seperate task as everything happens in a basically syncronous manner. It may well make sense to have a task that reads from the I2C sensor at some rate and leaves/sends the data for some other task(s) to use.

josantoniojl wrote on Wednesday, February 20, 2019:

Hi,
I performed two tasks, one for obtaining values and the second for the control of servomotors, that works perfectly. The priority level of the i2c task is high while that of the motors is above normal.

However, I don’t know if they have a recommendation for you to perform better task management. I was thinking about using a semaphore but I’m not sure how to use it.


void I2Communication(void const * argument)
{
  /* USER CODE BEGIN I2Communication */	

  /* Infinite loop */
  for(;;)
  {
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x28, 1,(uint8_t *)OUT_X_L, 1, 100); 
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x29, 1,(uint8_t *)OUT_X_H, 1, 100); 
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x2A, 1,(uint8_t *)OUT_Y_L, 1, 100); 
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x2B, 1,(uint8_t *)OUT_Y_H, 1, 100); 
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x2C, 1,(uint8_t *)OUT_Z_L, 1, 100); 
		HAL_I2C_Mem_Read (&hi2c1, SLAVEI2C_ADD,0x2D, 1,(uint8_t *)OUT_Z_H, 1, 100); // Registre OUT_Z_H
		x = ((OUT_X_H[0]<<8)|OUT_X_L[0]);
		y = ((OUT_Y_H[0]<<8)|OUT_Y_L[0]);
		z = ((OUT_Z_H[0]<<8)|OUT_Z_L[0]);
    osDelay(500);
  }
  /* USER CODE END I2Communication */
}

void PWMControl(void const * argument)
{
  /* USER CODE BEGIN PWMControl */
  /* Infinite loop */
  for(;;)
  {
		TIM2->CCR1=x;
		TIM2->CCR2=y;
		TIM2->CCR4=z;
		osDelay(500);
  }
  /* USER CODE END PWMControl */
}