EL68E Sistemas Embarcados
Prof. Douglas RENAUX
Programação Concorrente
1 – Infra-estrutura
• Prog. Sequencial x Prog Concorrente
• Pessoa x Equipe
• Processadores Virtuais
• Regiões de Memória de Prog. Sequencial
• Regiões de Memória de Prog. Concorrente
• Multi-processo / MMU / mem. Virtual
• Multi-threaded
Problema da Exclusão Mútua
• Soluções em SW
• Soluções com Semáforos
• Soluções com Mensagens
Problema da Exclusão Mútua – Soluções em SW
1. Porta
2. Porta 1 e Porta 2
1. Duas ordens de acesso possíveis
3. Vez
4. Porta 1, Porta 2 e Vez
Semáforos
Definição
Tipos: binário, contador, mutex
Conceito de propriedade – só a tarefa “dona” do semáforo pode liberá-lo
Suporte em HW Ciclos RMW
Solução no Cortex – instruções de LD/ST exclusivo
Comunicação e Sincronização via Mensagens
• Assíncrono
• Síncrono
• Síncrono com Resposta
Comunicação Assíncrona
Tarefa 1
Executando
Receive
Bloqueado em receive
Tarefa 2
Executando Pronto
Pronto
Put
Comunicação Síncrona
Comunicação Síncrona com Resp
Bloqueado em receive
Tarefa 1
Executando
Receive
Tarefa 2
Executando Pronto
Pronto Send
Bloqueado em send Executando
Reply
Por que o seu próximo RTOS
será compatível com CMSIS-RTOS ?
)
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 ?
Douglas Renaux – ESC 2014
Implementando Concorrência
Douglas Renaux – ESC 2014
PVPVPV
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
…
Douglas Renaux – ESC 2014
Multithreading
(múltiplas linhas de execução)
PV1 PV2 … PVn
RTOS HW
Douglas Renaux – ESC 2014
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
Douglas Renaux – ESC 2014
Regiões de Memória
Flash
CODE(.text) (.const)
RAM
HEAP
STACK
(.data)DATA (.bss)
CPU
Registradores
Douglas Renaux – ESC 2014
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
…
Douglas Renaux – ESC 2014
Estados das Tarefas
Douglas Renaux – ESC 2014
Olhando no tempo:
granularidade grossa
Douglas Renaux – ESC 2014
Thread 1 Thread 2 Thread 3 Thread 4
t0 t0 +1s t0 +2s t0 +3s
Olhando no tempo:
granularidade fina
Douglas Renaux – ESC 2014
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
Douglas Renaux – ESC 2014
• 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
• V 5.0 (2016)
CMSIS
(Cortex Microcontroller Software Interface Standard)
Douglas Renaux – ESC 2014
CMSIS-RTOS
http://www.keil.com/pack/doc/cmsis/rtos/html/index.html www.arm.com
CMSIS-RTOS RTX
http://www.keil.com/pack/doc/cmsis_rtx/index.html www.arm.com
CMSIS-RTOS
www.arm.com
CMSIS-RTOS
www.arm.com
Task Management
Timing (delay, timers) Signals
Semaphore / Mutex Memory Pool
Message Queue Mail Queue
CMSIS-RTOS Funcionalidades
Douglas Renaux – ESC 2014
CMSIS-RTOS - Prioridades
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0049a/gs_ma_rtos.htm
enum osPriority {
osPriorityIdle = -3, osPriorityLow = -2,
osPriorityBelowNormal = -1, osPriorityNormal = 0,
osPriorityAboveNormal = +1, osPriorityHigh = +2,
osPriorityRealtime = +3, osPriorityError = 0x84 }
Planejando uma Aplicação com RTOS
Douglas Renaux – ESC 2014
<<mutex>>
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.
Douglas Renaux – ESC 2014
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.
Douglas Renaux – ESC 2014
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.
Douglas Renaux – ESC 2014
CMSIS-RTOS: Overview 4/4
Douglas Renaux – ESC 2014
• 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
Douglas Renaux – ESC 2014
1. Definição de estruturas de dados como acessar ?
2. Inicialização destas estruturas
3. Operação Yield
GetId
SetPriority
4. Término (opcional)
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
Douglas Renaux – ESC 2014
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
Douglas Renaux – ESC 2014
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
Douglas Renaux – ESC 2014
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
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
Douglas Renaux – ESC 2014
osThreadTerminate( id );
- Destrói o TCB eliminando esta tarefa do sistema
Ciclo de Vida dos
Elementos do Kernel
Douglas Renaux – ESC 2014
Thread Timer Mutex Semaphore Memory
Pool Message Queue
Mail Queue Tipos (*) osThreadIdos_pthread osTimerIdos_ptimer osMutexId osSemaphoreId osPoolId osMessageQId osMailQId
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
(*) os Id são ponteiros para structs
Exercício 1
• Familiarização com o exemplo de CMSIS- RTOS
• Apresente um diagrama de classes com as tarefas deste exemplo
#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
Douglas Renaux – ESC 2014
Exercício 2
• Implementar um programa utilizando o CMSIS- RTOS RTX que acione as 3 cores do LED
RGB da placa base em intervalos de tempo ligeiramente diferentes.
– tR = 500ms, tG = 550ms, tB = 600ms
1. Utilizar osDelay em cada tarefa.
2. Utilizar 3 tarefas independentes, uma para cada cor do LED RGB.
Exemplo:
Acesso a recurso compartilhado
Douglas Renaux – ESC 2014
<<mutex>>
Duas tarefas que
compartilham um recurso
Douglas Renaux – ESC 2014
#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) { // main thread
: // setup and initialize peripherals
osMutexId mutLCDid = osMutexCreate (osMutex(mutLCD));
osThreadCreate (osThread(job1),NULL);
osThreadCreate (osThread(job2),NULL);
}
Exemplo:
Comunicação por Mensagem
Douglas Renaux – ESC 2014
<<mutex>>
Comunicação ISR -> Tarefa
Douglas Renaux – ESC 2014
#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) { // main thread
: // setup and initialize peripherals
MsgBox = osMessageCreate(osMessageQ(MsgBox), NULL);
osThreadCreate (osThread(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.
Douglas Renaux – ESC 2014
Alocação de Memória
Douglas Renaux – ESC 2014
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());
}
CMSIS-RTOS - Temporizadores
www.arm.com
Macro de definição de temporizador: osTimerDef
Macro para acesso ao temporizador: osTimer
Tipos de dados: os_timer_type, osTimerId, osStatus
Funções: osTimerCreate, osTimerStart, osTimerStop, osTimerDelete
Função de Callback
one-shot x repetitivo
Exercício 3 - repetir com temporizadores
• Implementar um programa utilizando o CMSIS- RTOS RTX que acione as 3 cores do LED
RGB da placa base em intervalos de tempo ligeiramente diferentes.
– tR = 500ms, tG = 550ms, tB = 600ms
1. Utilizar timers do CMSIS-RTOS em cada tarefa.
2. Utilizar 3 tarefas independentes, uma para cada cor do LED RGB.
CMSIS-RTOS
www.arm.com
CMSIS-RTOS
www.arm.com
CMSIS-RTOS - Eventos
Eventos são de 3 tipos:
Sinais – um flag (setado ou resetado)
Mensagens – um int de 32 bits / ponteiro Mail – um bloco de memória
osEvent status osStatus
(osEventSignal / osEventMessage / osEventMail) value int / ptr / grupo flags
def id (do mail ou da msg)
CMSIS-RTOS - Eventos
void Thread_2 (void const *arg);
osThreadDef(Thread_2, osPriorityHigh, 1, 0);
static void EX_Signal_1 (void) { int32_t signals;
uint32_t exec;
osThreadIdthread_id;
thread_id = osThreadCreate(osThread(Thread_2), NULL);
if (thread_id == NULL) {
// Failed to create a thread.
} else {
signals = osSignalSet(thread_id, 0x00000005); // Send signals to the created thread }
}
void Thread_3 (void const *arg);
osThreadDef(Thread_3, osPriorityHigh, 1, 0);
static void EX_Signal_1 (void) { osThreadIdthread_id;
osEventevt;
thread_id = osThreadCreate(osThread(Thread_2), NULL);
if (thread_id == NULL) {
// Failed to create a thread.
} else {
// wait for a signal
evt = osSignalWait(0x01, 100); // espera pelo sinal 0x1 por até 100 ms if (evt.status== osEventSignal) {
// handle event status }
} }
ver RTX_Conf_CM.C pela def do número max de sinais
CMSIS-RTOS - Semáforos
• osSemaphore - para sincronização entre tarefas e/ou tarefa/ISR
• osMutex - para exclusão Mútua. Apenas a tarefa que fez osMutexWait pode fazer
osMutexRelease
osSemaphoreWait osSemaphoreWait
osSemaphoreRelease
Mutex
// 1 – definição da estrutura de dados do Mutex (em geral é uma variável global) osMutexDef(mut_GLCD);
// 2 – definição de um ponteiro para o Mutex (também costuma ser uma var global) osMutexId mut_lcd;
// 3 – Inicialização do Mutex (em geral na função main) mut_lcd = osMutexCreate(osMutex(mut_GLCD));
// 4 – Uso do Mutex sem timeout (a partir de uma thread) osMutexWait(mut_lcd, osWaitForever);
...
osMutexRelease(mut_lcd);
obs:
osMutex(mut_GLCD) é uma chamada de MACRO
esta chamada retorna o endereço da estrutura
Projeto – Arquitetura da Solução
Elementos que compõem a arquitetura da solução:
• objetos/classes passivas
• Tarefas (threads) – objetos/classes ativas
• Tarefas Periódicas
• Message Queue – envia
• Event Queue – envia
• Temporizador – objeto passive + callback
• Semáforos (binário, contador e mutex)
• ISR – objeto/classe ativa
Projeto - Detalhamento
O que cada Tarefa faz ?
O que cada objeto/classe faz ?
• Diagramas de Estado
• Diagramas de atividades
• Estrutura de controle de cada tarefa
• Loop infinito com temporização
• Loop infinito com recebimento de msg/evento
• Função com final de execução