C per i sistemi embedded

È più che evidente la tendenza in atto che sta facendo migrare gli sviluppatori di sistemi embedded dal linguaggio assembly a quello C. A differenza dei sistemi commerciali, i sistemi embedded non lasciano a spazio a un errore di scelta. Decidere di utilizzare il linguaggio C per le applicazioni basate su piattaforme di computing embedded, anche molto spinte, è una scelta che può comportare rischi di insuccesso. I sistemi embedded sono nella maggior parte dei casi basati su dispositivi programmabili come i microcontrollori, i digital signal processor, i processori grafici, ecc. Fino a qualche anno fa, la programmazione più efficiente di tali processori era solo quella fatta con il linguaggio assembly, l'unico ad avere una corrispondenza diretta tra istruzioni simboliche e istruzioni macchina. Per tale natura, il linguaggio assembly garantisce che il codice sia minimo, sia rispetto all'occupazione di memoria, sia rispetto al tempo di esecuzione. Minima occupazione del codice e minimo tempo di esecuzione sono requisiti tipici dei sistemi embedded che lo sviluppatore deve rispettare. Questo è dunque spesso costretto a sviluppare molta parte dell'applicazione in linguaggio assembler, soprattutto quella relativa a parti critiche come i driver delle periferiche, le funzioni che governano direttamente la parte hardware del sistema, le procedure di gestione delle interruzioni, ecc. Lo sviluppatore infatti non si fida del linguaggio ad alto livello, in quanto non riesce ad avere la completa conoscenza della corrispondenza di quanto esso scrive a livello simbolico e di quanto il compilatore effettivamente produce a livello di istruzioni macchina.

Dal linguaggio assembly al linguaggio C
Il linguaggio C nello sviluppo dei sistemi commerciali viene utilizzato sin dall'introduzione dei primi personal computer. Per tali sistemi sono stati sviluppati compilatori molto poco efficienti e affatto ottimizzanti, quindi capaci di generare codice molto poco efficiente per tali sistemi. Le applicazioni commerciali compensavano le inefficienze del codice con un'ampia capacità di memoria e soprattutto, grazie alla legge di Moore, con una crescente velocità del processore conseguente alla diminuzione della geometria di integrazione. Per decenni i programmatori di sistemi embedded hanno ignorato il linguaggio C, malgrado la sua diffusione, proprio per colpa dei compilatori. Di tanto in tanto qualche produttore di compilatori C ne rilasciava una versione per microcontrollori o per Dsp, ma la qualità del codice prodotto era tanto bassa da indurre gli sviluppatori a scartare l'ipotesi di utilizzo del linguaggio C nello sviluppo dei sistemi embedded. Uno dei principali problemi che il compilatore C deve essere in grado di gestire per i sistemi embedded è l'aritmetica intera e la limitata precisione dell'Alu. L'aritmetica intera, tipica proprio dei microcontrollori a 8 e 16 bit, impone molta attenzione al modo in cui i numeri reali e la loro manipolazione aritmetica viene implementata su tali architetture. I compilatori C sono molto astratti rispetto a questo aspetto dell'architettura di computing, quindi non hanno un modello compilativo ottimizzante rispetto a questo aspetto. Alcuni compilatori C rendono a tale scopo estensioni che consentono di supportare specificamente i processori embedded relativamente all'aritmetica fixed-point e all'uso di variabili hardware come i registri. C'è comunque una forte motivazione al passaggio dal linguaggio assembly al linguaggio C per i sistemi embedded. La motivazione è la portabilità da piattaforma a piattaforma e la leggibilità. Inoltre, la rapidità di sviluppo dell'applicazione con il linguaggio C garantisce di centrare più facilmente i requisiti di time-to-market. Questi aspetti diventano ulteriormente significativi se il codice deve essere trasferito da uno sviluppatore all'altro e deve essere manutenuto a lungo nel tempo. Ovviamente, queste motivazioni possono essere soddisfatte solo se il codice eseguibile è efficiente e compatto. Ciò può essere garantito solo da un compilatore ottimizzante.

Scegliere il compilatore C giusto
Scegliere il compilatore C giusto per lo sviluppo di applicazioni embedded è sicuramente il passo più importante che uno sviluppatore deve compiere quando decide di passare dalla programmazione assembly a quella C. I compilatori C embedded sono ormai disponibili da parte di numerosi produttori di compilatori di linguaggio C o C++. Compilatori di ottima qualità sono disponibili anche da parte di organizzazioni non commerciali sotto forma di shareware. Il caso più noto di compilatore shareware è il Gcc Gnu, spesso utilizzato dai produttori di microcontrollori come compilatore reference per le loro famiglie di dispositivi (viene fornito in forma gratuita tra i tool di sviluppo). I criteri da tenere ben presente per la scelta del compilatore C sono fondamentalmente i seguenti:
•    compatibilità Ansi;
•    portabilità;
•    capacità di generare codice compatto.

La compatibilità Ansi è strettamente legata alla portabilità del codice. Questa è una diretta conseguenza della natura ad alto livello del codice C. Teoricamente, qualsiasi compilatore C potrebbe compilare qualsiasi codice C. Nella realtà ciò non è vero in quanto i compilatori non Ansi-C compatibili compilano linee di codice che altri compilatori non compilano, rendendo in tal modo la portabilità del codice critica. La capacità ottimizzante del compilatore C è la caratteristica del compilatore che consente di ottenere codice compatto ed efficiente nell'esecuzione. Ovviamente si tratta di requisiti mutuamente contrastanti, nel senso che per ottimizzare uno dei due bisogna rilassare l'altro. Il compilatore deve avere almeno la capacità di ottimizzare (a scelta) o l'uno o l'altro. Un buon compilatore ottimizzante è capace di offrire anche un'azione di ottimizzazione ponderata. La portabilità del codice è peculiare sia per prodotti finali che svolgono funzioni applicative simili, sia per prodotti finali soggetti a una rapida e frequente aggiornabilità. L'ambiente di sviluppo, di cui il compilatore C fa parte, è un altro aspetto di scelta importante, considerando la complessità delle applicazioni embedded e quindi la necessità di strumenti di produttività durante la fase di progettazione, ma anche durante quella di verifica, validazione e documentazione del codice. Oltre ai compilatori C open source, sono disponibili compilatori proprietari, che vengono offerti direttamente dal produttore del microcontrollore, o più in generale di dispositivi programmabili. Nella versione base è normalmente incluso gratuitamente nel EVM come versione base. Le versioni più ricche e complete sono invece a pagamento. Un ambiente di sviluppo commerciale che include il linguaggio C in una suite di sviluppo per sistemi embedded è CodeWarrior di Metrowerks. Questo ambiente di sviluppo, soprattutto da quando è stato acquisito da Motorola (poi Freescale), è particolarmente orientato a supportare dispositivi embedded come l'ampia gamma di microcontrollori, microcontrollori Dsp e Dsp puri di Freescale. Il compilatore C e C++ in esso incluso è ottimizzante.

ANSI C o C++?

Il linguaggio C, come ben noto, si è evoluto dalla versione originaria, l'Ansi C, ad altre versioni capaci di soddisfare le crescenti e diversificate esigenze dei progettisti: interfacce grafiche, comunicazione, interazione con dispositivi esterni, ecc. Sono state sviluppate quindi nuove versioni di C capaci di soddisfare le crescenti esigenze dei programmatori, in particolare quelli che utilizzano sistemi embedded programmabili come il microcontrollore. Il linguaggio C++, cioè il C ad oggetti, ha rappresentato una delle più rilevanti innovazioni del linguaggio C (Ansi). Gli sviluppatori di sistemi embedded, in particolare quelli che utilizzano piattaforme di computing avanzate come gli Asp (Application specific processor), hanno avuto dubbi sul fatto che il linguaggio C++ potesse essere vantaggioso per lo sviluppo di applicazioni embedded, soprattutto quelle con requisiti stringenti. Il dubbio maggiore rispetto al C++ concerne un potenziale sovraccarico che questo linguaggio produce proprio per i meccanismi implementativi degli oggetti. Ciò è vero, ma non dipende dal linguaggio. È il compilatore che, se non adeguato ed efficiente, produce codice con sovraccarico. Il linguaggio C++ va considerato come un'estensione del C, quindi fa tutto quello che fa il C, oltre a fare tutto quello consentito dalla modalità ad oggetti. L'idea principale che circola tra gli sviluppatori è che il linguaggio C++ sia lento, richieda più memoria di codice e soprattutto l'uso di librerie di classi porti alla generazione di codice binario particolarmente esteso. Il linguaggio C++ è un superinsieme del linguaggio C, quindi il codice generato da un compilatore di linguaggio C++ è lo stesso che genera un compilatore C a parità di codice sorgente.

LASCIA UN COMMENTO

Inserisci il tuo commento
Inserisci il tuo nome