FreeRTOS V10.0.0 e as novas APIs de mensagens

- por Sergio Prado

Categorias: FreeRTOS Tags:

Na semana passada escrevi sobre o lançamento do Amazon FreeRTOS, que aconteceu junto com a liberação do FreeRTOS V10.0.0.

Esta nova versão do FreeRTOS vem com diversas mudanças, dentre elas a inclusão de duas novas classes de funções para trocas de mensagens.

Até então, o único recurso básico existente para troca de mensagens no FreeRTOS eram os queues. A partir de agora, temos também os stream buffers e os message buffers.

STREAM BUFFERS

Stream Buffers implementam um conjunto de funções para trocas de dados (sequência de bytes) entre duas tarefas ou entre uma rotina de tratamento de interrupção (ISR) e uma tarefa.

Comparado a queues, os stream buffers são basicamente otimizados para comunicação um-para-um (tarefa->tarefa ou ISR->tarefa).

Para utilizar esta API é necessário incluir no projeto o arquivo stream_buffer.c. Um stream buffer pode ser criado com a função xStreamBufferCreate(), onde é possível definir o tamanho máximo do buffer e um trigger que será utilizado para desbloquear a rotina de leitura quando a quantidade de bytes enviados ao stream buffer atingir o valor configurado.

As rotinas xStreamBufferSend() e xStreamBufferReceive() podem ser utilizadas para respectivamente enviar e receber bytes do stream buffer.

Por exemplo, a tarefa abaixo irá tratar os dados recebidos da porta serial, se comunicando com a ISR da serial através de um stream buffer. Na inicialização, a tarefa irá criar um stream buffer de 256 bytes e depois bloquear esperando indefinidamente dados no stream buffer. A tarefa será desbloqueada quando receber pelo menos 16 bytes (valor definido como trigger na função de criação do stream buffer).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void taskUART(void *pvParameters)
{
    unsigned int qtdbytes;
    char msg[256];
 
    xStreamBuffer = xStreamBufferCreate(256, 16);
 
    for (;;) 
    {
	qtdbytes = xStreamBufferReceive(xStreamBuffer, (void *)msg, sizeof(msg), portMAX_DELAY);
 
        if (qtdbytes > 0)
        {
 
            // handle received bytes
 
        }
    }
}

A rotina de tratamento de interrupção da serial será responsável por enviar os dados recebidos para o stream buffer. Apesar da ISR enviar para o stream buffer os dados recebidos byte-a-byte, a rotina de leitura será desbloqueada apenas quando o valor configurado no trigger for atingido (16 bytes no exemplo acima).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void UART0_IRQHandler(uint32_t instance)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    unsigned char ch;
 
    /* handle RX interrupt */
    if((LPSCI_HAL_GetRxDataRegFullIntCmd(baseAddr)) && (LPSCI_HAL_IsRxDataRegFull(baseAddr)))
    {
        LPSCI_HAL_Getchar(baseAddr, &ch);
        xStreamBufferSendFromISR(xStreamBuffer, &ch, 1, &xHigherPriorityTaskWoken);
    }
 
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

Conforme comentei mais acima, é importante ressaltar que esta API está otimizada e permite apenas a comunicação um-para-um, onde apenas uma tarefa (ou ISR) é responsável por enviar dados para o stream buffer, e uma outra tarefa é responsável por receber estes dados. Se você precisar enviar ou receber dados com mais de uma tarefa, é necessário proteger as rotinas do stream buffer dentro de uma seção crítica, utilizando por exemplo um mutex ou desabilitando as interrupções (neste caso, o uso de um queue talvez faça mais sentido).

Outras funções de stream buffer ainda estão disponíveis e documentadas no site do FreeRTOS.

MESSAGE BUFFERS

As funções da API de message buffers permitem o envio de mensagens de tamanho variável. Como estas funções utilizam internamente os stream buffers, acabam herdando suas características como a obrigatoriedade da comunicação um-para-um (tarefa->tarefa ou ISR->tarefa).

Assim como no uso de stream buffers, para utilizar a API de message buffers é necessário incluir no projeto o arquivo stream_buffer.c. Um message buffer pode ser criado com a função xMessageBufferCreate() e as funções xMessageBufferSend() e xMessageBufferReceive() podem ser utilizadas respectivamente para enviar e receber mensagens do buffer.

Por exemplo, a tarefa abaixo irá receber e imprimir mensagens (strings) de tamanho variável. Na inicialização, a tarefa irá criar um message buffer de 256 bytes e depois bloquear indefinidamente esperando mensagens neste buffer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void taskRxMSG(void *pvParameters)
{
    unsigned int qtdbytes;
    char msg[32];
 
    xMessageBuffer = xMessageBufferCreate(256);
 
    for (;;) 
    {
	qtdbytes = xMessageBufferReceive(xMessageBuffer, (void *)msg, sizeof(msg) - 1, portMAX_DELAY);
 
        msg[qtdbytes] = 0;
        printf("%s\n", msg);
    }
}

E a tarefa abaixo irá enviar, a cada 1 segundo, mensagens de tamanho variável para o message buffer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void taskTxMSG(void *pvParameters)
{
    char *msgs[] = {
        "nostromo",
        "patna",
        "auriga",
        "prometheus",
        "covenant",
    };
 
    unsigned int qtd = sizeof(msgs)/sizeof(msgs[0]);
    unsigned int ind = 0;
 
    for (;;) 
    {
	xMessageBufferSend(xMessageBuffer, msgs[ind], strlen(msgs[ind]), portMAX_DELAY);
 
        if (++ind >= qtd)
            ind = 0;
 
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}

A API completa da funcionalidade de message buffers está documentada no site do FreeRTOS.

OUTRAS ALTERAÇÕES

Além da inclusão destas duas novas APIs, o FreeRTOS v10.0.0 trouxe a implementação da pilha de protocolos TCP/IP (FreeRTOS+TCP) desenvolvida pela própria equipe do FreeRTOS.

Quem já precisou integrar ao FreeRTOS uma pilha de protocolos TCP/IP como a uIP ou a lwIP sabe das dificuldades que é realizar este trabalho. Esta nova pilha de protocolos vem para facilitar a nossa vida, é de código-aberto (licença MIT) e já está integrada às APIs do FreeRTOS.

No momento, estão disponíveis as implementações de ARP, IP, TCP, UDP, Berkeley Sockets, DHCP e DNS, e segundo a documentação tem um footprint de aproximadamente 20K quando compilada com o GCC para ARM Cortex-M (otimizando com o parâmetro -Os).

Para mais informações sobre esta pilha de protocolos, consulte a documentação no site do FreeRTOS.

Nesta nova versão do FreeRTOS foram adicionados ainda novos projetos de demonstração, correções e otimizações em alguns portes e mais algumas alterações cosméticas.

A lista completa de mudanças está disponível no histórico de alterações do FreeRTOS.

Um abraço,

Sergio Prado

  • Juliano Oliveira

    Parabéns pelo artigo, este complementa legal o documento mastering FREERTOS disponível sem as explicações de stream e message buffers

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.