Table of Contents
Introduzione: Il ruolo dei sistemi operativi in tempo reale nel design incorporato
I sistemi incorporati richiedono sempre più l'esecuzione prevedibile, la bassa latenza e la gestione concomitante di eventi multipli. Un sistema operativo in tempo reale (RTOS) fornisce il framework per soddisfare queste esigenze senza costringere gli sviluppatori a costruire la logica di programmazione da zero. Tra le opzioni disponibili, FreeRTOS si distingue come un kernel leggero e open source che è diventato la scelta di fatto per i microcontroller (MCU) e piccole applicazioni di processori.
Questo articolo si espande sulla guida originale di FreeRTOS, immergendosi più a fondo nella sua architettura, configurazione, gestione delle attività, meccanismi di sincronizzazione e funzionalità avanzate.
Cos'è FreeRTOS?
FreeRTOS è un kernel di sistema operativo in tempo reale leader di mercato progettato specificamente per i sistemi incorporati. È stato creato da Richard Barry ed è ora mantenuto sotto l'ombrello Amazon Web Services (AWS) FreeRTOS, garantendo il supporto e l'allineamento continuo con gli ecosistemi Internet of Things (IoT) . Il kernel fornisce multitasking preemptive, comunicazione inter-task, primitivi di sincronizzazione e timer software pochi, il tutto richiedendo solo pochi.
Gli attributi chiave che rendono FreeRTOS così ampiamente adottato includono:
- Apri fonte sotto licenza MIT:[] Nessuna commissione di licenza, disponibilità di codice sorgente completo e uso permissivo nei prodotti commerciali.
- Portabilità:[] Porte ufficiali per decine di architetture MCU (ARM Cortex-M, RISC‐V, AVR, PIC, ecc.) e portautensili (GCC, IAR, Keil, LLVM).
- Ingombro minimo:[] Il kernel può funzionare fino a 4 KB di ROM e 1 KB di RAM, rendendolo adatto per dispositivi sensibili ai costi.
- Comportamento deterministico:[] La sovraccarica Scheduling è costante e indipendente dal numero di compiti, garantendo tempi prevedibili.
- Active community and commercial support:[ Ampia documentazione, forum e servizi professionali del team e dei partner FreeRTOS.
FreeRTOS è spesso il primo incontro di ingegneri RTOS, e i suoi concetti mappano direttamente a sistemi più complessi, rendendolo un'eccellente piattaforma di apprendimento e una fondazione pronta alla produzione.
Concetti core e oggetti Kernel
Prima di immergersi in passaggi pratici, è essenziale capire i blocchi fondamentali di costruzione FreeRTOS fornisce.
Compiti
Le attività sono filetti indipendenti di esecuzione che condividono il tempo della CPU secondo un programmatore preento basato sulla priorità. Ogni compito ha il proprio stack e contesto. FreeRTOS supporta un numero illimitato di attività (limitato solo dalla memoria disponibile).
Queues
Le code consentono di trasmettere messaggi tra le attività e tra interrotti e compiti, sono il meccanismo primario per la comunicazione inter-task. Le code FreeRTOS sono FIFO o LIFO (quest'ultimo tramite ]][]]]) e possono contenere elementi dati a dimensione fissa.
Semafori e Mutexe
FreeRTOS offre semafori binari, conteggio semafori e mutexe. Semafori binari agiscono come semplici bandiere utilizzate per segnalare o sincronizzare le attività (ad esempio, notifica che si è verificato un interruzione). Conteggio semafori gestire più risorse, mentre i mutexe forniscono l'esclusione reciproca con un meccanismo di ereditarietà prioritario integrato per prevenire l'inversione di priorità.
Timer software
Il kernel fornisce timer software che eseguono una funzione di callback quando un periodo passa. I timer possono essere one-shot (fire una volta) o auto-ricarica. Essi vengono eseguiti in un'attività di servizio timer dedicata, in modo che i loro gestori devono essere brevi e non-bloccanti.
Gruppi di eventi
I gruppi di eventi permettono di attendere una combinazione di bit multipli (eventi) da impostare, semplificando gli scenari in cui un'azione dipende da diverse condizioni asincrona, come le letture dei sensori e una pressione del pulsante dell'utente.
Iniziare con FreeRTOS
L'adozione di FreeRTOS richiede la valutazione dell'hardware di destinazione, l'ottenimento della sorgente del kernel e la configurazione per soddisfare i vincoli della tua applicazione.
Scegliere un Microcontroller compatibile
Conferma che il dispositivo scelto ha abbastanza RAM e flash per il kernel più le tue attività. Ad esempio, un ARM Cortex-M0+ con 16 KB RAM può eseguire comodamente alcuni compiti, mentre un Cortex-M4 con 256 KB RAM supporta molti. Controllare la pagina ufficiale della porta FreeRTOS o SDK del tuo fornitore di silicio per esempi pre-integrati.
Scaricare e integrare il Kernel
L'ultimo codice sorgente di FreeRTOS è disponibile dal sito ufficiale FreeRTOS[]] o tramite GitHub. La distribuzione include il kernel core ([), i file a layer portatili (]) e i progetti demo. Per un avvio efficiente, copiare il [[FIO:3] e l'apposita directory portatile nel vostro albero di progetto.
Configurazione: Il File
Tutto il comportamento del kernel è controllato attraverso ]. Ottenere queste impostazioni a destra è fondamentale sia per le prestazioni che per la stabilità.
- :[]] Impostare a 1 per la pianificazione preventiva (tipico per applicazioni in tempo reale).
- :[] La frequenza attuale dell'orologio della CPU (utilizzata dal kernel per la corretta tempistica).
- :[]] La frequenza del timer di sistema si interrompe. I valori comuni sono 100 Hz (10 ms tick) o 1000 Hz (1 ms tick).
- :[] Totale della RAM disponibile per l'allocazione dinamica della memoria (utilizzata da ]).
- :[] La dimensione dello stack (in parole) per l'attività inattivo e il default per le nuove attività se non specificato.
- ]:[ Lunghezza massima dei nomi delle mansioni leggibili dall'uomo (aiuta a debug).
- :[]] Impostare a 1 per contatori di zecca a 16 bit (savese RAM ma limita il valore massimo di zecca a 65535 – non consigliato per sistemi di velocità a lungo termine o ad alto tick).
Inoltre, scegliere un sistema di gestione del mucchio tramite [ e ]. Il kernel include cinque implementazioni di mucchio (sapone 1 a heap 5) con diversi trade-off nella frammentazione, velocità di allocazione e determinismo. La maggior parte delle applicazioni utilizzano (primo premio con carbonizzazione) o (multiple regioni di memoria non-contattive).
Creazione e gestione del ciclo di vita
La creazione di compiti è semplice, ma i dettagli di dimensionamento stack, priorità e transizioni statali influiscono profondamente sull'affidabilità del sistema.
Usando
Un compito è creato definendo una funzione che non ritorna mai (un loop è tipico) e chiamando :
TaskHandle_t xHandle;
xTaskCreate(
vTaskFunction, // Task function pointer
"MyTask", // Name for debugging
configMINIMAL_STACK_SIZE, // Stack size in words
NULL, // Parameters passed to task
2, // Priority (higher number = higher priority)
&xHandle // Optional task handle
);
La funzione dovrebbe inizializzare qualsiasi periferica necessaria e poi entrare nel suo anello infinito, eseguendo il suo lavoro, dormire, o in attesa di eventi.
Priorità delle attività e Programmatore
FreeRTOS supporta le priorità da 0 (lowest) a (più alto). L'attività inattivo viene eseguita in priorità 0. Il programmatore preentivo eseguirà sempre la massima priorità in funzione. Se due compiti condividono la stessa priorità, il tempo-slice (round-robin) con una durata pari a un periodo di tick.
Stati membri
Ogni compito esiste in uno di questi stati:
- Running:[] L'attività sta attualmente eseguendo (solo un compito per core della CPU).
- Leggi:] Il compito è in grado di funzionare ma è attualmente in esecuzione un compito di priorità superiore o di pari priorità.
- Blocked:[] L'attività è in attesa di un evento (tempo, messaggio di coda, semaforo, ecc.).
- Sospeso:[] L'attività viene rimossa dalla lista pronta del programmatore, in genere tramite .
Il blocco è il meccanismo primario per un utilizzo efficiente della CPU: invece di inquinare, un'attività aspetta semplicemente una condizione, permettendo di eseguire operazioni di priorità inferiore.
Protezione per la dimensionamento e la sovratensione
Una delle fonti più comuni di bug FreeRTOS è il overflow di stack. Il kernel fornisce due controlli facoltativi: [. Quando abilitato, può rilevare i overflow al momento dell'interruttore di contesto.
Allocazione statica (utilizzando ]) offre un maggior controllo permettendo di fornire il buffer stack da soli, che evita la frammentazione del mucchio e consente il posizionamento in specifiche regioni di memoria (ad esempio, la memoria strettamente accoppiata per le attività in tempo reale).
Sincronizzazione e comunicazione Inter‐Task
Le attività raramente funzionano in isolamento; devono coordinare e scambiare dati. FreeRTOS fornisce diversi meccanismi, ciascuno adatto a particolari modelli.
Per il passaggio dei dati
Utilizzare le code per inviare dati da un'attività (o interrompere) ad un'altra. La coda memorizza un numero fisso di elementi di una data dimensione. Ad esempio, un'attività di lettura del sensore potrebbe inviare ] campioni a un'attività di registrazione. L'API è semplice:
- – invia l'oggetto da un'attività (blocca se piena).
- – ricevere l'oggetto (blocco se vuoto).
- Versioni ISR-safe: e .
Controllare sempre i valori di ritorno; una coda può essere piena o la chiamata può time out. In ISRs, un o []] ritorno indica se è necessario un interruttore di contesto.
Semafori binari come Segnali semplici
I semafori binari sono ideali per segnalare un compito che si è verificato un evento. Ad esempio, un interruzione GPIO può “dare” un semaforo, e un compito di attesa può “prenderlo” e elaborare l’evento. Questo decouples interrompe le routine di servizio (ISR) dalla logica di applicazione. L’ISSR usa ; il compito usa in un loop.
Mutexe con integrità prioritaria
Quando più compiti si accede ad una risorsa condivisa (ad esempio, un UART o una struttura dati), utilizzare un mutex invece di un semaforo binario. I Mutexe includono un meccanismo di ereditarietà prioritario che aumenta temporaneamente la priorità del compito tenendo la serratura alla massima priorità di qualsiasi attività di attesa.
Contare Semaphores per la gestione delle risorse
Per esempio, un pool di cinque canali DMA può essere gestito con un semaforo di conteggio inizializzato a 5. Un compito “prende” un semaforo per acquisire un canale e “darlo” indietro quando fatto.
Gruppi di eventi per la sincronizzazione multi-condizione
Se un'attività deve attendere fino a che non si siano verificati diversi eventi indipendenti, i gruppi di eventi sono più efficienti di semafori multipli. I bit sono impostati da attività o ISR, e l'attività di attesa può specificare una maschera di bit e se tutto o qualsiasi deve essere impostato. L'API include , , e le loro controparti ISR.
Gestione interrotta: Lavorazione differita
Uno dei modelli più importanti di FreeRTOS è quello di mantenere gli ISR estremamente brevi, invece di eseguire processi complessi all'interno di un interruzione, utilizzare il seguente approccio:
- All'interno dell'ISR, raccogliere dati minimi e segnalare un'attività (tramite semaforo, coda o notifica dell'attività).
- Sblocca il compito, che corre ad una normale priorità per eseguire il sollevamento pesante.
- Utilizzare le versioni “FromISR” delle chiamate API FreeRTOS ([[, [, ecc.) e controllare il parametro []. Se l'attività sbloccata ha una priorità maggiore rispetto al compito interrotto, viene richiesto un interruttore di contesto.
FreeRTOS supporta anche la nidificazione degli interruttori, ma è necessario assicurarsi che i livelli di priorità di interruzione siano configurati correttamente, per ARM Cortex‐M, il kernel richiede che il livello di priorità più alto accessibile all'utente sia utilizzato per il timer di zecca e qualsiasi ISR di riferimento API.
Migliori Pratiche per applicazioni FreeRTOS Produttive
Oltre all'uso di base, diverse pratiche separano un sistema stabile da un fragile.
Gestione della memoria
heap 4] è generalmente un buon default perché si fonde con blocchi liberi adiacenti. Se la vostra applicazione crea e elimina frequentemente le attività o le code, evita heap 2]] (nessun carbonescing) come porta alla frammentazione.
Controllare l'utilizzo del mucchio usando e . Assicurarsi che [] è abbastanza grande da ospitare le allocazioni dei casi peggiori.
Strategia di assegnazione prioritaria
Assegna priorità in base alla scadenza e alla criticità di ogni compito.
- Più alta priorità:[ loop di controllo critico temporale (ad esempio, PID motore, elaborazione audio).
- Presunzione media:[] Acquisizione periodica dei dati con requisiti di latenza moderata.
- Primonibilità bassa:[] Attività di sfondo, aggiornamenti dell'interfaccia utente, registrazione.
Evitare di avere più compiti con la stessa priorità se tutti hanno bisogno di scadenze sode, perché il tempo-slicing può introdurre ingiustizia.
Ottimizzazione di potere: Senza problemi
FreeRTOS supporta una modalità instancabile di idle che ferma il periodico interruzione di zecca quando il sistema è inattivo e tutte le attività sono bloccate per una durata conosciuta. Il MCU può quindi entrare in uno stato di sonno profondo. Questo è configurato impostando a 1 e fornendo le macro [[FLT-46] e diversi ordini di grandezza dell'evento possono ridurre.
Debug e Profiling
FreeRTOS include una funzione di statistica run-time (attiva [ e ) che fornisce percentuali di esecuzione delle attività. Questo aiuta a identificare i fumetti e le bancarelle della CPU. Inoltre, le funzioni e generano i riassunti leggibili dall'uomo a un buffer di caratteri.
Per un'analisi più approfondita, integrare FreeRTOS+Trace[ (ora parte del tester di dispositivo AWS IoT). Questo strumento registra eventi del kernel (context switch, operazioni di coda, voci ISR) e li visualizza in una linea temporale, inestimabile per la diagnosi di problemi di tempistica e inversioni di priorità.
Caratteristiche avanzate
Notifiche delle attività
Le notifiche delle attività offrono un'alternativa leggera ai semafori e alle code per un semplice segnale. Ogni compito ha un valore di notifica a 32 bit integrato e un conteggio di notifica in attesa. Inviare una notifica (tramite ] o ) può sbloccare l'attività di ricezione con zero overhead da un oggetto del kernel separato.
Buffer di Stream e buffer di messaggi
I buffer di flusso introdotti in FreeRTOS V10.0.0 consentono di trasmettere i dati di lunghezza variabile tra le attività o tra un ISR e un'attività senza una coda a dimensione fissa. Un buffer di messaggio è un buffer di flusso che preserva anche i confini dei messaggi. Questi sono utili per situazioni in cui la dimensione dei dati non è conosciuta in anticipo, come stack di rete o parsers di comando.
Co‐Routines (Legacy)
FreeRTOS include anche co-routine, che sono compiti senza stack che condividono un singolo stack. Sono raramente utilizzati nelle applicazioni moderne perché complicano il debug e non hanno tutte le funzioni. Si consiglia di utilizzare compiti standard a meno che non si siano fortemente conseguiti con RAM (ad esempio, 8 bit MCU).
Conclusioni
FreeRTOS fornisce una solida base ben documentata per la costruzione di applicazioni embedded efficienti. Il suo supporto per i primitivi di sincronizzazione preentivi, la ricca e avanzata come idle e le notifiche di attività senza ingombro lo rende adatto a tutto, dai semplici nodi di sensore ai gateway IoT complessi. Comprendendo i parametri di configurazione del kernel, seguendo le migliori pratiche per la gestione della memoria e l'assegnazione prioritaria, e sfruttando gli strumenti di debugging
Per ulteriori informazioni, consultare il FreeRTOS Reference Manual[] ed esplorare le applicazioni demo incluse nell'albero di origine. Molti fornitori di silicio, come STMicroelectronics e ]NXP], fornire microcontroller-specifica guida di sviluppo.