cancel
Showing results for 
Search instead for 
Did you mean: 

Grouping sensors connected to the same ADC and schedule them at different rate in FreeRTOS.

ubaldot
Senior

Say that I have the following set of sensors: s1,s2,s3, s4, s5 and s6.

I want the set (s1,s2,s3) to be scheduled at 100ms, s4 every 200ms and the set (s5,s6) every second. 

My gut feeling suggests me to create three periodic tasks task1, task2 and task3 that calls `sensor_set1()`, `sensor_set2()` and `sensor_set3()`, respectively.

The problem here is that all the sensors are connected in the same ADC, and therefore, at the beginning of each function call I should re-configure the ADC.

My idea is to do something like the following but I don't know if it is correct or not. Any help? :)

sensor_set1(){
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 3;

  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

  sConfig.Channel = ADC_CHANNEL_2;
  sConfig.Rank = 2;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = 3;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

   HAL_ADC_Start_DMA(&hadc1, &analog_readSet1, 3);
   xSemaphoreTake(xSemaphoreADC_PV, portMAX_DELAY); // Wait for ADC EOC
   HAL_ADC_Stop_DMA(&hadc1);
}

sensor_set2(){
  hadc1.Init.ScanConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;

  sConfig.Channel = ADC_CHANNEL_4;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

   HAL_ADC_Start_DMA(&hadc1, &analog_readSet2, 1);
   xSemaphoreTake(xSemaphoreADC_PV, portMAX_DELAY); // Wait for ADC EOC
   HAL_ADC_Stop_DMA(&hadc1);
}

sensor_set3(){
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 2;

  sConfig.Channel = ADC_CHANNEL_5;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig

  sConfig.Channel = ADC_CHANNEL_6;
  sConfig.Rank = 2;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);

   HAL_ADC_Start_DMA(&hadc1, &analog_readSet3, 2);
   xSemaphoreTake(xSemaphoreADC_PV, portMAX_DELAY); // Wait for ADC EOC
   HAL_ADC_Stop_DMA(&hadc1);
}

 

5 REPLIES 5
TDK
Guru

Convert all 6 channels every 100ms and ignore the result of channels that don't need captured that quickly. Read every other result on s4 and every 10th result on s5, s6.

(Changing hadc1.Init without re-initializing the peripheral will not have any effect.)

> ADC_SAMPLETIME_3CYCLES

For the sake of accuracy, this could be much higher.

If you feel a post has answered your question, please click "Accept as Solution".

Or, a slight variation on that, have a single task that's called every 100ms

The Task always does s1,s2,s3, and maintains a count so that it knows when to also do the others ...

Ok, I was also thinking about that solution but it seemed a sort of "waste" as you throw away measurements. 

Also,  although for this specific use case things will work, in case the ratio of all couple of sampling periods is not an integer, then we may need to round the sampling interval. For example, is set1 is sampled at 130ms, set2 at 275ms and set3 at 830ms, then things becomes tricky. Could this be a use case to deinit/init the ADC peripheral? Or is it still better to sample all the sensors with the fastest period anyway and throw away the measurements with longer periods requirement? 


@ubaldot wrote:

 it seemed a sort of "waste" as you throw away measurements. 


What, exactly, do you feel you are "wasting" by doing that?

Is it any more "wasteful" than the waste of constantly re-configuring the ADC?

Anyhow, my variation on @TDK 's suggestion addresses that.

 


@ubaldot wrote:

in case the ratio of all couple of sampling periods is not an integer,  


Then find a basic "tick" time that does work, and have my suggestion work off that "tick" and do whichever sensor(s) it needs ...


What, exactly, do you feel you are "wasting" by doing that?

Is it any more "wasteful" than the waste of constantly re-configuring the ADC?

I feel that I am wasting resources to read values that I will never use. 

That is actually what I wanted to figure out: what is larger waste? Throwing away measurements of re-configuring the ADC?