

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Princípios básicos do kernel do FreeRTOS
<a name="dev-guide-freertos-kernel"></a>

O kernel do FreeRTOS é um sistema operacional em tempo real compatível com inúmeras arquiteturas. Seus fundamentos são ideais para a criação de aplicativos de microcontroladores incorporados. Ele fornece:
+ Um programador multitarefa.
+ Várias opções de alocação de memória (inclusive a possibilidade de criar sistemas totalmente alocados estaticamente). 
+ Primitivos de coordenação entre tarefas, inclusive notificações de tarefas, filas de mensagens, vários tipos de semáforos e buffers de fluxo e de mensagens.
+ Compatibilidade com o multiprocessamento simétrico (SMP) em microcontroladores de vários núcleos.

O kernel do FreeRTOS nunca realiza operações não determinísticas, como percorrer uma lista vinculada, dentro de uma seção crítica ou interrupção. O kernel do FreeRTOS inclui uma implementação de temporizador de software eficiente que não usa nenhum tempo de CPU, a menos que um temporizador precise de manutenção. Tarefas bloqueadas não exigem manutenção periódica e demorada. Notificações diretas para tarefas permitem a sinalização rápida de tarefas, praticamente sem sobrecarga de RAM. Elas podem ser usadas na maioria dos cenários de sinalização entre tarefas e de interrupção para tarefa.

O kernel do FreeRTOS foi projetado para ser pequeno, simples e fácil de usar. Uma imagem binária típica do kernel do RTOS está no intervalo de 4.000 a 9.000 bytes.

Para obter a documentação mais atualizada sobre o kernel FreeRTOS, consulte [FreeRTOS.org](https://freertos.org/). O site FreeRTOS.org oferece diversos tutoriais e guias detalhados sobre o uso do kernel FreeRTOS, incluindo um [Guia de início rápido do kernel do FreeRTOS](https://freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/02-Quick-start-guide) e uma [implementação mais aprofundada do RTOS](https://freertos.org/Documentation/02-Kernel/05-RTOS-implementation-tutorial/01-RTOS-implementation) na *Documentação do FreeRTOS*.

# O programador de kernel do FreeRTOS
<a name="freertos-kernel-scheduler"></a>

Uma aplicação incorporada que usa um RTOS pode ser estruturada como um conjunto de tarefas independentes. Cada tarefa é executada em seu próprio contexto, sem dependência de outras tarefas. Somente uma tarefa na aplicação será executada a qualquer momento. O programador do RTOS em tempo real determina quando cada tarefa deve ser executada. Cada tarefa é fornecida com a própria pilha. Quando uma tarefa é trocada para que outra possa ser executada, o contexto de execução da tarefa é salvo na pilha de tarefas para que ele possa ser restaurado quando a mesma tarefa for trocada de novo posteriormente para retomar sua execução. 

Para fornecer um comportamento determinístico em tempo real, o programador de tarefas do FreeRTOS permite que as tarefas recebam prioridades estritas. O RTOS garante que a tarefa de maior prioridade que pode ser executada receba o tempo de processamento. Isso requer o compartilhamento do tempo de processamento entre tarefas de igual prioridade, se elas estiverem prontas para serem executadas simultaneamente. O FreeRTOS também cria uma tarefa inativa que é executada somente quando nenhuma outra tarefa está pronta para ser executada.

# Alocação de memória do kernel
<a name="kernel-memory-allocation"></a>

O kernel do RTOS precisa de memória RAM toda vez que uma tarefa, fila ou outro objeto do RTOS é criado. A memória RAM pode ser alocada:
+ Estaticamente no momento da compilação.
+ Dinamicamente a partir do heap do RTOS pelas funções de criação de objeto da API do RTOS.

Quando os objetos do RTOS são criados dinamicamente, o uso da biblioteca `malloc()` e das funções C `free()` padrão nem sempre é apropriado por diversos motivos:
+ Elas podem não estar disponíveis em sistemas incorporados.
+ Elas ocupam um espaço de código valioso.
+ Normalmente, elas não são seguras para o thread.
+ Elas não são deterministas.

Por esses motivos, o FreeRTOS mantém a API de alocação de memória em seu nível portátil. A camada portátil está fora dos arquivos de origem que implementam a funcionalidade principal do RTOS, para que você possa fornecer uma implementação específica da aplicação apropriada para o sistema em tempo real que você está desenvolvendo. Quando o kernel do RTOS exige RAM, ele chama `pvPortMalloc()` em vez de `malloc()`. Quando a memória RAM está sendo liberada, o kernel do RTOS chama `vPortFree()` em vez de `free()`.

# Gerenciar memória do aplicativo
<a name="application-memory-management"></a>

Quando as aplicações precisam de memória, elas podem alocá-la do heap do FreeRTOS. O FreeRTOS oferece vários esquemas de gerenciamento de heap que variam em termos de complexidade e recursos. Você também pode fornecer sua própria implementação de heap.

O kernel do FreeRTOS inclui cinco implementações de heap:

**`heap_1`**  
É a implementação mais simples. Não permite que a memória seja liberada.

**`heap_2`**  
Permite que a memória seja liberada, mas não une blocos livres adjacentes.

**`heap_3`**  
Encapsula o `malloc()` e o `free()` padrão para segurança de threads.

**`heap_4`**  
Une blocos livres adjacentes para evitar a fragmentação. Inclui uma opção de posicionamento de endereço absoluto.

**`heap_5`**  
É semelhante a heap\$14. Pode abranger o heap em várias áreas de memória não adjacentes.

# Coordenação entre tarefas
<a name="inter-task-coordination"></a>

Esta seção contém informações sobre primitivos do FreeRTOS.

**Topics**
+ [Filas](#inter-task-queues)
+ [Semáforos e mutexes](#inter-task-semaphones)
+ [Notificações diretas para tarefas](#direct-task-notifications)
+ [Buffers de fluxo](#rtos-stream-buffer)
+ [Buffers de mensagens](#rtos-message-buffer)

## Filas
<a name="inter-task-queues"></a>

As filas são a principal forma de comunicação entre tarefas. Elas podem ser usadas para enviar mensagens entre tarefas e entre interrupções e tarefas. Na maioria dos casos, elas são usadas como buffers FIFO (primeiro a entrar, primeiro a sair) seguros para threads com novos dados sendo enviados para o final da fila. (Os dados também podem ser enviados para a frente da fila.) As mensagens são enviadas por meio de filas por cópia, o que significa que os dados (que podem ser um ponteiro para buffers maiores) são copiados na fila, em vez de simplesmente armazenar uma referência aos dados.

As APIs de fila permitem que um tempo de bloqueio seja especificado. Quando uma tarefa tenta ler a partir de uma fila vazia, a tarefa é colocada no estado Bloqueada até que os dados se tornem disponíveis na fila ou que o tempo de bloqueio termine. As tarefas no estado Bloqueadas não consomem nenhum tempo de CPU, permitindo que outras tarefas sejam executadas. Da mesma forma, quando uma tarefa tenta gravar em uma fila cheia, a tarefa é colocada no estado Bloqueada até que o espaço seja disponibilizado na fila ou o tempo de bloqueio termine. Se mais de uma tarefa bloquear na mesma fila, a tarefa com a prioridade mais alta será desbloqueada primeiro. 

Outros primitivos do FreeRTOS, como notificações diretas para tarefas e buffers de fluxo e de mensagens, oferecem alternativas leves para filas em muitos cenários de projeto comuns. 

## Semáforos e mutexes
<a name="inter-task-semaphones"></a>

O kernel do FreeRTOS fornece semáforos binários, semáforos de contagem e mutexes para fins de sincronização e exclusão mútua.

Semáforos binários só podem ter dois valores. Eles são uma boa opção para implementar a sincronização (entre tarefas ou entre tarefas e uma interrupção). Os semáforos de contagem podem usar mais de dois valores. Eles permitem que muitas tarefas compartilhem recursos ou executem operações de sincronização mais complexas.

Mutexes são semáforos binários que incluem um mecanismo de herança de prioridade. Isso significa que, se uma tarefa de alta prioridade for bloqueada ao tentar obter um mutex que esteja retido no momento por uma tarefa de prioridade mais baixa, a prioridade da tarefa que contém o token é temporariamente aumentada para o nível da tarefa de bloqueio. Esse mecanismo é projetado para garantir que a tarefa de prioridade mais alta seja mantida no estado Bloqueada pelo menor tempo possível, para minimizar a inversão de prioridade que ocorreu.

## Notificações diretas para tarefas
<a name="direct-task-notifications"></a>

As notificações de tarefas permitem que as tarefas interajam com outras tarefas e sincronizem com rotinas de serviço de interrupção (ISRs), sem a necessidade de um objeto de comunicação separado, como um semáforo. Cada tarefa do RTOS possui um valor de notificação de 32 bits que é usado para armazenar o conteúdo da notificação, se houver. Uma notificação de tarefa do RTOS é um evento enviado diretamente a uma tarefa que pode desbloquear a tarefa de recebimento e, opcionalmente, atualizar o valor de notificação da tarefa de recebimento.

As notificações de tarefas do RTOS podem ser usadas como uma alternativa mais rápida e leve aos semáforos binários e de contagem e, em alguns casos, às filas. Notificações de tarefas têm vantagens de velocidade e espaço de RAM em relação a outros recursos do FreeRTOS que podem ser usados para executar funcionalidades equivalentes. No entanto, as notificações de tarefas só podem ser usadas quando houver apenas uma tarefa que possa ser o destinatário do evento.

## Buffers de fluxo
<a name="rtos-stream-buffer"></a>

Os buffers de fluxo permitem que um fluxo de bytes seja transmitido de uma rotina de serviço de interrupção para uma tarefa ou de uma tarefa para outra. Um fluxo de bytes pode ser de tamanho arbitrário e não tem necessariamente um começo ou um fim. Qualquer número de bytes pode ser gravado de uma só vez e lido ao mesmo tempo. Você ativa a funcionalidade de buffer de fluxo incluindo o arquivo de origem `stream_buffer.c` em seu projeto.

Os buffers de fluxo presumem que há apenas uma tarefa ou interrupção que grava no buffer (o gravador) e apenas uma tarefa ou interrupção que lê a partir do buffer (o leitor). É seguro que o gravador e o leitor sejam tarefas ou rotinas de serviço de interrupção diferentes, mas não é seguro ter vários gravadores ou leitores.

A implementação do buffer de fluxo usa as notificações diretas para tarefas. Portanto, chamar uma API de buffer de fluxo que coloca a tarefa de chamada no estado Bloqueada pode alterar o estado e o valor de notificação da tarefa de chamada.

### Envio de dados
<a name="rtos-stream-buffer-send"></a>

`xStreamBufferSend()` é usado para enviar dados a um buffer de fluxo em uma tarefa. `xStreamBufferSendFromISR()` é usado para enviar dados a um buffer de fluxo em uma rotina de serviço de interrupção (ISR).

`xStreamBufferSend()` permite que um tempo de bloqueio seja especificado. Se `xStreamBufferSend()` for chamado com um tempo de bloqueio diferente de zero para gravar em um buffer de fluxo e o buffer estiver cheio, a tarefa será colocada no estado Bloqueada até que o espaço seja disponibilizado ou o tempo de bloqueio expire.

`sbSEND_COMPLETED()` e `sbSEND_COMPLETED_FROM_ISR()` são macros que são chamadas (internamente pela API do FreeRTOS) quando os dados são gravados em um buffer de fluxo. É utilizado o identificador do buffer de fluxo que foi atualizado. As duas macros verificam se há uma tarefa bloqueada no buffer de fluxo aguardando dados e, se esse for o caso, removem a tarefa do estado Bloqueada.

Você pode alterar esse comportamento padrão fornecendo sua própria implementação de `sbSEND_COMPLETED()` em [`FreeRTOSConfig.h`](freertos-config.md) Isso é útil quando um buffer de fluxo é usado para transmitir dados entre núcleos em um processador de vários núcleos. Nesse cenário, `sbSEND_COMPLETED()` pode ser implementado para gerar uma interrupção no outro núcleo da CPU, em seguida, a rotina de serviço da interrupção poderá usar a API `xStreamBufferSendCompletedFromISR()` para verificar e, se necessário, desbloquear uma tarefa que esteja aguardando os dados.

### Recebimento de dados
<a name="rtos-stream-buffer-receive"></a>

`xStreamBufferReceive()` é usado para ler dados de um buffer de fluxo em uma tarefa. `xStreamBufferReceiveFromISR()` é usado para ler dados de um buffer de fluxo em uma rotina de serviço de interrupção (ISR).

`xStreamBufferReceive()` permite que um tempo de bloqueio seja especificado. Se `xStreamBufferReceive()` for chamado com um tempo de bloqueio diferente de zero para ler de um buffer de fluxo e o buffer estiver vazio, a tarefa será colocada no estado Bloqueada até que uma quantidade especificada de dados seja disponibilizada no buffer de fluxo ou o tempo de bloqueio expire.

A quantidade de dados que deve estar no buffer de fluxo antes de uma tarefa ser desbloqueada é chamada de nível de ativação do buffer de fluxo. Uma tarefa bloqueada com um nível de ativação de 10 é desbloqueada quando pelo menos 10 bytes são gravados no buffer ou o tempo de bloqueio da tarefa expira. Se o tempo de bloqueio de uma tarefa de leitura expirar antes do nível de ativação ser atingido, a tarefa receberá todos os dados gravados no buffer. O nível de ativação de uma tarefa deve ser definido para um valor entre 1 e o tamanho do buffer de fluxo. O nível de ativação de um buffer de fluxo é definido quando `xStreamBufferCreate()` é chamado. É possível alterá-lo chamando `xStreamBufferSetTriggerLevel()`.

`sbRECEIVE_COMPLETED()` e `sbRECEIVE_COMPLETED_FROM_ISR()` são macros que são chamadas (internamente pela API do FreeRTOS) quando os dados são lidos de um buffer de fluxo. As macros verificam se há uma tarefa bloqueada no buffer de fluxo aguardando que o espaço fique disponível dentro do buffer e, se esse for o caso, removem a tarefa do estado Bloqueada. Você pode alterar o comportamento padrão de `sbRECEIVE_COMPLETED()` fornecendo uma implementação alternativa no [`FreeRTOSConfig.h`](freertos-config.md).

## Buffers de mensagens
<a name="rtos-message-buffer"></a>

Os buffers de mensagens permitem que mensagens discretas de tamanho variável sejam transmitidas de uma rotina de serviço de interrupção para uma tarefa ou de uma tarefa para outra. Por exemplo, mensagens com 10, 20 e 123 bytes de tamanho podem ser gravadas e lidas a partir do mesmo buffer de mensagens. Uma mensagem de 10 bytes só pode ser lida como uma mensagem de 10 bytes, não como bytes individuais. Os buffers de mensagens são criados na implementação do buffer de fluxo. É possível habilitar a funcionalidade do buffer de mensagens incluindo o arquivo de origem `stream_buffer.c` em seu projeto.

Os buffers de mensagens presumem que há apenas uma tarefa ou interrupção que grava no buffer (o gravador) e apenas uma tarefa ou interrupção que lê a partir do buffer (o leitor). É seguro que o gravador e o leitor sejam tarefas ou rotinas de serviço de interrupção diferentes, mas não é seguro ter vários gravadores ou leitores.

A implementação do buffer de mensagens usa as notificações diretas para tarefas. Portanto, chamar uma API de buffer de fluxo que coloca a tarefa de chamada no estado Bloqueada pode alterar o estado e o valor de notificação da tarefa de chamada. 

Para permitir que os buffers de mensagens manipulem mensagens de tamanho variável, o tamanho de cada mensagem é gravado no buffer de mensagens antes da própria mensagem. O tamanho é armazenado em uma variável do tipo `size_t`, que normalmente é de 4 bytes em uma arquitetura de 32 bytes. Portanto, gravar uma mensagem de 10 bytes em um buffer de mensagens consome na verdade 14 bytes de espaço em buffer. Da mesma forma, gravar uma mensagem de 100 bytes em um buffer de mensagens usa na verdade 104 bytes de espaço em buffer.

### Envio de dados
<a name="rtos-message-buffer-send"></a>

`xMessageBufferSend()` é usado para enviar dados a um buffer de mensagens a partir de uma tarefa. `xMessageBufferSendFromISR()` é usado para enviar dados a um buffer de mensagens a partir de uma rotina de serviço de interrupção (ISR).

`xMessageBufferSend()` permite que um tempo de bloqueio seja especificado. Se `xMessageBufferSend()` for chamado com um tempo de bloqueio diferente de zero para gravar em um buffer de mensagens e o buffer estiver cheio, a tarefa será colocada no estado Bloqueada até que o espaço seja disponibilizado no buffer de mensagens ou o tempo de bloqueio expire.

`sbSEND_COMPLETED()` e `sbSEND_COMPLETED_FROM_ISR()` são macros que são chamadas (internamente pela API do FreeRTOS) quando os dados são gravados em um buffer de fluxo. É utilizado um único parâmetro, que é o identificador do buffer de fluxo que foi atualizado. As duas macros verificam se há uma tarefa bloqueada no buffer de fluxo aguardando dados e, se esse for o caso, elas removem a tarefa do estado Bloqueada.

Você pode alterar esse comportamento padrão fornecendo sua própria implementação de `sbSEND_COMPLETED()` em [`FreeRTOSConfig.h`](freertos-config.md) Isso é útil quando um buffer de fluxo é usado para transmitir dados entre núcleos em um processador de vários núcleos. Nesse cenário, `sbSEND_COMPLETED()` pode ser implementado para gerar uma interrupção no outro núcleo da CPU, em seguida, a rotina de serviço da interrupção poderá usar a API `xStreamBufferSendCompletedFromISR()` para verificar e, se necessário, desbloquear uma tarefa que estava aguardando os dados.

### Recebimento de dados
<a name="rtos-message-buffer-receive"></a>

`xMessageBufferReceive()` é usado para ler dados de um buffer de mensagens em uma tarefa. `xMessageBufferReceiveFromISR()` é usado para ler dados de um buffer de mensagens em uma rotina de serviço de interrupção (ISR). `xMessageBufferReceive()` permite que um tempo de bloqueio seja especificado. Se `xMessageBufferReceive()` for chamado com um tempo de bloqueio diferente de zero para ler a partir de um buffer de mensagens e o buffer estiver vazio, a tarefa será colocada no estado Bloqueada até que os dados sejam disponibilizados ou o tempo de bloqueio expire.

`sbRECEIVE_COMPLETED()` e `sbRECEIVE_COMPLETED_FROM_ISR()` são macros que são chamadas (internamente pela API do FreeRTOS) quando os dados são lidos de um buffer de fluxo. As macros verificam se há uma tarefa bloqueada no buffer de fluxo aguardando que o espaço fique disponível dentro do buffer e, se esse for o caso, removem a tarefa do estado Bloqueada. Você pode alterar o comportamento padrão de `sbRECEIVE_COMPLETED()` fornecendo uma implementação alternativa no [`FreeRTOSConfig.h`](freertos-config.md).

# Suporte ao multiprocessamento simétrico (SMP)
<a name="smp-support"></a>

O [suporte ao SMP no kernel do FreeRTOS](https://freertos.org/symmetric-multiprocessing-introduction.html) permite que uma instância kernel do FreeRTOS agende tarefas em vários núcleos de processador idênticos. As arquiteturas principais devem ser idênticas e compartilhar a mesma memória.

A API do FreeRTOS permanece substancialmente a mesma entre as versões de núcleo único e de SMP, exceto [essas APIs adicionais](https://freertos.org/symmetric-multiprocessing-introduction.html#smp-specific-apis). Portanto, uma aplicação escrita para a versão single-core do FreeRTOS deve ser compilado com a versão SMP com o mínimo ou nenhum esforço. No entanto, pode haver alguns problemas funcionais, porque algumas suposições que eram verdadeiras para aplicações de núcleo único podem não ser mais verdadeiras para aplicações de vários núcleos.

Uma suposição comum é que uma tarefa de menor prioridade não pode ser executada enquanto uma tarefa de maior prioridade está em execução. Embora isso fosse verdade em um sistema de núcleo único, não é mais verdade para sistemas de vários núcleos porque várias tarefas podem ser executadas simultaneamente. Se a aplicação se basear em prioridades de tarefas relativas para fornecer exclusão mútua, ela poderá observar resultados inesperados em um ambiente com vários núcleos.

Outra suposição comum é que os ISRs não podem ser executados simultaneamente entre si ou com outras tarefas. Isto não é mais verdade em um ambiente com vários núcleos. O criador da aplicação precisa garantir a exclusão mútua adequada ao acessar dados compartilhados entre tarefas e ISRs.

# Temporizadores de software
<a name="software-timers"></a>

Um temporizador de software permite que uma função seja executada em um horário definido no futuro. A função executada pelo temporizador é chamada de *função de retorno de chamada* do temporizador. O tempo entre um temporizador ser iniciado e sua função de retorno de chamada ser executada é chamado de *período* do temporizador. O kernel do FreeRTOS fornece uma implementação de temporizador de software eficiente porque:
+ Não executa funções de retorno de chamada do temporizador a partir de um contexto de interrupção.
+ Não consome nenhum tempo de processamento, a menos que um temporizador tenha expirado.
+ Não adiciona nenhuma sobrecarga de processamento à interrupção do tique.
+ Não percorre estruturas de lista de links enquanto as interrupções estão desativadas.

# Suporte para baixo consumo
<a name="low-power-support"></a>

Como a maioria dos sistemas operacionais incorporados, o kernel do FreeRTOS usa um temporizador de hardware para gerar interrupções de tique periódicas, que são usadas para medir o tempo. A economia de energia de implementações de temporizador de hardware regulares é limitada pela necessidade de sair periodicamente do estado de baixo consumo e, em seguida, entrar novamente para processar as interrupções de tique. Se a frequência da interrupção de tique for muito alta, a energia e o tempo consumidos ao entrar e sair de um estado de baixo consumo para cada tique superam quaisquer ganhos potenciais de economia de energia, exceto dos modos de economia de energia mais leves. 

Para resolver essa limitação, o FreeRTOS inclui um modo de temporizador sem tiques para aplicações de baixo consumo. O modo de inatividade sem tique do FreeRTOS para a interrupção periódica de tique durante períodos inativos (períodos em que não há tarefas de aplicação que podem ser executadas) e, em seguida, faz um ajuste de correção no valor de contagem de tiques do RTOS quando a interrupção de tique é reiniciada. Parar a interrupção de tique permite que o microcontrolador permaneça em um estado de economia de energia profunda até que ocorra uma interrupção ou seja o momento de o kernel do RTOS fazer a transição de uma tarefa para o estado pronto.

# Configurar o kernel (FreeRTOSConfig.h)
<a name="freertos-config"></a>

Você pode configurar o kernel do FreeRTOS para uma placa e aplicação específicos com o arquivo de cabeçalho `FreeRTOSConfig.h`. Toda aplicação criada no kernel deve ter um arquivo de cabeçalho `FreeRTOSConfig.h` em seu caminho de inclusão do pré-processador. `FreeRTOSConfig.h` é específico da aplicação e deve ser colocado sob um diretório de aplicação e não em um dos diretórios de código-fonte do kernel do FreeRTOS.

Os arquivos `FreeRTOSConfig.h` das aplicações de demonstração e teste do FreeRTOS estão localizados em `freertos/vendors/vendor/boards/board/aws_demos/config_files/FreeRTOSConfig.h` e `freertos/vendors/vendor/boards/board/aws_tests/config_files/FreeRTOSConfig.h`.

Para obter uma lista dos parâmetros de configuração disponíveis para especificar em `FreeRTOSConfig.h`, consulte [FreeRTOS.org](https://www.freertos.org/a00110.html).