Help in choosing an algorithm of actions

I need help in solving my problem more correctly.)
I want to transfer my project (based on STM32) to RTOS
The dilemma is that I have a function that controls outputs port at a certain time interval such as period, number of repetitions, time interval between repetitions.
The function measures the time interval of the STM32 internal timer and in accordance with this, controls the outputs, so the function itself is constantly polled in the main loop.
Now, instead of one main loop, I will have tasks and first of all I thought about creating a task that would poll a function (or several functions for different ports) every ms, but as far as I understand, 1 ms is not enough and It is recommended to set more time.
I’m new to RTOS, please advise what is the best way to proceed?

Your first issue is that you are describing this action as POLLING, which means the only way you know the action happened is to read an I/O to see that it happened. Polling is BAD in an RTOS environment. Instead, you want the action to create an interrupt when it happens, and then put the immediate response needed in an ISR, and perhaps the ISR could trigger a task to handle slower responses to that event.

I understand what you mean, but I don’t understand how to do it)
My function is related to a one timer that just ticks.
Perhaps I should have explained the functionality of my function better.
For example, I need to flash the LED five times with a period of 500ms and a pause of 1 minute and again.
I can’t do this kind of functionality simply on one RTOS software timer.
And in order to understand how much time has passed, I need to record the time in a variable and compare it with the time of the timer ticks.
I can create such functions for example at 10 different time intervals.
How do I inform the interrupt that the period time or interval time between periods has passed?
just constantly compare the value of the variable with the current value of the timer ticks.

That can easily be done with FreeRTOS timers, or a task.

A task can delay for a specified time with vTaskDelay (or vTaskDelayUntil to delay from a time from the last time it was started to avoid slippage).

The Timer function which calls back to a function, can have its period changed.

There is a macro pdMS_TO_TICKS that will convert a time period in milliseconds to the same period expressed in tick (in case you aren’t running at a 1000kHz tick rate, which you normally are not).

So, if you are only doing things at human scale times, using software timers for simple operations and tasks (using delays) works fine. You don’t try to schedule at an absolute time mark, but a relative time mark.

@peit Please take a look at the documentation for vTaskDelay and xTaskCheckForTimeOut which together should allow you to do what you are asking.

For example, the following task code would blink an led every 500 ms or so:

void vMyTask(void * pvParameters)
{
    vLedOn();
    vTaskDelay(pdMS_TO_TICKS(500));
    vLedOff();
    vTaskDelay(pdMS_TO_TICKS(500));
}

For a little more precision, you could use xTaskCheckForTimeOut to account for the time spent calling vLedOn and vLedOff.

This code only implements on and off, but if I need the number of repetitions or dynamically change the period and repetition values, I need to augment the task with a queue, and if I need to manage 10 ports, create 10 tasks? (this will lead to code duplication)…

I sincerely don’t understand why you can’t get by with one function that is polled once every 10ms (for example), this function is not blocking

if I need to manage different periods of 10 different ports, do I need to create 10 tasks (or tamers) ?)
This is a very memory-intensive operation

I apologize, maybe I can’t understand something or maybe I misinterpreted the functionality I needed…

If all intervals are a multiple of 10ms, then you could use a 10ms repeat period (either a task or a timer) and in that decide to do what is needed.

Note, multiple tasks can use the same code, they might take a different data pointer as their startup parameter.

Following your recommendations, I will try to solve my problem.
Since I am new to RTOS, in real projects (in practice) there may be 30-40 tasks (it is not necessary that all of them are constantly executed) or is this from the world of fantasy?)

Tasks should be programmed to BLOCK when they don’t have something to do, which means that while the task exists, and is using memory, it isn’t running and loading the CPU.

Yes, it is possible (on a larger microprocessor) to have 30-40 task configured, I find I normally don’t need that many. Remember, some simple things, like you light blinking, might not need to be full tasks, but function tied to timers.

Thanks for the answer)

Say that you want to flash an LED for 100 ms, wait 100 ms, flash for 200 ms, wait 100 ms, and so on, then repeat the sequence.
One way is to simply hard code the sequence:

LED ON
vTaskDelay(100);
LED OFF
vTaskDelay(100)
LED ON
vTaskDelay(200)
LED OFF
// etc.

another way would be to determine the minimum time for on and off, say it’s 100 msec.
then create a constant, say 32 or 64 bits as desired. 10110…
Read the constant from the beginning:
if the bit is 1, LED on, delay 100 ms
if the bit is 0, LED off, delay 100 ms.
This allows any pattern desired, for as long as you feed it bits in the variable.
if you want, a queue could feed the variable to the routine. If no new data on the queue, repeat the last.
The LED routine is a task:
either read a constant in memory, control the LED, and just keep on going…
you would need a semaphore to tell an external routine when it can update the sequence bits
or use a queue as described above.

And another way is to have an array of times for how long you delay for at each step (and put a 0 at the end, since 0 isn’t a valid delay)

With an array of times, you might find it difficult to put it on a queue, but you’d have variable times (per entry on a queue)
With a pattern, you’re looking more at patterns, of fixed lengths, and fixed intervals.
Either works, but it depends on what you really want.
I use it to do LED flashing with a task for that LED. (pin driven, on/off)

But you can pass the address of the list (or an ID number)

True enough. That works without a problem when the data is a constant in Flash. If it is not (a general case), then you must maintain separate storage and unassign that storage when the queue delivers and the message is handled.

Do you know of a nicer way to do this?

You could use a MessageBuffer to send the variable length array.

Do you mean to put the time value into the array?

Yes, you can do that, but I think it’s not the best option…