

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Aspetti fondamentali del kernel FreeRTOS
<a name="dev-guide-freertos-kernel"></a>

Il kernel FreeRTOS è un sistema operativo in tempo reale che supporta numerose architetture I suoi fondamenti sono ideali per la creazione di applicazioni di microcontrollori integrati. Offre:
+ Un pianificatore multitasking.
+ Numerose opzioni di allocazione di memoria (tra cui la possibilità di creare sistemi completamente allocati staticamente). 
+ Primitive di coordinamento tra task, che includono notifiche di task, code di messaggi, più tipi di semaforo e buffer dei messaggi e di flusso.
+ Support per il multiprocessing simmetrico (SMP) su microcontrollori multi-core.

Il kernel FreeRTOS non esegue mai operazioni non deterministiche, ad esempio esplorare un elenco collegato, in una sezione critica o in un interrupt. Il kernel FreeRTOS include un'efficiente implementazione del timer di software che non utilizza tempo CPU, a meno che un timer non necessiti di manutenzione. Le attività bloccate non richiedono una manutenzione periodica dispendiosa in termini di tempo. Direct-to-taskle notifiche consentono una segnalazione rapida delle attività, praticamente senza sovraccarico di RAM. Possono essere utilizzate nella maggior parte degli scenari di interattività e interrupt-to-task segnalazione.

Il kernel FreeRTOS è stato progettato per essere semplice, piccolo e di facile utilizzo. L'immagine binaria del kernel di un RTOS tipica rientra nell'intervallo compreso tra 4.000 e 9.000 byte.

[Per la maggior parte della up-to-date documentazione sul kernel FreerTOS, vedere FreerTOS.org.](https://freertos.org/) [*Freertos.org offre una serie di tutorial e guide dettagliate sull'uso del kernel FreerTOS, inclusa una guida rapida del kernel FreerTOS FreerTOS e l'implementazione RTOS più approfondita nella documentazione di *[FreerTOS](https://freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/02-Quick-start-guide).](https://freertos.org/Documentation/02-Kernel/05-RTOS-implementation-tutorial/01-RTOS-implementation)

# Lo scheduler del kernel FreerTOS
<a name="freertos-kernel-scheduler"></a>

Un'applicazione integrata che utilizza un sistema RTOS può essere strutturata come set di task indipendenti. Ogni task viene eseguito all'interno del proprio contesto, senza alcuna dipendenza da altri task. Nell'applicazione viene eseguito sempre un solo task alla volta. Il pianificatore RTOS in tempo reale determina quando deve essere eseguito ciascun task. Ogni task ha il proprio stack. Quando viene eseguito lo swap out di un task per consentire l'esecuzione di un altro task, il relativo contesto di esecuzione viene salvato nel rispettivo stack, in modo che il task possa essere ripristinato quando ne viene eseguito nuovamente lo swap in per riprenderne l'esecuzione. 

Per offrire un comportamento deterministico in tempo reale, il pianificatore di task FreeRTOS permette di assegnare ai task priorità rigorose. RTOS garantisce che venga assegnato tempo di elaborazione ai task con la massima priorità che riesce a eseguire. Ciò comporta che, se sono pronti per essere eseguiti simultaneamente, i task di pari priorità devono condividere il tempo di elaborazione. FreeRTOS inoltre crea un task inattivo che viene eseguito solo quando non ci sono altri task pronti per l'esecuzione.

# Allocazione della memoria del kernel
<a name="kernel-memory-allocation"></a>

Il kernel RTOS richiede RAM ogni volta che viene creato un task, una coda o un altro oggetto RTOS. La RAM può essere allocata:
+ Staticamente in fase di compilazione.
+ Dinamicamente dall'heap RTOS dalle funzioni di creazione dell'oggetto API RTOS.

Quando gli oggetti RTOS vengono creati in modo dinamico, l'utilizzo delle funzioni `malloc()` e `free()` della libreria C standard non è sempre appropriato per una serie di motivi.
+ Potrebbero non essere disponibili nei sistemi integrati.
+ Occupano spazio di codice prezioso.
+ Generalmente non sono thread-safe.
+ Non sono deterministiche.

Per questi motivi, FreeRTOS mantiene l'API di allocazione della memoria nel livello portatile. Il livello portatile è esterno ai file di origine che implementano la funzionalità di base di RTOS, consentendo di fornire un'implementazione specifica dell'applicazione appropriata per il sistema in tempo reale che stai sviluppando. Quando il kernel RTOS richiede RAM, chiama `pvPortMalloc()` anziché `malloc()`(). Quando viene liberata RAM, il kernel RTOS chiama `vPortFree()` anziché `free()`.

# Gestire la memoria delle applicazioni
<a name="application-memory-management"></a>

Quando le applicazioni hanno bisogno di memoria, possono allocarla dall'heap FreeRTOS. L'heap FreeRTOS offre vari schemi di gestione degli heap di complessità e caratteristiche varie. È anche possibile specificare un'implementazione heap personalizzata.

Il kernel FreeRTOS include cinque implementazioni heap:

**`heap_1`**  
Si tratta del tipo di implementazione più semplice. Non consente che venga liberata memoria.

**`heap_2`**  
Consente che venga liberata memoria, ma non unisce i blocchi liberi adiacenti.

**`heap_3`**  
Racchiude i valori `malloc()` e `free()` standard per la sicurezza per i thread.

**`heap_4`**  
Unisce i blocchi adiacenti per evitare la frammentazione. Include un'opzione di posizionamento dell'indirizzo assoluto.

**`heap_5`**  
È simile a heap\$14. Può distribuire l'heap su più aree di memoria non adiacenti.

# Coordinamento tra attività
<a name="inter-task-coordination"></a>

Questa sezione contiene informazioni sulle primitive FreeRTOS.

**Topics**
+ [Queues](#inter-task-queues)
+ [Semafori e mutex](#inter-task-semaphones)
+ [Direct-to-task notifiche](#direct-task-notifications)
+ [Buffer dei flussi](#rtos-stream-buffer)
+ [Buffer dei messaggi](#rtos-message-buffer)

## Queues
<a name="inter-task-queues"></a>

Le code sono la principale forma di comunicazione tra task. Esse possono essere utilizzate per lo scambio di messaggi tra i task, e tra interrupt e task. Nella maggior parte dei casi, vengono utilizzate come buffer FIFO (First In First Out) thread-safe con l'inserimento di nuovi dati in coda, ma è possibile anche predisporre un inserimento in testa. I messaggi vengono inviati alle code attraverso una copia, ciò significa che la coda non si limita ad archiviare un riferimento ai dati, ma vengono copiati nella coda i dati stessi (che possono essere un puntatore ai buffer di dimensioni maggiori).

La coda APIs consente di specificare un periodo di blocco. Quando prova a leggere da una coda vuota, un task viene inserito nello stato bloccato, in modo da non consumare alcun tempo di CPU e da dare la possibilità di mandare in esecuzione altri task, fino a quando nella coda non diventano disponibili dati o fino allo scadere del periodo di blocco. Analogamente, quando prova a scrivere in una coda piena, il task viene inserito nello stato bloccato finché nella coda non si libera spazio o fino allo scadere del periodo di blocco. Se nella stessa coda si bloccano più task, il primo task a essere sbloccato sarà quello con priorità più alta. 

Altre primitive FreerTOS, direct-to-task come le notifiche e i buffer di stream e messaggi, offrono alternative leggere alle code in molti scenari di progettazione comuni. 

## Semafori e mutex
<a name="inter-task-semaphones"></a>

Il kernel FreeRTOS prevede semafori binari, semafori a conteggio e mutex, utilizzati sia per risolvere la mutua esclusione sia per scopi di sincronizzazione.

I semafori binari possono avere solo due valori. Sono la soluzione migliore per implementare la sincronizzazione (tra i task o tra i task e un interrupt). I semafori a conteggio accettano più di due valori e consentono a un numero elevato di task di condividere le risorse o di eseguire operazioni di sincronizzazione più complesse.

I mutex sono semafori binari che includono un meccanismo di ereditarietà della priorità. Questo significa che, se un task a priorità elevata si blocca durante il tentativo di ottenere un mutex attualmente incluso in un task di priorità inferiore, la priorità del task che include il token viene temporaneamente elevata al livello di quella del task che blocca. Questo meccanismo è stato progettato per garantire che il task con priorità maggiore resti nello stato bloccato per il minor tempo possibile, in modo da ridurre al minimo l'inversione di priorità che si verifica.

## Direct-to-task notifiche
<a name="direct-task-notifications"></a>

Le notifiche delle attività consentono alle attività di interagire con altre attività e di sincronizzarsi con le routine del servizio di interruzione (ISRs), senza la necessità di un oggetto di comunicazione separato come un semaforo. Ogni task RTOS presenta un valore di notifica a 32 bit che viene utilizzato per memorizzare eventuale contenuto della notifica. Una notifica di task RTOS è un evento inviato direttamente a un task che può sbloccare il task ricevente e, facoltativamente, aggiornare il rispettivo valore di notifica.

Le notifiche di task RTOS possono essere utilizzate come alternativa semplice e veloce ai semafori a conteggio e binari e, in alcuni casi, alle code. Le notifiche di task presentano vantaggi sia in termini di velocità che di ingombro della RAM rispetto alle altre caratteristiche di FreeRTOS che possono essere utilizzate per eseguire funzionalità equivalenti. Tuttavia, le notifiche dei task possono essere utilizzate solo nei casi un cui un solo task può essere destinatario dell'evento.

## Buffer dei flussi
<a name="rtos-stream-buffer"></a>

I buffer di flussi consentono a un flusso di byte di passare da una routine di servizi di interrupt a un task o da un task a un altro. Un flusso di byte può essere di lunghezza arbitraria e non ha necessariamente un inizio o una fine. È possibile leggere e scrivere qualsiasi numero di byte contemporaneamente. La funzionalità del buffer di flussi viene abilitata includendo nel progetto il file di origine `stream_buffer.c`.

I buffer di flussi presuppongono che un solo task o un solo interrupt scriva nel buffer (il writer) e che un solo task o un solo interrupt legga dal buffer (il reader). Il writer e il reader possono essere task diversi o diverse routine di servizi di interrupt, ma non è sicuro avere più writer o reader.

L'implementazione dello stream buffer utilizza direct-to-task le notifiche. Pertanto, chiamare un'API del buffer di flussi che inserisce il task chiamante nello stato bloccato può modificare il valore e lo stato della notifica del task.

### Invio dei dati
<a name="rtos-stream-buffer-send"></a>

`xStreamBufferSend()` viene utilizzato per inviare dati a un buffer di flussi in un task. `xStreamBufferSendFromISR()` viene utilizzato per inviare dati a un buffer di flussi in una routine di servizi di interrupt (ISR).

`xStreamBufferSend()` consente di specificare un periodo di blocco. Se si chiama `xStreamBufferSend()` con un periodo di blocco diverso da zero per scrivere in un buffer di flussi e il buffer è pieno, il task viene inserito nello stato bloccato finché non si libera spazio o fino allo scadere del periodo di blocco.

`sbSEND_COMPLETED()` e `sbSEND_COMPLETED_FROM_ISR()` sono macro che vengono chiamate (internamente dall'API FreeRTOS) quando vengono scritti dati in un buffer di flussi. Utilizzano l'handle del buffer di flussi che è stato aggiornato. Entrambe le macro verificano la presenza di eventuali task bloccati nel buffer di flussi in attesa di dati e, se presenti, li rimuovono dallo stato bloccato.

È possibile modificare questo comportamento predefinito specificando la propria implementazione di `sbSEND_COMPLETED()` in [`FreeRTOSConfig.h`](freertos-config.md). Questa funzione risulta utile quando viene utilizzato un buffer di flussi per trasferire dati tra i core in un processore multicore. In tale scenario è possibile implementare `sbSEND_COMPLETED()` per generare un interrupt nell'altro core della CPU e la routine dei servizi di interrupt può quindi utilizzare l'API `xStreamBufferSendCompletedFromISR()` per verificare la presenza di un task in attesa dei dati e, se necessario, sbloccarlo.

### Ricezione dei dati
<a name="rtos-stream-buffer-receive"></a>

`xStreamBufferReceive()` viene utilizzato per leggere i dati a un buffer di flussi in un task. `xStreamBufferReceiveFromISR()` viene utilizzato per leggere i dati da un buffer di flussi in una routine di servizi di interrupt (ISR).

`xStreamBufferReceive()` consente di specificare un periodo di blocco. Se si chiama `xStreamBufferReceive()` con un periodo di blocco diverso da zero per leggere da un buffer di flussi e il buffer è vuoto, il task viene inserito nello stato bloccato finché nel buffer non diventa disponibile una quantità di dati specificata o fino allo scadere del periodo di blocco.

La quantità di dati che deve trovarsi nel buffer di flussi prima che un task venga sbloccato viene denominata livello di trigger del buffer di flussi. Un task bloccato con un livello di trigger pari a 10 viene sbloccato quando nel buffer vengono scritti almeno 10 byte o allo scadere del periodo di blocco. Se il periodo i blocco del task di lettura scade prima che venga raggiunto il livello di trigger, il task riceve tutti i dati scritti nel buffer. Il livello di trigger di un'attività deve essere impostato su un valore compreso tra 1 e le dimensioni del buffer di flussi. Il livello di trigger di un buffer di flussi viene impostato quando si chiama `xStreamBufferCreate()`. Può essere modificato chiamando `xStreamBufferSetTriggerLevel()`.

`sbRECEIVE_COMPLETED()` e `sbRECEIVE_COMPLETED_FROM_ISR()` sono macro che vengono chiamate (internamente dall'API FreeRTOS) quando vengono letti dati da un buffer di flussi. Le macro verificano la presenza di eventuali task bloccati nel buffer di flussi in attesa che si liberi spazio nel buffer e, se presenti, li rimuovono dallo stato bloccato. È possibile modificare questo comportamento predefinito di `sbRECEIVE_COMPLETED()` specificando un'implementazione alternativa in [`FreeRTOSConfig.h`](freertos-config.md).

## Buffer dei messaggi
<a name="rtos-message-buffer"></a>

I buffer di messaggi consentono a singoli messaggi di lunghezza variabile di passare da una routine di servizi di interrupt a un task o da un task a un altro. Ad esempio, i messaggi lunghi 10, 20 e 123 byte possono essere tutti letti da e scritti nello stesso buffer di messaggi. Un messaggio da 10 byte può essere letto solo come messaggio da 10 byte, non come byte singoli. I buffer dei messaggi vengono creati nella parte superiore dell'implementazione del buffer di flusso. È possibile abilitare la funzionalità di buffer dei messaggi includendo il file di origine `stream_buffer.c` nel progetto.

I buffer di messaggi presuppongono che un solo task o un solo interrupt scriva nel buffer (il writer) e che un solo task o un solo interrupt legga dal buffer (il reader). Il writer e il reader possono essere task diversi o diverse routine di servizi di interrupt, ma non è sicuro avere più writer o reader.

L'implementazione del buffer dei messaggi utilizza direct-to-task le notifiche. Pertanto, chiamare un'API del buffer di flussi che inserisce il task chiamante nello stato bloccato può modificare il valore e lo stato della notifica del task. 

Per consentire ai buffer di messaggi di gestire messaggi di dimensioni variabili, prima di ciascun messaggio ne viene scritta la lunghezza. La durata viene memorizzata in una variabile di tipo `size_t`, che in genere in un'architettura a 32 byte è di 4 byte. Pertanto, per scrivere un messaggio di 10 byte in un buffer di messaggi si consumano 14 byte di spazio di buffer effettivi. Analogamente, per scrivere un messaggio di 100 byte in un buffer di messaggi si utilizzano 104 byte di spazio di buffer effettivi.

### Invio dei dati
<a name="rtos-message-buffer-send"></a>

`xMessageBufferSend()` viene utilizzato per inviare dati a un buffer di messaggi da un task. `xMessageBufferSendFromISR()` viene utilizzato per inviare dati a un buffer di messaggi da una routine di servizi di interrupt (ISR).

`xMessageBufferSend()` consente di specificare un periodo di blocco. Se si chiama `xMessageBufferSend()` con un periodo di blocco diverso da zero per scrivere in un buffer di messaggi e il buffer è pieno, il task viene inserito nello stato bloccato finché non si libera spazio nel buffer di messaggi o fino allo scadere del periodo di blocco.

`sbSEND_COMPLETED()` e `sbSEND_COMPLETED_FROM_ISR()` sono macro che vengono chiamate (internamente dall'API FreeRTOS) quando vengono scritti dati in un buffer di flussi. Accettano un parametro singolo, ovvero l'handle del buffer di flussi che è stato aggiornato. Entrambe le macro verificano la presenza di eventuali task bloccati nel buffer di flussi in attesa di dati e, se presenti, li rimuovono dallo stato bloccato.

È possibile modificare questo comportamento predefinito specificando la propria implementazione di `sbSEND_COMPLETED()` in [`FreeRTOSConfig.h`](freertos-config.md). Questa funzione risulta utile quando viene utilizzato un buffer di flussi per trasferire dati tra i core in un processore multicore. In tale scenario è possibile implementare `sbSEND_COMPLETED()` per generare un interrupt nell'altro core della CPU e la routine dei servizi di interrupt può quindi utilizzare l'API `xStreamBufferSendCompletedFromISR()` per verificare e, se necessario, sbloccare, un task in attesa dei dati.

### Ricezione dei dati
<a name="rtos-message-buffer-receive"></a>

`xMessageBufferReceive()` viene utilizzato per leggere i dati da un buffer di messaggi in un task. `xMessageBufferReceiveFromISR()` viene utilizzato per leggere i dati da un buffer di messaggi in una routine di servizio di interrupt (ISR). `xMessageBufferReceive()` consente di specificare un periodo di blocco. Se si chiama `xMessageBufferReceive()` con un periodo di blocco diverso da zero per leggere da un buffer di messaggi e il buffer è vuoto, il task viene inserito nello stato bloccato finché non diventano disponibili dati o fino allo scadere del periodo di blocco.

`sbRECEIVE_COMPLETED()` e `sbRECEIVE_COMPLETED_FROM_ISR()` sono macro che vengono chiamate (internamente dall'API FreeRTOS) quando vengono letti dati da un buffer di flussi. Le macro verificano la presenza di eventuali task bloccati nel buffer di flussi in attesa che si liberi spazio nel buffer e, se presenti, li rimuovono dallo stato bloccato. È possibile modificare questo comportamento predefinito di `sbRECEIVE_COMPLETED()` specificando un'implementazione alternativa in [`FreeRTOSConfig.h`](freertos-config.md).

# Supporto per il multiprocessing simmetrico (SMP)
<a name="smp-support"></a>

Il [supporto SMP nel kernel FreerTOS consente](https://freertos.org/symmetric-multiprocessing-introduction.html) a un'istanza del kernel FreerTOS di pianificare attività su più core di processore identici. Le architetture principali devono essere identiche e condividere la stessa memoria.

[L'API FreerTOS rimane sostanzialmente la stessa tra le versioni single-core e SMP, ad eccezione di queste aggiuntive. APIs](https://freertos.org/symmetric-multiprocessing-introduction.html#smp-specific-apis) Pertanto, un'applicazione scritta per la versione single-core di FreerTOS dovrebbe essere compilata con la versione SMP con uno sforzo minimo o nullo. Tuttavia, potrebbero esserci alcuni problemi funzionali, perché alcune ipotesi che erano vere per le applicazioni single-core potrebbero non essere più vere per le applicazioni multi-core.

Un presupposto comune è che un'attività con priorità inferiore non possa essere eseguita mentre è in esecuzione un'attività con priorità più alta. Sebbene ciò fosse vero in un sistema single-core, non è più vero per i sistemi multicore perché più attività possono essere eseguite contemporaneamente. Se l'applicazione si basa su priorità di attività relative per garantire l'esclusione reciproca, potrebbe ottenere risultati imprevisti in un ambiente multicore.

Un altro presupposto comune è che non ISRs possono essere eseguiti contemporaneamente l'uno con l'altro o con altre attività. Questo non è più vero in un ambiente multi-core. L'autore dell'applicazione deve garantire la corretta esclusione reciproca durante l'accesso ai dati condivisi tra attività e. ISRs

# Timer del software
<a name="software-timers"></a>

Un timer del software consente di eseguire una funzione a un'ora futura stabilita. La funzione eseguita dal timer viene denominata la *funzione di callback* del timer. Il periodo di tempo compreso tra l'avvio di un timer e l'esecuzione della rispettiva funzione di callback viene denominato *periodo* del timer. Il kernel FreeRTOS offre un'implementazione efficace del timer del software perché:
+ Non esegue funzioni di callback del timer da un contesto di interrupt.
+ Non consuma tempo di elaborazione, a meno che un timer non sia scaduto.
+ Non aggiunge alcun sovraccarico di elaborazione all'interrupt del tick.
+ Non esplora nessuna struttura di elenchi di link quando gli interrupt sono disabilitati.

# Supporto della modalità a basso consumo
<a name="low-power-support"></a>

Come la maggior parte dei sistemi operativi integrati, il kernel FreeRTOS utilizza un timer hardware per generare periodici interrupt del tick, il cui scopo è misurare il tempo. Il risparmio di energia delle normali implementazioni dei timer hardware è limitata dalla necessità di uscire e rientrare periodicamente nella modalità a basso consumo per elaborare gli interrupt dei tick. Se la frequenza dell’interrupt del tick è troppo elevata, l'energia e il tempo consumati per entrare e uscire nella modalità a basso consumo per ogni tick annulla qualsiasi potenziale vantaggio derivante dall'uso di una modalità di risparmio energetico, ad eccezione di quella a più basso consumo. 

Per risolvere questa limitazione, FreeRTOS include una modalità del timer senza tick per le applicazioni a basso consumo. La modalità inattiva senza tick FreeRTOS arresta l'interrupt del tick periodico durante i periodi di inattività (periodi in cui non sono presenti task di applicazione in grado di essere eseguiti), quindi apporta un adeguamento correttivo al valore del conteggio dei tick RTOS quando viene riavviato l'interrupt del tick. L'arresto dell'interrupt del tick consente al microcontroller di rimanere in uno stato di risparmio energetico profondo finché non si verifica un interrupt oppure fino a quando il kernel RTOS non deve eseguire la transizione di un task nello stato pronto.

# Configura il kernel (Free RTOSConfig .h)
<a name="freertos-config"></a>

È possibile configurare il kernel FreeRTOS per una scheda e un'applicazione specifiche con il file di intestazione `FreeRTOSConfig.h`. Ogni applicazione basata su kernel deve avere un file di intestazione `FreeRTOSConfig.h` nel suo percorso di inclusione del preprocessore. `FreeRTOSConfig.h` è specifico dell'applicazione e deve essere posizionato all'interno della directory di un'applicazione e non in una delle directory del codice sorgente del kernel FreeRTOS.

I `FreeRTOSConfig.h` file per le applicazioni demo e di test di FreerTOS si trovano in e. `freertos/vendors/vendor/boards/board/aws_demos/config_files/FreeRTOSConfig.h` `freertos/vendors/vendor/boards/board/aws_tests/config_files/FreeRTOSConfig.h`

Per un elenco di tutti i parametri di configurazione disponibili da specificare in `FreeRTOSConfig.h`, consulta [FreeRTOS.org](https://www.freertos.org/a00110.html).