Olá caros leitores, neste artigo eu (Evandro Teixeira) e Eder Tadeu iniciaremos uma série sobre o RTOS (Real Time Operating System – Sistema Operacional de Tempo Real) da NXP, o MQX RTOS. Além desta proposta, também sugerir mais uma opção de RTOS que as grandes companhias oferecem e também “pegar carona” na série sobre o mesmo tema que o Rodrigo Almeida abordou.
MQX RTOS
O MQX é um Sistema Operacional de Tempo Real (RTOS) que inclui um Kernel multi-tarefa, ou seja, é um software que gerencia recursos de hardware e tarefas (funções como em sistemas baremetal) a fim de garantir as respectivas execuções dentro do tempo estimados e também respeitando as prioridades (pre-empetive scheduling – um escalonador de tarefas para serem executadas já com as prioridades pré-definidas). Além disso, garante um tempo de resposta muito rápido para interrupções.
Seu pequeno e configurável tamanho conserva o espaço de memória para aplicação embarcadas e pode ser configurado com poucos 6KB de memória ROM, incluindo o Kernel, interrupções, semáforos (semaphores), listas (queues) e o gerenciador de memória.
O MQX tem suporte integrado a pilhas de protocolo TCP/IP stack (RTCS), MS-DOS File System (MFS), USB host/device stack e suporte também a múltiplos núcleos de processamento (multicore).
A seguir temos uma visão geral de MQX RTOS (figura 1) em uma aplicação.
Termos encontrados no MQX
Tanto no MQX RTOS quanto em qualquer outro RTOS, levando em conta suas particularidades, mas de forma geral, encontramos os seguintes termos recorrentes:
- Task: uma task em RTOS pode ser entendida como pequeno programa independente que executa seu próprio contexto sem nenhuma dependência de outra task dentro sistema. É responsabilidade do escalonador (scheduling RTOS) assegurar o contexto do processador (valores de registradores, conteúdo da pilha, etc) quando há uma permuta entre tasks, ou seja, quando uma deixa de ser ativa para dar lugar a outra (em Round-Robin seria uma task de alta prioridade estar como “ready” enquanto a que está em “running” ter prioridade menor). Assim, todo momento em que a task for executada novamente, seu contexto sempre será restaurado e salvo quando uma task der lugar a outra;
- Task Management (Gestão de Tarefas): é um componente do núcleo do MQX e cria automaticamente tasks quando o MQX RTOS inicia. Uma aplicação pode também criar, gerenciar e finalizar outras tasks. Também pode criar mulíiplas instâncias da mesma task e não há limite do total de número de tasks na aplicação. Qualquer aplicação também pode dinamicamente mudar os atributos de qualquer task. O MQX RTOS libera recursos quando ele termina uma task;
- Scheduling (Escalonador): o Scheduling ou Escalonador é um algoritmo responsável por escolher qual a próxima task será executada. É complacente ao POSIX.4 e fornece como opções de funcionamento: FIFO Scheduling (baseado em prioridades e a task ativa permanece em funcionamento enquanto outra com maior prioridade ainda não estiver ativa), Round Robin (parecido com o modelo anterior e também baseado em prioridade, mas possui um tempo de execução chamado de “time slice” que não pode ser estrapolado) e Explicit (usando listas de tasks – tasks queues). Para detalhes de cada tipo, sugere-se que seja lido o Manual do Usuário MQX RTOS;
- Gerenciando memória com alocadores de memória dinâmica: para alocar e liberar pedaços de tamanhos variáveis (chamados de blocos de memória), o MQX RTOS fornece um serviço de núcleo que é similar às funções “malloc()” e “free()” que a maioria das bibliotecas de tempo de execução fornecem. É possível escolher uma das três opções possíveis de implementação de alocação dinâmica: LWMEM, MEM ou TLSF;
- Eventos (Events): Eventos são componentes opcionais do MQX, eles suportam o gerenciamento dinâmico de objetos que são formatados como campos de bits. Tasks e ISR (Interrupt Service Routine – Rotina de Serviço de Interrupção) pode usar eventos para sincronizar e transmitir simples informações na forma de mudança de estados dos bits. Existem os grupos de eventos rápidos e os nomeados. Esses grupos podem se auto “resetar” o bit de evento, além disso o MQX automaticamente “reseta” os bits após a criação;
- Semáforos (Semaphores): Semáforos são componentes opcionais. Pode-se usá-los para sincronizar as tasks, ou seja, se algum recurso da aplicação estiver sendo usado (lido ou escrito como uma memória Flash, por exemplo), o semáforo permite que uma task faça o uso enquanto outra aguarda, ou que esse recurso seja restrito ou não restrito, assim implementando um mecanismo de sinalização produtor/consumidor;
- Mensagens (Messages): Mensagens são componentes opcionais. Tasks podem comunicar com outras enviando mensagens para queue (fila) de mensagens (message queues). Cada task abre sua própria queue de mensagem de entrada (input-message queue). Uma mensagem é unicamente identificada pela sua ID da queue que o MQX atribui quando a própria queue é criada. Qualquer task pode enviar uma mensagem para a queue quando ela estiver aberta, desde que a task saiba o ID da queue.
Versões do MQX
A NXP elaborou algumas versões do MQX RTOS para os microcontroladores e processadores de seu portifólio, assim, a seguir faremos um breve resumo das respectivas características que cada família possui, veja:
-
MQX RTOS
É uma versão completa e funcional do MQX RTOS. Suporta as principais famílias (Kinetis, Vybrid, ColdFire, i.MX e Power Architecture). Ocupa em torno de 6KB de memoria ROM e 2,5KB de memória RAM, Além disso, seus drives são compatíveis com o padrão POSIX.
-
MQX Lite RTOS
NXP MQX™ Lite RTOS é o mais simples MQX RTOS dedicado para microcontroladores com recursos limitados. Inicialmente desenvolvido para a família Kinetis série L. O NXP MQX Lite RTOS esta disponível como componente do Processor Expert e é facilmente configurável.
-
MQX RTOS for Kinetis SDK
É uma versão dedicada à família de microcontroladores Kinetis. Também é uma versão completa do MQX RTOS integrada ao Kinetis Software Development Kit (KSDK).
Microcontroladores suportados
A seguir uma lista de microcontroladores e processadores que podem embutir o MQX RTOS em suas aplicações:
Tabela 1 – MCUs e MPUs suportados pelo MQX.
Criando projeto com MQX RTOS para Kinetis SDK
Para aderir o MQX em um projeto, faremos o uso do Kinetis Design Studio e também do KSDK Project Generator, mas a princípio utilizaremos o último, assim proceda da seguinte forma:
1) Procure pela opção “Advanced” e configure conforme a figura 5;
2) Feito o primeiro passo, abra o Kinetis Design Studio e importe o projeto feito no passo anterior.
3) Clique em “File” e depois em “Import”. Nesta última procure por “General” e selecione a opção “Existing Project into Workspace”, em seguida, clique em “Next”.
4) Clique em “Browse” e selecione o diretório do projeto gerado pelo KSDK Project Generator, em seguida, clique em “Finish”.
Observe que além do projeto criado, também são importados os projetos do MQX RTOS e KSDK (ksdk_mqx_libMK22FN512VLH12, mqx_frdm_k22f_MK22FN512VLH12, mqx_frdmk22f, mqx_stdlib_frdmk22f, nshell_frdmk22f). Assim, compile todos os projetos.
Feito isto, vamos estudar um pouquinho o projeto criado. Assim: abra o diretório “Sources”, ele contém dois arquivos (main.c e main.h). O arquivo main.h possui os include’s dos arquivos do MQX RTOS e KSDK, já o arquivo main.c contém duas tarefas (main_task e task_example) além dos “templates” das tarefas.
A tarefa main_task é inicializada pelo próprio MQX RTOS e inicializa os periféricos do hardware, a UART para auxiliar no Debug e criar a tarefa task_example.
A tarefa task_example possui apenas a estrutura básica, imprime uma mensagem para Debug e a tarefa entra em loop infinito.
Código fonte main.c
//-----------------------------------------------------------------------
// Standard C/C++ Includes
//-----------------------------------------------------------------------
#include <stdio.h>
//-----------------------------------------------------------------------
// KSDK Includes
//-----------------------------------------------------------------------
#include "main.h"
//-----------------------------------------------------------------------
// Application Includes
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------
void main_task(uint32_t param);
void task_example(task_param_t param);
//-----------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------
#define MAIN_TASK 8U
const TASK_TEMPLATE_STRUCT MQX_template_list[] =
{
{ MAIN_TASK, main_task, 0xC00, 20, "main_task", MQX_AUTO_START_TASK},
{ 0L, 0L, 0L, 0L, 0L, 0L }
};
#define TASK_EXAMPLE_PRIO 6U
#define TASK_EXAMPLE_STACK_SIZE 1024U
//-----------------------------------------------------------------------
// Typedefs
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------
OSA_TASK_DEFINE(task_example, TASK_EXAMPLE_STACK_SIZE);
//-----------------------------------------------------------------------
// Main Function
//-----------------------------------------------------------------------
void main_task(uint32_t param)
{
osa_status_t result = kStatus_OSA_Error;
// Configure board specific pin muxing
hardware_init();
// Initialize UART terminal
dbg_uart_init();
OSA_Init();
result = OSA_TaskCreate(task_example,
(uint8_t *)"example",
TASK_EXAMPLE_STACK_SIZE,
task_example_stack,
TASK_EXAMPLE_PRIO,
(task_param_t)0,
false,
&task_example_task_handler);
if (result != kStatus_OSA_Success)
{
PRINTF("Failed to create example task\r\n");
return;
}
OSA_Start();
for (;;) // Forever loop
{
__asm("NOP");
}
}
//-----------------------------------------------------------------------
// Task Functions
//-----------------------------------------------------------------------
void task_example(task_param_t param)
{
PRINTF("\r\nRunning the mqx_frdm_k64f project.\r\n");
while(1)
{
}
}
//-----------------------------------------------------------------------
Código fonte main.h
//----------------------------------------------------------------------- // KSDK Includes //----------------------------------------------------------------------- #include "board.h" #include "fsl_debug_console.h" #include "fsl_clock_manager.h" #include "fsl_interrupt_manager.h" #include "fsl_power_manager.h" #include "fsl_os_abstraction.h" #include "fsl_adc16_driver.h" #include "fsl_cmp_driver.h" #include "fsl_cmt_driver.h" #include "fsl_crc_driver.h" #include "fsl_dac_driver.h" #include "fsl_dspi_edma_master_driver.h" #include "fsl_dspi_edma_slave_driver.h" #include "fsl_dspi_master_driver.h" #include "fsl_dspi_slave_driver.h" #include "fsl_edma_driver.h" #include "fsl_enet_driver.h" #include "fsl_ewm_driver.h" #include "fsl_flexbus_driver.h" #include "fsl_flexcan_driver.h" #include "fsl_ftm_driver.h" #include "fsl_gpio_driver.h" #include "fsl_i2c_master_driver.h" #include "fsl_i2c_slave_driver.h" #include "fsl_lptmr_driver.h" #include "fsl_mpu_driver.h" #include "fsl_pdb_driver.h" #include "fsl_pit_driver.h" #include "fsl_rnga_driver.h" #include "fsl_rtc_driver.h" #include "fsl_sai_driver.h" #include "fsl_sdhc_driver.h" #include "fsl_smartcard_driver.h" #if defined(FSL_FEATURE_SOC_EMVSIM_COUNT) #if (FSL_FEATURE_SOC_EMVSIM_COUNT >= 1) #include "fsl_smartcard_emvsim_driver.h" #endif #endif #if defined(FSL_FEATURE_UART_HAS_SMART_CARD_SUPPORT) #if (FSL_FEATURE_UART_HAS_SMART_CARD_SUPPORT == 1) #include "fsl_smartcard_uart_driver.h" #endif #endif #include "fsl_uart_driver.h" #include "fsl_uart_edma_driver.h" #include "fsl_vref_driver.h" #include "fsl_wdog_driver.h" #if USING_DIRECT_INTERFACE #include "fsl_smartcard_direct_driver.h" #endif #if USING_NCN8025_INTERFACE #include "fsl_smartcard_ncn8025_driver.h" #endif
Conclusão
O MQX RTOS é uma ótima opção para utilizar em sua aplicação em conjunto com os microcontroladores da NXP, contém um número grande de API’s que auxilia no desenvolvimento do seu projeto. No próximo artigo iremos explorar as API’s para trabalhar com as tarefas.
Referências
MQX™ RTOS for Kinetis SDK v1.3
MQX™ Lite Real-Time Operating System (RTOS)
MQX Lite ™ RTOS – Reference Manual
Fonte das Imagens: NXP MQX™ RTOS









Muito bom conhecer mais sobre o MQX! Ótimo artigo!