Comparado com o TaskSwitcher, no entanto, os RTOSes possuem algoritmos muito mais complexos, além de outras funcionalidades. Nesta disciplina, utilizaremos o FreeRTOS, que possui código aberto e é uma alternativa bastante popular.
7.1 Instalação do FreeRTOS
No Arduino, a instalação do FreeRTOS é muito fácil, podendo ser obtido diretamente no repositório de biblioteca.
Infelizmente, o Tinkercad suporta apenas uma quantidade limitada de bibliotecas, o que não inclui o FreeRTOS. Desse modo, para realizarmos o estudo do FreeRTOS, vamos utilizar o port do FreeRTOS para desktop (Windows, Linux e MacOS). Nesta apostila, focaremos na versão Windows com MinGW, mas o procedimento para os outros SOs não é muito diferente.
Sendo assim, antes de iniciar a instalação, verifique se o MinGW está instalado. Caso não esteja, siga os passos da apostila de C. Outra opção para executar os códigos deste e dos próximos capítulos é rodar no Google Colab a partir do notebook disponibilizado na página da disciplina. Note que o processo de instalação no Linux/MacOS é semelhante ao empregado no Google Colab.
7.2 Obtendo o código fonte
O modo padrão de utilização do FreeRTOS é incluir os arquivos fonte (.c
e .h
) diretamente no projeto da nossa aplicação.
Então, o primeiro passo consiste em obter o código fonte do FreeRTOS, que é disponibilizado no repositório:
https://github.com/FreeRTOS/FreeRTOS
Para não baixar todos os submódulos (o que implicaria em quase 1GB de código), vamos clonar apenas o kernel, que basicamente é o programa núcleo de um sistema operacional:
$ git clone https://github.com/FreeRTOS/FreeRTOS-Kernel.git
7.3 Criando um projeto novo: copiando os arquivos do código fonte
Crie uma pasta nova para o seu projeto novo, que pode chamar freertos-tutorial
com o comando
$ mkdir freertos-tutorial
Agora vamos copiar os arquivos .c
necessários com o comando:
$ cp ./FreeRTOS-Kernel/tasks.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/queue.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/list.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/timers.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/event_groups.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/portable/MSVC-MingW/*.c ./freertos-tutorial
$ cp ./FreeRTOS-Kernel/portable/MemMang/heap_4.c ./freertos-tutorial
Agora vamos copiar os headers:
$ mkdir freertos-tutorial/include
$ cp ./FreeRTOS-Kernel/include/*.* ./freertos-tutorial/include
$ cp ./FreeRTOS-Kernel/portable/MSVC-MingW/*.h ./freertos-tutorial
Se preferir, pode copiar manualmente os arquivos ao invés de utilizar os comandos acima. No final do processo, a sua estrutura de diretórios deve ser:
📦freertos-tutorial
┣ 📂include
┃ ┣ 📜atomic.h
┃ ┣ 📜croutine.h
┃ ┣ 📜deprecated_definitions.h
┃ ┣ 📜event_groups.h
┃ ┣ 📜FreeRTOS.h
┃ ┣ 📜list.h
┃ ┣ 📜message_buffer.h
┃ ┣ 📜mpu_prototypes.h
┃ ┣ 📜mpu_wrappers.h
┃ ┣ 📜portable.h
┃ ┣ 📜projdefs.h
┃ ┣ 📜queue.h
┃ ┣ 📜semphr.h
┃ ┣ 📜StackMacros.h
┃ ┣ 📜stack_macros.h
┃ ┣ 📜stdint.readme
┃ ┣ 📜stream_buffer.h
┃ ┣ 📜task.h
┃ ┗ 📜timers.h
┣ 📜event_groups.c
┣ 📜heap_4.c
┣ 📜list.c
┣ 📜port.c
┣ 📜portmacro.h
┣ 📜queue.c
┣ 📜tasks.c
┗ 📜timers.c
O procedimento acima expande as instruções dadas no tutorial do FreeRTOS disponível no site oficial em
https://www.freertos.org/Documentation/RTOS_book.html
7.4 Criando um projeto novo: criando o arquivo de configuração FreeRTOSConfig.h
O arquivo FreeRTOSConfig.h
permite personalizar o FreeRTOS para sua aplicação, por meio de várias configurações, incluindo as do escalonador.
Para os exercícios desta apostila, uma configuração padrão pode ser utilizada.
Crie o arquivo freertos-tutorial/FreeRTOSConfig.h
com o seguinte conteúdo:
/*
* FreeRTOS V202104.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. See
* http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 70 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the win32 thread. */
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 65 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 12 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_RECURSIVE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 20
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_ALTERNATIVE_API 0
#define configUSE_QUEUE_SETS 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configSUPPORT_STATIC_ALLOCATION 0
/* Software timer related configuration options. The maximum possible task
* priority is configMAX_PRIORITIES - 1. The priority of the timer task is
* deliberately set higher to ensure it is correctly capped back to
* configMAX_PRIORITIES - 1. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 20
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
#define configMAX_PRIORITIES ( 7 )
/* Run time stats gathering configuration options. */
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initialises the run time counter. */
#define configGENERATE_RUN_TIME_STATS 0
/* Co-routine related configuration options. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* This demo can use of one or more example stats formatting functions. These
* format the raw data provided by the uxTaskGetSystemState() function in to human
* readable ASCII form. See the notes in the implementation of vTaskList() within
* FreeRTOS/Source/tasks.c for limitations. */
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Enables the test whereby a stack larger than the total heap size is
* requested. */
#define configSTACK_DEPTH_TYPE uint32_t
/* Set the following definitions to 1 to include the API function, or zero
* to exclude the API function. In most cases the linker will remove unused
* functions anyway. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_uxTaskGetStackHighWaterMark2 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskAbortDelay 1
#endif /* FREERTOS_CONFIG_H */
Detalhes sobre as opções de configuração podem ser encontradas na documentação oficial em
https://www.freertos.org/Documentation/RTOS_book.html
7.5 Criando um projeto novo: finalizando a aplicação "Hello World"
O nosso projeto está quase pronto, falta apenas o código principal do nosso programa.
Para inseri-lo, crie o arquivo freertos-tutorial/main.c
com o conteúdo
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
/*** SEE THE COMMENTS AT THE TOP OF THIS FILE ***/
int main( void )
{
/* Perform any hardware setup necessary. (Not necessary for Desktop) */
/* prvSetupHardware(); */
/* --- APPLICATION TASKS CAN BE CREATED HERE --- */
/* Start the created tasks running. */
vTaskStartScheduler();
/* Execution will only reach here if there was insufficient heap to
start the scheduler. */
for( ;; );
return 0;
}
/*-----------------------------------------------------------*/
Estamos pronto para compilar!
Primeiro, vamos fazer esse processo manualmente, compilando os arquivos .c
um de cada vez para gerar os arquivos objetos .o
.
Para tal, execute os comandos:
$ cd freertos-tutorial
$ gcc -Wall -I. -I./include -c main.c -o main.o
$ gcc -Wall -I. -I./include -c tasks.c -o tasks.o
$ gcc -Wall -I. -I./include -c queue.c -o queue.o
$ gcc -Wall -I. -I./include -c list.c -o list.o
$ gcc -Wall -I. -I./include -c timers.c -o timers.o
$ gcc -Wall -I. -I./include -c event_groups.c -o event_groups.o
$ gcc -Wall -I. -I./include -c heap_4.c -o heap_4.o
$ gcc -Wall -I. -I./include -c port.c -o port.o
Agora vamos executar o linker para gerar o executável. A entrada do linker deve ser feita em todos os arquivos objetos, então o comando é
$ gcc main.o tasks.o queue.o list.o timers.o event_groups.o heap_4.o port.o -lWinmm -o freertos-tutorial.exe
Se não ocorreu nenhum erro de compilação ou linker, a sua instalação deve estar correta! Você pode tentar executar a aplicação com:
$ .\freertos-tutorial.exe
Mas nada deve ocorrer, pois nossa aplicação fica em laço infinito. Caso queira observar um programa de verdade em execução, copie um dos códigos do próximo capítulo, compile e execute.
7.6 Criando um projeto novo: automatizando a construção com Makefile (opcional)
O processo de construção do executável feito na seção anterior é bastante trabalhoso. Imagine que toda vez que modificar algum arquivo é preciso repetir o processo, pelo menos parcialmente. Para facilitar o desenvolvimento, vamos utilizar o sistema de build Makefiles, como feito na Apostila de C, na seção 9.1.
Para tal, primeiro apague todos os arquivos de saída da compilação com o comando:
No powershell:
$ rm *.o, *.
Ou, no prompt de comando:
$ del *.o *.exe
Depois, crie o arquivo freertos-tutorial/Makefile
com o conteúdo
# Compilador
CC := gcc
# Nome do executavel
TARGET = freertos-tutorial.exe
# Arquivos fonte .c
SOURCES = main.c \
tasks.c \
queue.c \
list.c \
timers.c \
event_groups.c \
heap_4.c \
port.c \
# Diretorios de busca para #include
INCLUDE_DIRS := -I.
INCLUDE_DIRS += -I./include
# Flags para a compilacao (geracao dos arquivos .o)
CFLAGS := -Wall
# Flags para o linker (.o's para executavel)
LDFLAGS := -lWinmm
OBJS = $(SOURCES:.c=.o)
.PHONY: build
build: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
%.o : %.c
$(CC) $(CFLAGS) $(INCLUDE_DIRS) -c $< -o $@
.PHONY: clean
clean:
del $(OBJS) $(TARGET)
# For non Windows users:
# rm -f $(OBJS) $(TARGET)
Com isso, para construir o seu projeto com o make
, execute:
$ mingw32-make build
Que deve imprimir as seguintes mensagens:
gcc -Wall -I. -I./include -c main.c -o main.o
gcc -Wall -I. -I./include -c tasks.c -o tasks.o
gcc -Wall -I. -I./include -c queue.c -o queue.o
gcc -Wall -I. -I./include -c list.c -o list.o
gcc -Wall -I. -I./include -c timers.c -o timers.o
gcc -Wall -I. -I./include -c event_groups.c -o event_groups.o
gcc -Wall -I. -I./include -c heap_4.c -o heap_4.o
gcc -Wall -I. -I./include -c port.c -o port.o
gcc main.o tasks.o queue.o list.o timers.o event_groups.o heap_4.o port.o -lWinmm -o freertos-tutorial.exe
e gerar o executável freertos-tutorial/freertos-tutorial.exe
.
Note que os comandos foram os mesmos executados na seção anterior. Uma vantagem de utilizar um sistema de build é que, ao modificar um arquivo, o make detecta automaticamente qual(is) arquivo(s) precisa(m) ser recompilado(s).
Por fim, é possível remover todos os arquivos do build com o comando:
$ mingw32-make clean
Bibliografia para este capítulo
- Tutorial e referência do FreeRTOS: https://www.freertos.org/Documentation/RTOS_book.html
- Tutorial Makefile: https://makefiletutorial.com/