menu_book Índice

Logo UFPR

Sistemas Operacionais para Dispositivos Embarcados

Logo Licenciatura

Disciplina: Práticas de Sistemas Operacionais para Dispositivos Embarcados

Universidade Federal do Paraná

Prof. Jéfer – jefer@ufpr.br

Objetivo: Explorar práticas e exemplos reais de sistemas operacionais em dispositivos embarcados, com foco em ESP32, Raspberry Pi e Arduino.

Logo UFPR

Introdução a SO para Dispositivos Embarcados

Logo Licenciatura

Dispositivos Embarcados:

  • Sistemas computacionais dedicados a funções específicas.
  • Exemplos populares:
    • ESP32: Microcontrolador com Wi-Fi e Bluetooth, amplamente usado em IoT.
    • Raspberry Pi: Computador de placa única (SBC) para projetos complexos.
    • Arduino: Plataforma de prototipagem eletrônica.
    • Raspberry Pi Pico: Microcontrolador baseado no RP2040, ideal para projetos de baixo custo.

Papel do Sistema Operacional:

  • Gerenciar recursos de hardware (CPU, memória, E/S).
  • Facilitar o desenvolvimento de aplicações.
  • Oferecer suporte a multitarefa e comunicação entre processos.
  • Exemplos de SO para embarcados:
    • FreeRTOS: Sistema operacional em tempo real para microcontroladores.
    • Zephyr: SO moderno para dispositivos IoT.
    • Linux Embarcado: Usado em placas como Raspberry Pi e BeagleBone.
    • ArdOS/Duinos: SO simples para Arduino.

Objetivo:

  • Apresentar práticas com exemplos reais em ESP32, Raspberry Pi e Arduino.
  • Explorar sistemas operacionais como FreeRTOS, Linux Embarcado e ArdOS.
  • Discutir aplicações em IoT, automação e robótica.

Placas Similares à Raspberry Pi:

  • BeagleBone Black: Placa com foco em projetos de automação e robótica.
  • Orange Pi: Alternativa de baixo custo à Raspberry Pi.
  • NVIDIA Jetson Nano: Placa com foco em IA e visão computacional.
Logo UFPR

ESP32 - FreeRTOS e Atribuição de Tarefas

Logo Licenciatura

ESP32:

  • Microcontrolador dual-core (Core 0 e Core 1) com Wi-Fi e Bluetooth.
  • Amplamente utilizado em projetos de IoT e automação.

FreeRTOS:

  • Sistema operacional em tempo real (RTOS) de código aberto.
  • Oferece gerenciamento de tarefas, filas, semáforos e temporizadores.
  • Permite multitarefa preemptiva e priorização de tarefas.

Atribuição de Tarefas:

  • É possível definir em qual núcleo uma tarefa será executada.
  • Exemplo de código para criar uma tarefa no Core 0:
  • xTaskCreatePinnedToCore(taskFunction, "TaskName", 10000, NULL, 1, NULL, 0);
  • Parâmetros:
    • taskFunction: Função que a tarefa executará.
    • "TaskName": Nome da tarefa para depuração.
    • 10000: Tamanho da pilha da tarefa.
    • 1: Prioridade da tarefa.
    • 0: Núcleo onde a tarefa será executada (0 ou 1).

Outras Funcionalidades do FreeRTOS:

  • Filas: Permitem a comunicação entre tarefas.
    xQueueSend(queueHandle, &data, portMAX_DELAY);
  • Semáforos: Usados para sincronização entre tarefas.
    xSemaphoreGive(semaphoreHandle);
  • Temporizadores: Executam tarefas em intervalos específicos.
    xTimerStart(timerHandle, portMAX_DELAY);

Exemplo Completo:

void taskFunction(void *pvParameters) {
  while (1) {
    // Código da tarefa
    vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay de 1 segundo
  }
}

void setup() {
  xTaskCreatePinnedToCore(taskFunction, "Task1", 10000, NULL, 1, NULL, 0);
}

Referência: Atribuir tarefa a um núcleo do ESP32

Logo UFPR

ESP32 - Multiprocessamento com FreeRTOS

Logo Licenciatura

Multiprocessamento no ESP32:

  • O ESP32 possui dois núcleos (Core 0 e Core 1) que podem executar tarefas simultaneamente.
  • O FreeRTOS gerencia a execução de múltiplas tarefas, permitindo multitarefa preemptiva.
  • Exemplos de aplicações:
    • Leitura de sensores em uma tarefa.
    • Comunicação Wi-Fi em outra tarefa.
    • Atualização de um display em uma terceira tarefa.
📡
Tarefa 1: Leitura de Sensor
Envia dados via Fila
Fila (Queue)
Recebe dados via Fila
📶
Tarefa 2: Comunicação Wi-Fi

Criação de Tarefas:

  • Exemplo de código para criar duas tarefas:
  • xTaskCreate(taskSensor, "SensorTask", 10000, NULL, 1, NULL);
    xTaskCreate(taskWiFi, "WiFiTask", 10000, NULL, 1, NULL);
  • Parâmetros:
    • taskSensor e taskWiFi: Funções das tarefas.
    • "SensorTask" e "WiFiTask": Nomes das tarefas para depuração.
    • 10000: Tamanho da pilha de cada tarefa.
    • 1: Prioridade das tarefas.

Comunicação entre Tarefas:

  • Filas: Permitem o envio de dados entre tarefas.
    xQueueSend(queueHandle, &data, portMAX_DELAY);
  • Semáforos: Usados para sincronização entre tarefas.
    xSemaphoreGive(semaphoreHandle);

Exemplo Completo:

QueueHandle_t queueHandle;

void taskSensor(void *pvParameters) {
  int sensorData = 0;
  while (1) {
    sensorData = readSensor(); // Simula leitura de um sensor
    xQueueSend(queueHandle, &sensorData, portMAX_DELAY);
    vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay de 1 segundo
  }
}

void taskWiFi(void *pvParameters) {
  int receivedData;
  while (1) {
    if (xQueueReceive(queueHandle, &receivedData, portMAX_DELAY)) {
      sendDataViaWiFi(receivedData); // Simula envio de dados via Wi-Fi
    }
  }
}

void setup() {
  queueHandle = xQueueCreate(10, sizeof(int));
  xTaskCreate(taskSensor, "SensorTask", 10000, NULL, 1, NULL);
  xTaskCreate(taskWiFi, "WiFiTask", 10000, NULL, 1, NULL);
}

Referência: Multiprocessamento no ESP32

Logo UFPR

ESP32 - ISR e Timers

Logo Licenciatura

ISR (Interrupções)

  • Definição: Rotinas de serviço de interrupção que respondem instantaneamente a eventos de hardware (ex.: botão pressionado, sinal de sensor).
  • Características no ESP32:
    • Executadas na RAM com atributo IRAM_ATTR para baixa latência.
    • Suporte a múltiplos pinos GPIO e fontes (rising, falling, change).
    • Podem notificar tarefas FreeRTOS via filas ou semáforos.
  • Exemplo prático: Contador de pressionamentos de botão.
    
    volatile int counter = 0;
    void IRAM_ATTR buttonISR() {
      counter++; // Incrementa contador na interrupção
    }
    void setup() {
      pinMode(4, INPUT_PULLUP); // GPIO 4 com pull-up interno
      attachInterrupt(digitalPinToInterrupt(4), buttonISR, FALLING);
    }
    void loop() {
      Serial.printf("Botão pressionado %d vezes\n", counter);
      delay(1000);
    }
            

Timers

  • Definição: Mecanismos para executar tarefas em intervalos regulares ou após atrasos específicos.
  • Tipos no ESP32:
    • Timers de hardware: 4 timers de 64 bits (grupos 0 e 1).
    • Timers FreeRTOS: Software via xTimerCreate, mais flexíveis.
  • Exemplo prático: Piscar LED a cada 500ms com FreeRTOS.
    
    #include 
    #include 
    #include 
    
    TimerHandle_t ledTimer;
    int ledPin = 2;
    
    void timerCallback(TimerHandle_t xTimer) {
      digitalWrite(ledPin, !digitalRead(ledPin)); // Alterna LED
    }
    
    void setup() {
      pinMode(ledPin, OUTPUT);
      ledTimer = xTimerCreate("LEDTimer", pdMS_TO_TICKS(500), pdTRUE, NULL, timerCallback);
      xTimerStart(ledTimer, 0);
    }
    
    void loop() {
      // Loop vazio; tudo gerenciado por FreeRTOS
    }
            

Fonte: ISR – Interrupções e Timer com ESP32

Logo UFPR

FreeRTOS - Conceitos Avançados

Logo Licenciatura

Filas (Queues)

  • Definição: Estruturas para comunicação assíncrona entre tarefas ou entre ISR e tarefas.
  • Características:
    • Tamanho fixo (definido na criação).
    • Suporta bloqueio com timeout (ex.: portMAX_DELAY).
    • Tipos de dados: Inteiros, structs, ponteiros.
  • Exemplo prático: Enviar leitura de sensor entre tarefas.
    
    QueueHandle_t sensorQueue;
    
    void sensorTask(void *pvParameters) {
      int sensorData = 0;
      while (1) {
        sensorData = analogRead(34); // Leitura do pino 34
        xQueueSend(sensorQueue, &sensorData, portMAX_DELAY);
        vTaskDelay(pdMS_TO_TICKS(1000)); // 1s
      }
    }
    
    void displayTask(void *pvParameters) {
      int receivedData;
      while (1) {
        if (xQueueReceive(sensorQueue, &receivedData, portMAX_DELAY)) {
          Serial.printf("Sensor: %d\n", receivedData);
        }
      }
    }
    
    void setup() {
      sensorQueue = xQueueCreate(10, sizeof(int)); // Fila para 10 inteiros
      xTaskCreate(sensorTask, "Sensor", 2048, NULL, 1, NULL);
      xTaskCreate(displayTask, "Display", 2048, NULL, 1, NULL);
    }
            

Semáforos (Semaphores)

  • Definição: Mecanismos de sincronização para gerenciar acesso a recursos compartilhados ou sinalizar eventos.
  • Tipos:
    • Binário: Sinaliza eventos (ex.: tarefa concluída).
    • Contador: Controla múltiplos acessos (ex.: buffer).
    • Mutex: Proteção contra acesso concorrente.
  • Exemplo prático: Proteger acesso a um LED compartilhado.
    
    SemaphoreHandle_t ledMutex;
    
    void task1(void *pvParameters) {
      while (1) {
        if (xSemaphoreTake(ledMutex, portMAX_DELAY)) {
          digitalWrite(2, HIGH);
          vTaskDelay(pdMS_TO_TICKS(500));
          digitalWrite(2, LOW);
          xSemaphoreGive(ledMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
      }
    }
    
    void setup() {
      ledMutex = xSemaphoreCreateMutex();
      pinMode(2, OUTPUT);
      xTaskCreate(task1, "Task1", 2048, NULL, 1, NULL);
      xTaskCreate(task1, "Task2", 2048, NULL, 1, NULL); // Mesmo código, outra instância
    }
            

Temporizadores (Timers)

  • Definição: Timers de software para executar callbacks em intervalos ou uma única vez.
  • Características:
    • Criação com xTimerCreate: Nome, período, auto-reload.
    • Controle: xTimerStart, xTimerStop, xTimerReset.
  • Exemplo prático: Log periódico de status.
    
    TimerHandle_t statusTimer;
    
    void statusCallback(TimerHandle_t xTimer) {
      Serial.println("Status: Sistema OK");
    }
    
    void setup() {
      Serial.begin(115200);
      statusTimer = xTimerCreate("StatusTimer", pdMS_TO_TICKS(2000), pdTRUE, NULL, statusCallback);
      if (statusTimer != NULL) {
        xTimerStart(statusTimer, portMAX_DELAY);
      }
    }
            
Logo UFPR

Raspberry Pi e Pico - Instalação de SO e Frameworks

Logo Licenciatura

Raspberry Pi (Modelos Tradicionais)

  • Sistemas Disponíveis:
    • Raspberry Pi OS: Base Debian, otimizado para RPi.
    • Ubuntu Mate: Interface desktop completa.
    • Outros SOs:
  • Download Oficial:
  • Instalação no SD Card:
    • Ferramenta: dd (Linux/macOS) ou Raspberry Pi Imager.
    • Exemplo com dd:
      
      sudo dd bs=4M if=raspberry-pi-os.img of=/dev/sdc status=progress
      sync
                  
    • Dica: Use lsblk para confirmar o dispositivo (/dev/sdc).
  • Diagrama de Instalação:
    • [Download da Imagem] → [Gravação no SD com dd ou Imager] → [Inserir SD no RPi] → [Boot do Sistema]

Raspberry Pi Pico

  • Características:
    • Microcontrolador RP2040: Dual-core ARM Cortex-M0+, 133 MHz, 264 KB SRAM.
    • Não suporta SOs completos; usa frameworks leves.
  • Sistemas/Frameworks Disponíveis:
  • Instalação e Exemplos:
    • MicroPython:
      • Download: rp2-pico-latest.uf2.
      • Processo: Pressione BOOTSEL, conecte USB, copie .uf2 para RPI-RP2.
      • Exemplo - Piscar LED:
        
        from machine import Pin
        import time
        led = Pin(25, Pin.OUT) # LED onboard
        while True:
            led.toggle()
            time.sleep(0.5)
                        
    • CircuitPython:
      • Download: .uf2 do site CircuitPython.
      • Processo: Mesmo que MicroPython; copia para RPI-RP2.
      • Exemplo - Ler Botão e Acender LED:
        
        import board
        import digitalio
        import time
        led = digitalio.DigitalInOut(board.LED)
        led.direction = digitalio.Direction.OUTPUT
        button = digitalio.DigitalInOut(board.GP15)
        button.direction = digitalio.Direction.INPUT
        while True:
            led.value = button.value
            time.sleep(0.1)
                        
    • Arduino Core:
      • Instalação: Adicionar URL no Arduino IDE (Preferences > Additional Boards Manager URLs: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json), instalar "Raspberry Pi Pico/RP2040".
      • Exemplo - Piscar LED com Delay:
        
        #define LED_PIN 25
        void setup() {
          pinMode(LED_PIN, OUTPUT);
        }
        void loop() {
          digitalWrite(LED_PIN, HIGH);
          delay(500);
          digitalWrite(LED_PIN, LOW);
          delay(500);
        }
                        
  • Diagrama de Instalação:
    • [Download do .uf2] → [Pressionar BOOTSEL e Conectar USB] → [Copiar .uf2 para RPI-RP2] → [Pico Reinicia e Executa]
Logo UFPR

Raspberry Pi - Aplicações Práticas

Logo Licenciatura

Urna Eletrônica

  • Descrição: Simulação de uma urna eletrônica com interface gráfica, ideal para ensino de sistemas embarcados.
  • Tecnologias:
    • Raspberry Pi (qualquer modelo, ex.: RPi 4).
    • SO: Raspberry Pi OS.
    • Framework: Qt5 para GUI interativa.
  • Funcionalidades:
    • Registro e contagem de votos.
    • Exibição em display (ex.: touchscreen).
  • Exemplo Prático: Código básico em Qt5/C++ para botão de votação.
    
    #include 
    #include 
    
    int main(int argc, char *argv[]) {
      QApplication app(argc, argv);
      QPushButton button("Votar");
      button.show();
      QObject::connect(&button, &QPushButton::clicked, []() {
        qDebug() << "Voto registrado!";
      });
      return app.exec();
    }
            
  • Fonte: Embarcados - Urna Eletrônica

Retrogaming com Recalbox

  • Descrição: Sistema operacional especializado em emulação de jogos clássicos.
  • Requisitos:
    • Raspberry Pi (recomendado: RPi 3 ou 4).
    • Cartão SD (mínimo 16 GB).
    • Controles USB ou Bluetooth.
  • Funcionalidades:
    • Emulação de consoles: NES, SNES, Mega Drive, PS1.
    • Interface gráfica amigável.
    • Suporte a ROMs e save states.
  • Instalação:
    • Download da imagem em Recalbox.
    • Gravar no SD com Raspberry Pi Imager.
  • Exemplo Prático: Configurar um controle USB via interface web do Recalbox.

Servidor IoT com Node-RED

  • Descrição: Plataforma para automação e monitoramento via Raspberry Pi.
  • Tecnologias:
    • Raspberry Pi OS com Node.js instalado.
    • Node-RED: Ferramenta de programação visual.
  • Funcionalidades:
    • Conexão com sensores (ex.: DHT22 via GPIO).
    • Dashboard web para monitoramento.
  • Exemplo Prático: Fluxo básico no Node-RED.
    • Instalar: sudo apt install nodered
    • Iniciar: node-red-start
    • Acessar: http://:1880
    • Exemplo: Nó "inject" → Nó "debug" para teste simples.
Logo UFPR

Arduino - Sistemas Operacionais

Logo Licenciatura

Contexto Geral

  • Arduino Tradicional:
    • Opera em "bare-metal" (sem SO), com loop único.
    • Limitações: 2 KB RAM e 32 KB Flash no Uno; 8 KB RAM e 256 KB Flash no Mega.
    • SOs viáveis em modelos potentes (Mega, Due, Zero).

Sistemas Operacionais Específicos

  • Duinos:
    • Descrição: SO experimental para multitarefa simples.
    • Exemplo: Piscar LEDs em paralelo.
      
      #include 
      void task1() { while(1) { digitalWrite(13, !digitalRead(13)); delay(500); } }
      void task2() { while(1) { digitalWrite(12, !digitalRead(12)); delay(1000); } }
      void setup() {
        pinMode(13, OUTPUT);
        pinMode(12, OUTPUT);
        task_create(task1);
        task_create(task2);
      }
                  
    • Download: Duinos (Arquivado, 2013).
  • ArdOS:
    • Descrição: SO leve com escalonamento preemptivo.
    • Exemplo: Tarefa com semáforo.
      
      #include 
      OS_SEMAPHORE sem;
      void task1(void *p) {
        while (1) {
          os_sema_take(&sem);
          digitalWrite(13, HIGH);
          os_delay(500);
          digitalWrite(13, LOW);
          os_sema_give(&sem);
        }
      }
      void setup() {
        pinMode(13, OUTPUT);
        os_init();
        os_sema_init(&sem, 1);
        os_task_create(task1, NULL, 100);
        os_start();
      }
                  
    • Documentação: ArdOS Wiki.

Alternativas: FreeRTOS no Arduino

  • Descrição: Biblioteca RTOS robusta para Arduino.
  • Exemplo Simples: Piscar LED.
    
    #include 
    void blinkTask(void *pvParameters) {
      pinMode(13, OUTPUT);
      while (1) {
        digitalWrite(13, HIGH);
        vTaskDelay(500 / portTICK_PERIOD_MS);
        digitalWrite(13, LOW);
        vTaskDelay(500 / portTICK_PERIOD_MS);
      }
    }
    void setup() {
      xTaskCreate(blinkTask, "Blink", 128, NULL, 1, NULL);
      vTaskStartScheduler();
    }
    void loop() {}
            
  • Exemplo Complexo: Sensor e display com fila.
    
    #include 
    #include 
    QueueHandle_t sensorQueue;
    
    void sensorTask(void *pvParameters) {
      while (1) {
        int value = analogRead(A0);
        xQueueSend(sensorQueue, &value, portMAX_DELAY);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
    
    void displayTask(void *pvParameters) {
      int receivedValue;
      while (1) {
        if (xQueueReceive(sensorQueue, &receivedValue, portMAX_DELAY)) {
          Serial.print("Valor do sensor: ");
          Serial.println(receivedValue);
        }
      }
    }
    
    void setup() {
      Serial.begin(115200);
      sensorQueue = xQueueCreate(5, sizeof(int));
      xTaskCreate(sensorTask, "Sensor", 128, NULL, 1, NULL);
      xTaskCreate(displayTask, "Display", 128, NULL, 1, NULL);
      vTaskStartScheduler();
    }
    void loop() {}
            
  • Download: Arduino FreeRTOS.

Comparação entre SOs

SO Recursos Suporte Facilidade Compatibilidade
Duinos Multitarefa básica Arquivado (2013) Média Uno, Mega
ArdOS Multitarefa, semáforos Em desenvolvimento Média Mega, Due
FreeRTOS Filas, semáforos, timers Ativo, comunidade forte Alta (com docs) Uno, Mega, Due, Zero

Detalhes Técnicos

  • Limitações de Hardware:
    • Uno: 2 KB RAM, 32 KB Flash - SOs consomem ~1 KB RAM.
    • Mega: 8 KB RAM, 256 KB Flash - Melhor para SOs.
    • Due: 96 KB RAM, 512 KB Flash - Ideal para FreeRTOS.
  • Compatibilidade:
    • Duinos: Limitado a AVR (Uno, Mega).
    • ArdOS: AVR e SAM (Mega, Due).
    • FreeRTOS: AVR, SAM, ESP (Uno, Mega, Due, ESP8266).
Logo UFPR

Conclusão

Logo Licenciatura

Resumo

  • Conceito Central: Sistemas operacionais embarcados otimizam dispositivos com recursos limitados (CPU, RAM, energia), oferecendo multitarefa e controle eficiente.
  • Abordagem:
    • ESP32: FreeRTOS para tarefas em núcleos duplos, ISR e timers.
    • Raspberry Pi: SOs completos (RPi OS, Ubuntu) e aplicações práticas (urna, retrogaming).
    • Raspberry Pi Pico: Frameworks leves (MicroPython, CircuitPython).
    • Arduino: SOs experimentais (Duinos, ArdOS) e FreeRTOS.
  • Exemplo Integrado: Um ESP32 monitorando sensores via FreeRTOS pode enviar dados a um Raspberry Pi rodando Node-RED para visualização.

Destaques

  • ESP32 com FreeRTOS:
    • Multiprocessamento em dois núcleos (ex.: sensor e Wi-Fi em paralelo).
    • Filas e semáforos para sincronização avançada.
  • Raspberry Pi:
    • Flexibilidade com SOs (ex.: Recalbox para jogos, Qt5 para urnas).
    • Instalação simples via SD (ex.: dd ou Imager).
  • Raspberry Pi Pico:
    • Frameworks como MicroPython permitem programação rápida (ex.: piscar LED em 5 linhas).
  • Arduino:
    • FreeRTOS como solução robusta vs. SOs experimentais limitados (ex.: Duinos obsoleto).

Perspectivas Futuras

  • Integração com IoT:
    • Dispositivos como ESP32 e RPi formarão redes inteligentes (ex.: casas conectadas).
    • SOs leves evoluirão para suportar MQTT e protocolos 5G.
  • Edge Computing:
    • Processamento local em embarcados reduz latência (ex.: RPi analisando dados de sensores).
    • FreeRTOS e frameworks como TensorFlow Lite para IA embarcada.
  • Evolução de SOs Leves:
    • MicroPython e CircuitPython ganharão mais bibliotecas (ex.: suporte a BLE).
    • Novos RTOS otimizados para ARM Cortex (ex.: Zephyr, RIOT).
  • Exemplo Futuro: Uma rede de Picos coletando dados ambientais, processada por um RPi com IA, coordenada por ESP32 via Wi-Fi.
Logo UFPR

Adicionais sobre FreeRTOS

Logo Licenciatura

Gerenciamento de Memória

  • Conceito: FreeRTOS oferece esquemas de alocação dinâmica para tarefas, filas e outros objetos.
  • Esquemas Disponíveis:
    • heap_1: Apenas alocação, sem liberação (leve, para sistemas estáticos).
    • heap_2: Alocação e liberação, mas sem coalescência (obsoleto).
    • heap_4: Alocação/liberação com coalescência, ideal para sistemas dinâmicos.
    • heap_5: Suporte a múltiplas regiões de memória (ex.: SRAM externa).
  • Exemplo Prático: Configurar heap_4 no ESP32.
    • Arquivo: FreeRTOSConfig.h
    • Linha: #define configMEM_MANGEMENT heap_4
    • Uso: xTaskCreate aloca memória dinamicamente.

Prioridades de Tarefas

  • Conceito: Escalonamento preemptivo baseado em prioridades (0 a configMAX_PRIORITIES - 1).
  • Funcionamento:
    • Tarefa de maior prioridade executa primeiro.
    • Igual prioridade: Round-robin (compartilhamento de tempo).
    • Configurável via configMAX_PRIORITIES (ex.: 5 ou 32).
  • Exemplo Prático: Tarefa crítica vs. secundária.
    
    void criticalTask(void *pvParameters) {
      while (1) {
        Serial.println("Tarefa Crítica");
        vTaskDelay(500 / portTICK_PERIOD_MS);
      }
    }
    void secondaryTask(void *pvParameters) {
      while (1) {
        Serial.println("Tarefa Secundária");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
    void setup() {
      Serial.begin(115200);
      xTaskCreate(criticalTask, "Critical", 2048, NULL, 2, NULL); // Prioridade alta
      xTaskCreate(secondaryTask, "Secondary", 2048, NULL, 1, NULL); // Prioridade baixa
      vTaskStartScheduler();
    }
            

Sincronização

  • Conceito: Ferramentas para gerenciar recursos compartilhados e evitar condições de corrida.
  • Mecanismos:
    • Mutexes: Proteção de exclusão mútua (xSemaphoreCreateMutex).
    • Semáforos Binários: Sinalização de eventos (xSemaphoreCreateBinary).
    • Semáforos Contadores: Controle de múltiplos acessos.
  • Exemplo Prático: Mutex para proteger Serial.
    
    SemaphoreHandle_t serialMutex;
    void task1(void *pvParameters) {
      while (1) {
        if (xSemaphoreTake(serialMutex, portMAX_DELAY)) {
          Serial.println("Task 1 usa Serial");
          xSemaphoreGive(serialMutex);
        }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
    void task2(void *pvParameters) {
      while (1) {
        if (xSemaphoreTake(serialMutex, portMAX_DELAY)) {
          Serial.println("Task 2 usa Serial");
          xSemaphoreGive(serialMutex);
        }
        vTaskDelay(1500 / portTICK_PERIOD_MS);
      }
    }
    void setup() {
      Serial.begin(115200);
      serialMutex = xSemaphoreCreateMutex();
      xTaskCreate(task1, "Task1", 2048, NULL, 1, NULL);
      xTaskCreate(task2, "Task2", 2048, NULL, 1, NULL);
      vTaskStartScheduler();
    }
            

Exemplo Completo

  • Descrição: Produtor/Consumidor com fila e prioridades.
  • Código:
    
    #include 
    #include 
    
    QueueHandle_t queueHandle;
    SemaphoreHandle_t printMutex;
    
    void producerTask(void *pvParameters) {
      int data = 0;
      while (1) {
        xQueueSend(queueHandle, &data, portMAX_DELAY);
        data++;
        vTaskDelay(1000 / portTICK_PERIOD_MS);
      }
    }
    
    void consumerTask(void *pvParameters) {
      int data;
      while (1) {
        if (xQueueReceive(queueHandle, &data, portMAX_DELAY)) {
          if (xSemaphoreTake(printMutex, portMAX_DELAY)) {
            Serial.print("Consumidor recebeu: ");
            Serial.println(data);
            xSemaphoreGive(printMutex);
          }
        }
      }
    }
    
    void setup() {
      Serial.begin(115200);
      queueHandle = xQueueCreate(10, sizeof(int));
      printMutex = xSemaphoreCreateMutex();
      xTaskCreate(producerTask, "Producer", 2048, NULL, 1, NULL);
      xTaskCreate(consumerTask, "Consumer", 2048, NULL, 2, NULL); // Prioridade maior
      vTaskStartScheduler();
    }
    void loop() {}
            
  • Explicação: Produtor envia dados a cada 1s; Consumidor, com maior prioridade, exibe usando mutex para proteger Serial.
Logo UFPR

Quiz de Múltipla Escolha

Logo Licenciatura

Responda as seguintes questões:

Logo UFPR

Perguntas Descritivas

Logo Licenciatura

Responda as seguintes questões:

1. Explique a diferença entre a atribuição de tarefas a um núcleo e o multiprocessamento no ESP32.

A atribuição de tarefas a um núcleo no ESP32, feita com xTaskCreatePinnedToCore, fixa uma tarefa a um núcleo específico (PRO_CPU ou APP_CPU), garantindo controle manual sobre a execução. Já o multiprocessamento aproveita os dois núcleos para executar tarefas simultaneamente, com o FreeRTOS balanceando automaticamente (sem afinidade) ou seguindo atribuições fixas, otimizando desempenho em aplicações complexas como IoT.

2. Quais os principais benefícios de utilizar FreeRTOS em dispositivos embarcados?

O FreeRTOS oferece multitarefa com escalonamento preemptivo, sincronização via filas, semáforos e mutexes, e suporte a prioridades, permitindo respostas em tempo real. Além disso, sua leveza (ocupa ~10 KB Flash) e portabilidade (ex.: ESP32, Arduino) o tornam ideal para gerenciar recursos limitados, como em sensores IoT ou controles industriais.

3. Como a instalação de um sistema operacional na Raspberry Pi contribui para aplicações práticas?

A instalação de um SO como Raspberry Pi OS ou Ubuntu Mate transforma a RPi em uma plataforma versátil, suportando interfaces gráficas (ex.: urna com Qt5), emulação (ex.: Recalbox para retrogaming) e servidores IoT (ex.: Node-RED). A gravação no SD com dd ou Imager permite personalização, habilitando conectividade (Wi-Fi, SSH) e processamento local.

4. Quais desafios o Arduino enfrenta ao utilizar um sistema operacional, e como iniciativas como Duinos e ArdOS ajudam?

O Arduino enfrenta desafios como RAM limitada (2 KB no Uno) e ausência de multitarefa nativa, dificultando aplicações complexas. Duinos oferece multitarefa básica para modelos como Uno e Mega, enquanto ArdOS adiciona escalonamento preemptivo e semáforos, especialmente em Mega e Due. Contudo, ambos são limitados frente ao FreeRTOS, que é mais robusto.

5. Qual a diferença entre instalar um SO completo na Raspberry Pi e um framework como MicroPython na Raspberry Pi Pico?

Um SO completo na Raspberry Pi (ex.: RPi OS) suporta um sistema operacional inteiro com kernel, drivers e GUI, ideal para aplicações robustas como retrogaming ou servidores, instalado via SD. Já o MicroPython na Pico é um framework leve, instalado como firmware (.uf2), focado em microcontroladores com recursos limitados (264 KB SRAM), perfeito para tarefas simples como controlar LEDs ou sensores.

6. Explique como o gerenciamento de memória no FreeRTOS pode impactar o desempenho de um sistema embarcado.

O FreeRTOS oferece esquemas como heap_1 (estático, sem liberação) e heap_4 (dinâmico com coalescência), afetando o uso de RAM. Heap_1 é leve mas inflexível, ideal para sistemas fixos, enquanto heap_4 reduz fragmentação, mas consome mais processamento. Escolher o esquema errado pode levar a falhas (ex.: estouro de RAM no ESP32) ou lentidão em tarefas dinâmicas.

7. Como uma aplicação prática como o Node-RED na Raspberry Pi pode se beneficiar de um sistema operacional embarcado?

O Node-RED, rodando em um SO como Raspberry Pi OS, aproveita o sistema de arquivos, conectividade (Wi-Fi, Ethernet) e bibliotecas (ex.: Node.js) para criar fluxos IoT, como monitoramento de sensores via GPIO. O SO gerencia recursos (CPU, RAM), permitindo dashboards web e integração com MQTT, algo inviável sem um sistema operacional completo.

8. Quais são as vantagens de integrar dispositivos embarcados como ESP32 e Raspberry Pi em projetos de edge computing?

A integração de ESP32 (com FreeRTOS para tempo real) e Raspberry Pi (com SO para processamento) em edge computing reduz latência ao processar dados localmente (ex.: análise de sensores ambientais). O ESP32 coleta dados rapidamente, enquanto a RPi executa IA (ex.: TensorFlow Lite), diminuindo dependência de nuvem e otimizando largura de banda.