26 e 27 de Agosto, 2014
Transamérica Expo Center, São Paulo/SP
Por que o seu próximo RTOS
será compatível com CMSIS-RTOS ?
Douglas Renaux
eSysTech (sócio – Engenharia)
Porque usar um RTOS ?
(1/5)1. Aumento da complexidade das aplicações ao longo dos anos:
– Comparar 80’s 90’s 00’s 10’s
80’s - 8051
Controlador de
impressora de cheque
• 8032
• 256 bytes RAM
• 24K EPROM
• Serial – Timer - I/O
• Assembly
• Bare-metal
90’s – 80186
Módulo de
central telefônica
• 80186
• 16K RAM
• 32K EPROM
• SDLC
• C/C++ (DOS)
• PET (library)
2000’s – ARM7TDMI
Sistema Telemetria
• ARM7TDMI
• 1 M RAM
• 16 M Flash
• Conectividade
• X Real-Time Kernel (lib)
• C++
USB/Eth/3G/Prot. Rádio
10’s - Cortex
Automação Predial
• Cortex-M4
• 128K RAM
• 512K Flash
• USB/Eth/WiFi/…
• RTOS (muitas opções)
Telemedicina
• Cortex-A8
• 512M DDR2
• 16 G Flash
• Android
Porque usar um RTOS ?
(2/5)• Aumento da Complexidade do SW
– Aplicações recentes seriam
extremamente difíceis de desenvolver em um RTOS.
– Uso intensivo de bibliotecas:
USB – TCP/IP – WiFi – 3/4G – gráfica Cada biblioteca tem seus requisitos temporais para operação.
Necessidade de um gerenciador da operação/temporização dos diversos módulos de SW
Porque usar um RTOS ?
(3/5)2. Bibliotecas prontas:
– TCP/IP, WiFi, 3/4G – USB
– CAN
– Gráfica
3. Reduzir TTM
-> aumentar equipe/paralelismo
Divisão da tarefa de desenvolvimento de SW entre vários programadores que trabalham concorrentemente
Porque usar um RTOS ?
(4/5)4. Modularidade da solução
Tarefas com finalidades específicas
• Facilita reuso
• Facilita teste
• Facilita integração
• Facilita gerenciamento (tempo-
periodicidade, deadline, prioridade)
• Facilita a divisão de atividades de desenvolvimento
Porque usar um RTOS ?
(5/5)5. Separation of Concerns
(Separação de Preocupações)
– Lógica de cada atividade (função) – Temporização
– Inter-relacionamento
6. Ferramentas de depuração
Visualizador de execução
O que é um RTOS ?
• Sem RTOS:
– Empresa individual = 1 pessoa faz tudo
• Telefone, visitantes, adm (banco, contabilidade,
fisco, contas a pagar, receber), vendas, divulgação, compras, …
Como seria o treinamento desta pessoa (programa) ?
• Regras do que fazer
+Regras de como priorizar
O que é um RTOS ?
1 pessoa para cada tipo de atividade
Treinamento
(programação) muito mais simples.
Reuso !
• Com RTOS:
– Trabalho em equipe
• Muitas pessoas, cada qual com seu papel específico.
• Em um time de pessoas (equipe) é
menos complexo definir o trabalho de cada um.
• Não há necessidade de uma pessoa ficar mudando sua atividade o tempo todo
– Modularidade
– Separation of Concerns
– Separação atividade x controle atividade – Reuso
Problema real
• Sistema embarcado com:
– 3 portas seriais 115kbps = 1 char / 100u – USB = 1 pacote de 1K a cada 125us
– IHM – touch – IHM – LCD – 5 atividades:
• A1: 2 ms leitura touch
• A2: 7 ms processamento numérico dados USB
• A3: 500 us protocolo USB
• A4: 100 ms – sistema de menus
• A5: …
Como seria o fluxo de controle num algoritmo único para tratar de todas
estas atividades ?
Problema real
• Sistema embarcado com:
– 3 portas seriais 115kbps = 1 char / 100u – USB = 1 pacote de 1K a cada 125us
– IHM – touch – IHM – LCD – 5 atividades:
• A1: 2 ms leitura touch
• A2: 7 ms processamento numérico dados USB
• A3: 500 us protocolo USB
• A4: 100 ms – sistema de menus
• A5: …
Como seria o fluxo de controle num algoritmo único para tratar de todas
estas atividades ?
Implementando Concorrência
Multithreading
(múltiplas linhas de execução)
PV1 PV2 … PVn RTOS
HW
Proc.
Mem. Perif
Proc 1
Memória Compartilhada Periféricos Compartilhados
Proc n
…
Multithreading
(múltiplas linhas de execução)
PV1 PV2 … PVn RTOS
HW
Mas afinal, qual a mágica por trás do RTOS ?
• Cria processadores virtuais idênticos
– Cada qual com seus registradores e sua pilha
• Soma da capacidade de
processamento de todos eles é igual ao do MCU
• Multicore
– Muito mais proc. Virtuais do que cores
Regiões de Memória
Flash
CODE (.text) (.const)
RAM
HEAP
STACK
DATA (.data)
(.bss)
CPU
Registradores
para um programa sequencial:
Flash
CODE (.text) (.const)
RAM
HEAP DATA (.data)
(.bss)
CPU
Registradores
RAM
Multithreading
(múltiplas linhas de execução)
STACK 1 Regs 1
RAM
STACK n Regs n
…
Estados das Tarefas
Olhando no tempo:
granularidade grossa
Thread 1 Thread 2 Thread 3 Thread 4
t0 t0 +1s t0 +2s t0 +3s
Olhando no tempo:
granularidade fina
t0 t0 +1ms t0 +2ms t0 +3ms
RTOS
• A área de Engenharia de Sistemas Embarcados já descobriu há
décadas a importância de se usar um RTOS (70s)
• Nestes 40 anos, inúmeros RTOS surgiram no mercado
– Comerciais
– FOSS (Free and Open Source SW) – Silicon vendor
Cenário Atual
2013 Embedded Market Study – UBM Tech POSIX
Android / Linux Windows CE Other RTOS
8/16/32 bits (Cortex-M)
Cenário Atual
2013 Embedded Market Study – UBM Tech POSIX
Android / Linux Windows CE Other RTOS
8/16/32 bits (Cortex-M)
Cenário Atual
• Case 1:
Update de produto existente
Mais funcionalidade (WiFi / USB / GLCD) Trocar ARM7TDMI por um Cortex-M4
Mudar o Silicon Vendor Usar o RTOS do SV
Reuso ??
Cenário Atual
• Case 2: (middleware provider)
– Desenvolvemos uma biblioteca de funções de navegação usando GPS.
– Roda sobre RTOS
• Temporização
• Comunicação com GPS
– Para qual plataforma (arquitetura+RTOS) devemos fornecer ?
Cenário Atual
• Case 3: (treinamento)
– Nova alternativa de RTOS no mercado.
– Muito interessante dos pontos de vista técnico e mercadológico.
– Toda nossa equipe de engenharia treinada para o RTOS antigo !!!
ARM
Mas qual o problema afinal ?
1. ARM
2. Si Vendor
3. Desenvolvedores
(DesignHouse/Integrator)
4. Consumidor Final
• v 1.0 (2008)
– Drivers API
• v 2.0
– DSP Lib
• v 3.0 (2012)
– API RTOS
– DAP (Debug)
• V 4.0 (2014)
– CMSIS-Driver – CMSIS-Pack
CMSIS
(Cortex Microcontroller Software Interface Standard)
• Task Management
• Timing (delay, timers)
• Signals
• Semaphore / Mutex
• Memory Pool
• Message Queue
• Mail Queue
CMSIS-RTOS Funcionalidades
CMSIS-RTOS Evaluation
CMSIS POSIX VxWorks FreeRTOS X Real-Time
Kernel Process x Thread
Single Threaded Process Multiple Threaded Process Multi Threaded
Preemption
Priority Levels 7 ≥ 32 256 config.(typ. 5) 32
Multiple tasks at same priority level
Static x Dynamic priorities both both both both both
Timers
Resolution / Precision 1ms/1tick - config. config.(typ. 4ms) 1ns/1clk
Single-Shot x Periodic both single-shot single-shot both both
Notification Callback Signal Signal Callback Callback / IRQ /
Assync. Msg Timing services
Delay (Resolution / Precision) 1ms/1tick ticks ticks ticks 1ns/1clk
Microseconds Delay Semaphore / Mutex
Binary/ Counter both both both both both
Mutex
Priority Inheritance (PIP) Priority Ceiling Protocol (PCP) Posix Signals
Flags
(*) implemented with signals
(*) (*) (*)
Memory Pool Malloc/Free only
Message Queue (integers) (*) implemented with Mail Queue
(*) (*) (*) (*)
Douglas Renaux – ESC 2014
Então só funciona para Cortex ?
• A ARM propôs com esta intenção
• Tem a funcionalidade esperada de um RTOS para MCU no segmento 1
• Se fabricantes de RTOS usarem esta API para os RTOS de todos as
arquiteturas, o mercado só tem a ganhar.
Porque é bom para o mercado ?
• Desenvolvedores
– Interface padronizada
• Facilita reuso
• Portabilidade
• Treinamento / Cultura
• Middleware vendors
– Uma biblioteca para todos os RTOS ! – Redução de custo de portabilidade – Mercado tem mais opções a melhor
preço
Planejando uma Aplicação
com RTOS
CMSIS-RTOS: Overview 1/4
• Kernel Information and Control
• osKernelInitialize : Initialize the RTOS kernel.
• osKernelStart : Start the RTOS kernel.
• osKernelRunning : Query if the RTOS kernel is running.
• osKernelSysTick $ : Get RTOS kernel system timer counter.
• osKernelSysTickFrequency $ : RTOS kernel system timer frequency in Hz.
• osKernelSysTickMicroSec $ : Convert microseconds value to RTOS kernel system timer value.
• Thread Management
• osThreadCreate : Start execution of a thread function.
• osThreadTerminate : Stop execution of a thread function.
• osThreadYield : Pass execution to next ready thread function.
• osThreadGetId : Get the thread identifier to reference this thread.
• osThreadSetPriority : Change the execution priority of a thread function.
• osThreadGetPriority : Obtain the current execution priority of a thread function.
CMSIS-RTOS: Overview 2/4
• Generic Wait Functions
• osDelay : Wait for a specified time.
• osWait $ : Wait for any event of the type Signal, Message, or Mail.
• Timer Management $
• osTimerCreate : Define attributes of the timer callback function.
• osTimerStart : Start or restart the timer with a time value.
• osTimerStop : Stop the timer.
• osTimerDelete : Delete a timer.
CMSIS-RTOS: Overview 3/4
• Signal Management
• osSignalSet : Set signal flags of a thread.
• osSignalClear : Reset signal flags of a thread.
• osSignalWait : Suspend execution until specific signal flags are set.
• Mutex Management $
• osMutexCreate : Define and initialize a mutex.
• osMutexWait : Obtain a mutex or Wait until it becomes available.
• osMutexRelease : Release a mutex.
• osMutexDelete : Delete a mutex.
• Semaphore Management $
• osSemaphoreCreate : Define and initialize a semaphore.
• osSemaphoreWait : Obtain a semaphore token or Wait until it becomes available.
• osSemaphoreRelease : Release a semaphore token.
• osSemaphoreDelete : Delete a semaphore.
CMSIS-RTOS: Overview 4/4
• Memory Pool Management $
• osPoolCreate : Define and initialize a fix-size memory pool.
• osPoolAlloc : Allocate a memory block.
• osPoolCAlloc : Allocate a memory block and zero-set this block.
• osPoolFree : Return a memory block to the memory pool.
• Message Queue Management $
• osMessageCreate : Define and initialize a message queue.
• osMessagePut : Put a message into a message queue.
• osMessageGet : Get a message or suspend thread execution until message arrives.
• Mail Queue Management $
• osMailCreate : Define and initialize a mail queue with fix-size memory blocks.
• osMailAlloc : Allocate a memory block.
• osMailCAlloc : Allocate a memory block and zero-set this block.
• osMailPut : Put a memory block into a mail queue.
• osMailGet : Get a mail or suspend thread execution until mail arrives.
• osMailFree : Return a memory block to the mail queue.
•
1. Definição de estruturas de dados como acessar ?
2. Inicialização destas estruturas 3. Operação
Yield GetId
SetPriority
4. Término (opcional)
Ciclo de Vida dos Elementos
do Kernel – exemplo: Thread
1. Definição de estruturas de dados como acessar ?
2. Inicialização destas estruturas 3. Operação
Yield GetId
SetPriority
4. Término (opcional)
osThreadCreate(osThread(job1),NULL);
- Ponteiro para a struct com configuração da tarefa - Ponteiro para argumento da função job1
osThreadDef(job1, osPriorityAboveNormal, 1, 0);
macro
Cria uma struct com:
-nome da função principal desta thread -prioridade
-número máximo de instâncias
-tamanho da pilha (em bytes) obs: 0 = tamanho default
osThread(job1):
uma macro que é substituida por um ponteiro para a estrutura acima
Ciclo de Vida dos Elementos
do Kernel – exemplo: Thread
1. Definição de estruturas de dados como acessar ?
2. Inicialização destas estruturas 3. Operação
Yield GetId
SetPriority
4. Término (opcional)
osThreadCreate(osThread(job1),NULL);
- Ponteiro para a struct com configuração da tarefa - Ponteiro para argumento da função job1
Ciclo de Vida dos Elementos do Kernel – exemplo: Thread
osThreadYield( );
- Libera o processador para a próxima tarefa osThreadGetId( );
- Retorna o identificador desta tarefa (ThreadId) osThreadSetPriority( id, priority);
- Altera o nível de prioridade de uma tarefa osThreadTerminate( id );
- Destrói o TCB eliminando esta tarefa do sistema
Ciclo de Vida dos Elementos do Kernel
Thread Timer Mutex Semaphore Memory
Pool
Message Queue
Mail Queue Definição
osThreadDef osTimerDef osMutexDef osSemaphoreDef osPoolDef osMessageQDef osMailQDef
Acesso
osThread osTimer osMutex osSemaphore osPool osMessageQ osMailQ
Inicializ.
osThreadCreate osTimerCreate osMutexCreate osSemaphoreCreate osPoolCreate osMessageCreate osMailQCreate
Operação
osThreadYield osThreadGetId
osTimerStart osTimerStop
osMutexWait osMutexRelease
osSemaphoreWait osSemaphoreRelease
osPoolAlloc osPoolFree
osMessagePut osMessageGet
osMailAlloc osMailFree osMailPut osMailGet
Término
osThreadTerminate osTimerDelete osMutexDelete osSemaphoreDelete
#include "cmsis_os.h" // CMSIS RTOS header file
void job1 (void const *argument) { // thread function 'job1' while (1) {
: // execute some code
osDelay (10); // delay execution for 10 milliseconds }
}
osThreadDef(job1, osPriorityAboveNormal, 1, 0); // define job1 as thread function
void job2 (void const *argument) { // thread function 'job2' while (1) {
: // execute some code }
}
osThreadDef(job2, osPriorityNormal, 1, 0); // define job2 as thread function int main (void) { // program execution starts here
osKernelInitialize (); // initialize RTOS kernel : // setup and initialize peripherals
osThreadCreate (osThread(job1),NULL); // higher priority osThreadCreate (osThread(job2),NULL);
osKernelStart (); // start kernel with job1 execution }
Duas tarefas independentes
Exemplo:
Acesso a recurso compartilhado
Duas tarefas que
compartilham um recurso
#include "cmsis_os.h" // CMSIS RTOS header file osMutexDef (mutLCD);
void job1 (void const *argument) { // thread function 'job1' while (1) {
osMutexWait (mutLCDid,osWaitForever);
: // resource usage osMutexRelease (mutLCDid);
} }
osThreadDef(job1, osPriorityNormal, 1, 0); // define job1 as thread function
void job2 (void const *argument) { // thread function 'job2' }
osThreadDef(job2, osPriorityNormal, 1, 0); // define job2 as thread function int main (void) { // program execution starts here
osKernelInitialize (); // initialize RTOS kernel : // setup and initialize peripherals
osMutexId mutLCDid = osMutexCreate (osMutex(mutLCD));
osThreadCreate (osThread(job1),NULL);
osThreadCreate (osThread(job2),NULL);
osKernelStart (); // start kernel
Exemplo:
Comunicação por Mensagem
Comunicação ISR -> Tarefa
#include "cmsis_os.h" // CMSIS RTOS header file
enum JoystickMovement {Up, Down, Left, Right, Center, Last = 0x12345678};
osMessageQDef (MsgBox, 2, JoystickMovement ); // Define message queue osMessageQId MsgBox;
void JoySt_ISR(void) {
JoystickMovement JS_value = ReadJoyStick( );
osMessagePut(MsgBox, &JS_value, 0);
}
void PacMan (void const *argument) {
osEvent evt; // osEventMessage,valor, id da MsgBox :
evt = osMessageGet(MsgBox, 5); // timeout 5 ms if (evt == ...) {
: }
osThreadDef(PacMan, osPriorityNormal,1,0); //define PacMan as thread function
int main (void) { // program execution starts here
osKernelInitialize (); // initialize RTOS kernel : // setup and initialize peripherals
MsgBox = osMessageCreate(osMessageQ(MsgBox), NULL);
osThreadCreate (osThread(PacMan));
osKernelStart (); // start kernel with execution of PacMan
Alocação de Memória
• Mesmo papel de malloc e free
• A biblioteca padrão do C não foi concebida para tolerar
chaveamento de contexto, ou seja, não é thread-safe.
Alocação de Memória
void th_alloc_ex (void const *argument) {
uint32_t *address;
osStatus status; // códigos de retorno osPoolId MemPool_Id; // ponteiro para o Pool
osPoolDef(MemPool,8,uint32_t); // Pool para 8 inteiros
MemPool_Id = osPoolCreate(osPool (MemPool)); // NULL = erro address = (uint32_t *) osPoolAlloc(MemPool_Id); //aloca 1
*address = 0xffaabbcc; // acesso escrita status = osPoolFree(MemPool_Id, address); // libera
// osOK, osErrorValue, osErrorParameter osThreadTerminate(osThreadGetId());
}
Conclusão
(1/2)• Por que usar um RTOS ?
• O que se pretende com o CMSIS-RTOS ?
• O papel do CMSIS-RTOS.
• Vários exemplos de uso.
Conclusão
(2/2)• Positivo:
– Agrega a funcionalidade da maioria dos RTOS – Apropriado para diversas arquiteturas
(architecture agnostic)
– Oferece uma API comum para todos os middleware (incentivo ao mercado de middleware)
– Oferece uma API comum para o
desenvolvedor de aplicação embarcada (incentivo a portabilidade, quebra barreiras de mudança de RTOS/plataforma)
• Futuro:
– Interessados devem cobrar.