Sei sulla pagina 1di 59

Università degli studi di Pisa

Corso di Laurea Specialistica in Ingegneria dell’Automazione

Sviluppo di software in Simulink e Real-Time


Workshop Embedded Coder

Paolo Tripicchio

Corso di Meccatronica
Anno accademico 2007/2008
Indice

1 The MathWorks 4
1.1 Il MATLAB . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Il Simulink . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Lo Stateflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Real Time Workshop 8


2.1 Scelta e configurazione del target . . . . . . . . . . . . . . . . 10
2.2 File sorgenti generati e dipendenze dei file . . . . . . . . . . . 11
2.3 Esecuzione del modello . . . . . . . . . . . . . . . . . . . . . . 12
2.3.1 Modelli per Sistemi Real-Time Single-Tasking . . . . . 13
2.3.2 Modelli per Sistemi Real-Time Multitasking . . . . . . 14
2.4 Temporizzazione del Programma . . . . . . . . . . . . . . . . 16
2.5 Differenze tra i Modelli di Esecuzione Rapid Prototyping ed
Embedded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.1 Funzioni del Modello Embedded . . . . . . . . . . . . . 17
2.6 Esecuzione di Modelli Multitasking . . . . . . . . . . . . . . . 18
2.7 Transizioni della Frequenza di Campionamento . . . . . . . . . 19
2.7.1 Problemi di Trasferimento Dati . . . . . . . . . . . . . 20
2.7.2 Assunzioni sul Trasferimento Dati . . . . . . . . . . . . 21
2.7.3 Opzioni del Blocco Rate Transition . . . . . . . . . . . 21
2.7.4 Automatic Rate Transition . . . . . . . . . . . . . . . . 23
2.8 Utilizzo delle S-Functions . . . . . . . . . . . . . . . . . . . . . 23
2.8.1 Tipi di S-Function . . . . . . . . . . . . . . . . . . . . 24
2.8.2 Noninlined S-Functions . . . . . . . . . . . . . . . . . . 24
2.8.3 Wrapper S-Functions . . . . . . . . . . . . . . . . . . . 25
2.8.4 Fully Inlined S-Functions . . . . . . . . . . . . . . . . . 25
2.8.5 MEX S-Function Wrapper . . . . . . . . . . . . . . . . 26
2.8.6 TLC S-Function Wrapper . . . . . . . . . . . . . . . . 28
2.8.7 Fully Inlined S-Functions . . . . . . . . . . . . . . . . . 31
2.9 Utilizzo di Blocchi Asincroni di Interruzione in Simulazione e
Generazione del Codice . . . . . . . . . . . . . . . . . . . . . . 32

1
2.9.1 Rate Transitions e Blocchi Asincroni . . . . . . . . . . 33

3 Real Time Workshop Embedded Coder 34


3.1 Stuttura Dati del Modello Real-Time . . . . . . . . . . . . . . 35
3.2 Esecuzione di Programmi Stand-Alone . . . . . . . . . . . . . 36
3.3 Programma Main . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4 rt OneStep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.4.1 Single-Rate Singletasking . . . . . . . . . . . . . . . . . 37
3.4.2 Multi-Rate Multitasking . . . . . . . . . . . . . . . . . 38
3.4.3 Rate Grouping . . . . . . . . . . . . . . . . . . . . . . 38
3.4.4 Multi-Rate Singletasking . . . . . . . . . . . . . . . . . 39
3.5 Linee Guida per la modifica di rt OneStep . . . . . . . . . . . 40

4 Ottimizzazioni fixed-point 41
4.1 Rappresentazione fixed-point . . . . . . . . . . . . . . . . . . . 41

5 Impostazioni Real Time Workshop 46


5.1 Block Reduction Optimization . . . . . . . . . . . . . . . . . . 46
5.2 Conditional Input Branch Execution . . . . . . . . . . . . . . 47
5.3 Implement Logic Signals as Boolean Data . . . . . . . . . . . 48
5.4 Signal Storage Reuse . . . . . . . . . . . . . . . . . . . . . . . 48
5.5 Inline Parameters . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.6 Application Lifespan . . . . . . . . . . . . . . . . . . . . . . . 49
5.7 Enable Local Block Outputs . . . . . . . . . . . . . . . . . . . 50
5.8 Reuse Block Outputs . . . . . . . . . . . . . . . . . . . . . . . 50
5.9 Ignore Integer Downcasts in Folded Expressions . . . . . . . . 50
5.10 Inline Invariant Signals . . . . . . . . . . . . . . . . . . . . . . 50
5.11 Eliminate Superfluous Temporary Variables (Expression Fold-
ing) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.12 Loop Unrolling Threshold . . . . . . . . . . . . . . . . . . . . 52
5.13 Remove Code from Floating-Point to Integer Conversions That
Wraps Out-of-Range Values . . . . . . . . . . . . . . . . . . . 53
5.14 Parameter Structure . . . . . . . . . . . . . . . . . . . . . . . 53
5.15 Sottopannello Data Initialization . . . . . . . . . . . . . . . . 53
5.16 Remove code that protects against division arithmetic exceptions 54

2
Elenco delle figure

2.1 Real-Time Workshop Flowchart . . . . . . . . . . . . . . . . . 11


2.2 File generati e dipendenze . . . . . . . . . . . . . . . . . . . . 12
2.3 Task timing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.4 Configurazione blocco Rate Transition . . . . . . . . . . . . . 22
2.5 Approccio a doppio-modello . . . . . . . . . . . . . . . . . . . 32

4.1 Rappresentazione fixed-point . . . . . . . . . . . . . . . . . . . 42


4.2 Simulink fixed-point . . . . . . . . . . . . . . . . . . . . . . . 44
4.3 Stateflow fixed-point . . . . . . . . . . . . . . . . . . . . . . . 44

5.1 Pannello Hardware Implementation . . . . . . . . . . . . . . . 55


5.2 Pannello Real-Time Workshop . . . . . . . . . . . . . . . . . . 56
5.3 Pannello interface . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.4 Pannello Templates . . . . . . . . . . . . . . . . . . . . . . . . 57
5.5 Pannello C166 Options . . . . . . . . . . . . . . . . . . . . . . 58

3
Capitolo 1

The MathWorks

La The MathWorks è il principale sviluppatore e fornitore di software per


il calcolo tecnico e la progettazione model-based. The MathWorks è stata
fondata nel 1984 e oggi da lavoro a più di 1500 persone con uffici e sedi rap-
presentative in tutto il mondo.
La The MathWorks produce software di calcolo e progettazione per ingegneri,
matematici e ricercatori. I prodotti di punta della compagnia sono il MAT-
LAB, utilizzato per effettuare calcoli matematici, analizzare e visualizzare
dati, scrivere nuovi programmi software; e Simulink, utilizzato per la model-
lazione e la simulazione di sistemi complessi. Altri pacchetti sono affiancati
ai principali per esigenze particolari.

4
1.1 Il MATLAB
Il MATLAB è un linguaggio ad alto livello ed un ambiente interattivo che
permette all’utente di compiere processi computazionalmente dispendiosi in
maniera più veloce che con i linguaggi di programmazione tradizionali.
E’ possibile utilizzare MATLAB in un largo numero di applicazioni tra le
quali il filtraggio di segnali ed immagini, la progettazioni di controllori, la
effettuazione di test e misurazioni, la modellazione finanziaria e la biologia
computazionale. Toolbox aggiuntivi estendono l’ambiente MATLAB permet-
tendo di risolvere particolari classi di problemi.
Il MATLAB fornisce una serie di meccanismi per documentare e condivire il
proprio lavoro. Riassumendo il MATLAB fornisce:

• Un linguaggio ad alto livello per il computo tecnico

• Un ambiente di sviluppo per la gestione di codice, files e dati

• Dei tools interattivi per l’esplorazione iterativa, la progettazione e la


risoluzione di problemi

• Delle funzioni matematiche per l’algebra lineare, la statistica, l’analisi


di Fourier, il filtraggio, l’ottimizzazione e l’integrazione numerica.

• Funzioni grafiche 2D e 3D per visualizzare i dati

• Strumenti per la creazione di interfaccie grafiche peronalizzate

• Funzioni per integrare gli algoritmi di MATLAB con applicazioni e


linguaggi esterni.

1.2 Il Simulink
Il Simulink è ua piattaforma per la simulazione e la progettazione model-
based dei sistemi dinamici. Esso fornisce un ambente grafico interattivo e un
insieme di librerie di blocchi personalizzabile che permettono di progettare
accuratamente, simulare, implementare e testare sistemi tempo varianti.
Dei prodotti aggiuntivi estendono l’ambiente Simulink con strumenti per la
modellazione e la generazione di codice specifica.
Simulink è integrato con MATLAB garantendo un accesso immediato ad un
numeroso insieme di strumenti per lo sviluppo di algoritmi, la visualizzazione
dei dati, l’analisi dei dati e il calcolo numerico.
Riassumendo il Simulink fornisce:

5
• Un numero estensivo ed espandibile di librerie di blocchi predefiniti
• Un editor grafico interattivo per l’assemblamento e la gestione intuitiva
dei diagrammi a blocchi
• La capacità di trattare progetti complessi segmentando i modelli dentro
gerarchie dei componenti del progetto
• La capacità di interfacciarsi con altri programmi di simulazione e di
incorporare codice scritto a mano
• Le opzioni per simulare i sistemi tempo-varianti interattivamente con
passo fisso o variabile
• Le funzioni per definire interattivamente gli ingressi e vedere le uscite
per valutare il comportamento del modello
• Un accesso completo alle funzionalità del MATLAB
• Strumenti per l’analisi di modello e strumenti diagnostici per assicurare
la consistenza del modello ed identificare gli errori di modellazione

1.3 Lo Stateflow
Lo Stateflow è uno strumento per la simulazione e la progettazione interattiva
dei sistemi ad eventi che si va ad aggiungere al Simulink. Lo Stateflow
fornisce gli elementi richiesti per la descrizione della logica complessa in una
forma naturale e comprensibile. Fornisce quindi un ambiente efficiente per
la progettazione di sistemi embedded che contengono logica di supervisione
o di controllo.
I diagrammi Stateflow permettono una rappresentazione grafica degli stati
paralleli o gerarchici e delle transizioni event-driven tra di essi. Con l’utilizzo
dello Stateflow Coder è anche possibile generare codice C ottimizzato dai
diagrammi Stateflow. Riassumendo lo Stateflow:
• Fornisce elementi di linguaggio, gerarchia, parallelismo e semantica di
esecuzione deterministica per la descrizione di logica complessa in una
forma naturale e comprensibile
• Offre la possibiltà di definire funzioni in maniera grafica attraverso di-
agrammi di flusso, in maniera procedurale tramite il linguaggio MAT-
LAB e in forma tabellare con le tabelle della verità.
• Schedula le transizioni e gli eventi usando una logica temporale

6
• Supporta le macchine a stati finiti di Mealy e di Moore

• Anima i diagrammi Stateflow e i dati di log durante la simulazione per


migliorare la comprensione del sistema e facilitare il debugging

• Include un debugger integrato per impostare breakpoints grafici, pro-


cedere a passi attraverso gli schemi e passare in rassegna i dati.

7
Capitolo 2

Real Time Workshop

Real-Time Workshop genera codice ANSI C/C++ ottimizzato dai modelli


Simulink per creare implementazioni dei modelli standalone che operano in
real-time o non-real-time in un varietà di ambienti target. Il codice generato
può essere eseguito su hardware PC, DSP , microcontrollori e tramite sistemi
operativi real-time proprietari (RTOS). Il Real-Time Workshop aumenta la
velocità di simulazione, la protezione della proprietà intellettuale e la prototi-
pazione su diversi targets. La figura mostra il ruolo del Real-Time Workshop
nel processo di progettazione del software.
Il Real-Time Workshop è un sistema aperto progettato per essere utilizzato

con una larga varietà di ambienti operativi e tipi di hardware. Il proces-

8
so di generazione dei programmi tramite Real-Time Workshop può essere
configurato secondo le proprie esigenze modificando i seguenti componenti:

• Simulink ed il file modello (model.mdl)


Simulink fornisce un ambiente di sviluppo con linguaggio ad alto livel-
lo(VHLL). Gli elementi del linguaggio sono i blocchi e sottosistemi che
interpretano visivamente gli algoritmi. Si può pensare al Real-Time
Workshop come ad un compilatore che processa programmi sorgen-
ti VHLL (model.mdl) e genera codice utilizzabile da un compilatore di
linguaggi ad alto livello tradizionale. Le S-functions scritte in C o C++
estendono il linguaggio VHLL di Simulink aggiungendo nuovi blocchi
e funzionalità.

• La descrizione di modello intermedia (model.rtw)


La fase iniziale del processo di generazione del codice consiste nell’ana-
lizzare il modello sorgente. Il file di descrizione risultante contiene una
struttura gerarchica di records che descrivono i sistemi, i blocchi e le
loro connessioni.
L’ S-function API include una funzione speciale (mdlRTW) che per-
mette di personalizzare il processo di generazione del codice inserendo
parametri dai propri blocchi nel file model.rtw.

• Il programma Target Language Compiler (TLC)


Il Target Language Compiler legge la descrizione del modello interme-
dia e genera il codice che implementa il modello come un programma.
Si possono personalizzare gli elementi del TLC in due modi. Il pri-
mo consiste nell’implementare un proprio system target file che ha il
controllo completo sui parametri di generazione del codice, il secon-
do nell’implementare i block target files che controllano come venga
generato il codice per i blocchi individuali quali ad esempio i blocchi
S-function.

• Il codice sorgente generato dal modello


Ci sono diversi metodi per personalizzare il codice generato o interfac-
ciarlo a del codice personalizzato:

– Gli entry points esportati permettono di interfacciare il proprio


codice scritto a mano al codice generato. Questo rende possibile
lo sviluppo di un proprio meccanismo di esecuzione e di temporiz-
zazione nonchè di combinare il codice generato da più modelli in
un solo eseguibile.

9
– Si può rendere visibile al codice esterno ogni segnale, parametro e
altra struttura dati rendendo più facile il tuning dei parametri e
la monitorizzazione dei segnali.
– E’ possibile modificare o preparare i files di script del Target Lan-
guage Compiler per personalizzare la trasformazione dei blocchi
Simulink in codice sorgente.

• File di supporto all’interfaccia run-time


L’interfaccia run-time consiste in un codice che si interfaccia al codice
generato del modello. Si possono creare una svariata serie di file di
interfaccia ( protocolli di comunicazione, timers, interrupts, etc.).

• Il template makefile e model.mk


Il makefile model.mk controlla la compilazione e il linking del codice
generato. Il Real-Time Workshop genera model.mk da un template
makefile durante la fase di generazione del codice. E’ possibile creare
un template makefile personalizzato per controllare le opzioni di com-
pilazione e le variabili del processo di make.

Tutte queste componenti contribuiscono al processo di trasformazione di un


modello Simulink in un programma eseguibile. La figura 2.1 riporta il dia-
gramma di flusso di questo processo.

2.1 Scelta e configurazione del target


Il primo passo per impostare un file per la generazione di codice è scegliere
e configurare un sistema target. Il processo di creazione di codice specifico
per il target è controllato da:

• Un system target file

• Un template makefile

• Un comando make

E’ possibile specificare queste informazioni di configurazione per uno specifico


target in un solo passo usando il System target File Browser. Il browser
elenca una serie di configurazioni ottimizzate pronte all’uso. Una volta scelto
il target, Real-Time Workshop modifica le impostazioni della configurazione
corrente per renderla compatibile con il system target file corrispondente.

10
Figura 2.1: Real-Time Workshop Flowchart

2.2 File sorgenti generati e dipendenze dei


file
I file sorgenti e i make files creati da Real-Time Workshop vengono generati
dentro la propria build directory che viene creata nella directory corrente.
Alcuni file vengono generati incondizionatamente mentre l’esistenza degli al-
tri dipende dalle impostazioni del target.
Per esempio il pacchetto file del target Real-Time Workshop Embedded coder
differisce leggermente dal pacchetto descritto qui sotto. Le dipendenze dei
file sorgenti generati da Real-Time Workshop sono mostrate in figura 2.2. Le
freccie che partono da un file puntano ai files che esso include. Come mostra-
to dalla figura esistono anche altre dipendenze rispetto ai file di intestazione
di Simulink tmwtypes.h, simstruc types.h e rtlibsrc.h e ai file delle librerie C
e C++.
Il diagramma mostra le relazioni di inclusione unicamente tra i file generati

11
Figura 2.2: File generati e dipendenze

nella directory di build. Il diagramma mostra anche che il file di intestazione


del sistema genitore (model.h) include tutti i file di intestazione dei sottosis-
temi figli (subsystem.h). In modelli a più livelli naturalmente i sottosistemi
includono similiarmente i file di intestazione di propri figli e cosı̀ via nella ger-
archia del modello. Come conseguenza i sottosistemi sono capaci di vedere
ricorsivamente in tutti i sottosistemi discendenti cosı̀ come nel sistema radice
perchè tutti i subsystem.c includono model.h e model private.h.

2.3 Esecuzione del modello


Real-Time Workshop genera codice algoritmico cosı̀ come è stato definito nel
proprio modello. E’ possibile includere il proprio codice nel modello utiliz-
zando le S-functions.
Real-Time Workshop è provvisto anche di una interfaccia run-time che es-
egue il codice generato del modello. L’interfaccia run-time ed il codice del
modello sono compilati insieme per creare l’eseguibile del modello. A noi
interessa sapere a livello concettuale come funziona l’esecuzione del modello
per sistemi single-tasking e multitasking in fase di simulazione ma soprat-
tutto in esecuzione real-time. Per la maggior parte dei modelli un’ambiente

12
multitasking risulterà in una esecuzione del modello più efficiente.
I concetti seguenti sono utili nella descrizione di come esegue il modello. Ri-
porto qui i nomi delle funzioni usate nei target GRT e ERT con tra parentesi
le analoghe chiamate GRT-compatibili.

• Inizializzazione: model initialize (MdlInitializeSizes, MdlInitialize-


SampleTimes, MdlStart) inizializza il codice di interfaccia run-time e
il codice del modello.

• ModelOutputs: Vengono chiamati tutti i blocchi nel modello che han-


no il campionamento al tempo corrente e viene prodotta la loro uscita.
model outputs (MdlOutputs) può essere eseguito nei passi temporali
maggiori o minori. Nei passi temporali maggiori l’uscita è data dal pas-
so corrente di simulazione, negli intervalli temporali minori l’interfaccia
run-time calcola le derivate per aggiornare gli stati continui.

• ModelUpdate: model update (MdlUpdate) chiama tutti i blocchi


del modello che hanno il campionamento al tempo corrente e aggiorna
i loro stati discreti.

• ModelDerivatives: Chiama tutti i blocchi del modello che hanno stati


continui e aggiorna le loro derivate. model derivatives è chiamato
solamente nei passi temporali minori.

• ModelTerminate: model terminate (MdlTerminate) termina il pro-


gramma se ha un tempo di esecuzione finito. Distrugge inoltre la strut-
tura dati del modello real-time, dealloca la memoria e può scrivere dei
dati su di un file.

2.3.1 Modelli per Sistemi Real-Time Single-Tasking


Lo pseudocodice che segue mostra l’esecuzione di un modello in un sistema
real-time single-tasking dove il modello viene eseguito a livello di interrupt.

rtOneStep()
{
Controllo interrupt overflow
Attivazione interrupt "rtOneStep"
ModelOutputs -- passo temporale maggiore.
LogTXY -- Log Tempo, stati e porte di uscita.
ModelUpdate -- passo temporale maggiore.
Integrate -- Integrazione nei passi temporali minori per

13
-- gli stati continui
ModelDerivatives
Do 0 o Più
ModelOutputs
ModelDerivatives
EndDo (Il numero di iterazioni dipende dal solutore.)
Calcolo derivate per aggiornare stati continui.
EndIntegrate
}

main()
{
Initializzazione (inclusa istallazione di rtOneStep come
interrupt service routine, ISR, per un clock real-time).
While(tempo < tempo finale)
Esecuzione processi in Background.
EndWhile
Mask interrupts (Disattiva rtOneStep dall’esecuzione.)
Completa tutti i Processi in Background.
Shutdown
}

L’esecuzione real-time single-tasking è molto simile all’esecuzione non-real-


time (simulazione) eccetto che invece di eseguire liberamente il codice la
funzione rt OneStep è pilotata da un interrupt del timer periodico.
Negli intervalli specificati dal tempo di campionamento di base del program-
ma l’ interrupt service routine (ISR) blocca i processi in background per es-
eguire il codice del modello. Il tempo di campionamento di base è il più veloce
nel modello. Se il modello ha blocchi continui allora il passo di integrazione
determina il tempo di campionamento di base.

2.3.2 Modelli per Sistemi Real-Time Multitasking


Lo pseudocodice che segue mostra come viene eseguito un modello in un sis-
tema real-time multitasking quando l’esecuzione è associata ad un interrupt.

rtOneStep()
{
Controllo interrupt overflow
Attivazione interrupt "rtOneStep"

14
ModelOutputs(tid=0) -- passo temporale maggiore.
LogTXY -- Log Tempo, stati e porte di uscita.
ModelUpdate(tid=0) -- passo temporale maggiore.
Integrate -- Integrazione nei passi temporali minori per
-- gli stati continui
ModelDerivatives
Do 0 o Più
ModelOutputs(tid=0)
ModelDerivatives
EndDo (Il numero di iterazioni dipende dal solutore.)
Calcolo derivate per aggiornare stati continui.
EndIntegrate
For i=1:NumTasks
If (hit in task i)
ModelOutputs(tid=i)
ModelUpdate(tid=i)
EndIf
EndFor
}

main()
{
Initializzazione (inclusa istallazione di rtOneStep come
interrupt service routine, ISR, per un clock real-time).
While(time < final time)
Esecuzione processi in Background.
EndWhile
Mask interrupts (Disattiva rtOneStep dall’esecuzione.)
Completa tutti i Processi in Background.
Shutdown
}

Eseguire modelli a livello interrupt in un ambiente real-time multitasking


è molto simile ad eseguirli nel precedente ambiente single-tasking con l’ec-
cezione che interruzioni sovrapposte sono adoperate per l’esecuzione concor-
rente dei processi.

15
2.4 Temporizzazione del Programma
I programmi real-time richiedono una temporizzazione attenta per l’invo-
cazione dei task per assicurare che il codice del modello termini la sua es-
ecuzione prima che avvenga un’altra chiamata del task. Questo include il
tempo per leggere e scrivere dati da e verso hardware esterno.
La figura 2.3 mostra la temporizzazione dell’interruzione. L’intervallo di

Figura 2.3: Task timing

campionamento deve essere abbastanza grande da permettere l’esecuzione


del codice del modello tra le invocazioni dei task.
Nella figura 2.3 il tempo tra due frecce verticali adiacenti è l’intervallo di
campionamento. Il primo diagramma mostra un esempio di come un pro-
gramma possa completare un passo all’interno dell’intervallo lasciando anco-
ra del tempo per eseguire i processi in background. Il diagramma inferiore
mostra cosa succede se l’intervallo di campionamento è troppo corto: Si ha
un’altra invocazione di processo prima che il processo sia completato ovvero
avviene un errore di esecuzione.
Come mostra l’esempio precedente un programma real-time non può richiedere
il 100% del tempo della CPU. Questo garantisce l’opportunità di eseguire pro-
cessi in background nel tempo libero.
E’ importante comunque che il programma sia capace di prelazionare i pro-
cessi in background al tempo appropiato per assicurare l’esecuzione real-time
del codice del modello.

16
2.5 Differenze tra i Modelli di Esecuzione Rapid
Prototyping ed Embedded
Il Rapid Prototyping fornisce una interfaccia di programmazione delle ap-
plicazioni (API) che non cambia tra le definizioni di modello. L’ Embed-
ded Coder invece fornisce una API ottimizzata su misura al proprio modello.
Quando viene utilizzato lo stile embedded di generazione del codice la model-
lazione viene fatta nel modo in cui si vuole che esegua il codice nel sistema
embedded.
Una delle maggiori differenze tra lo stile di generazione del codice Rapid
Prototyping ed Embedded è che quest’ultimo contiene meno funzioni entry-
point. Lo stile di codice Embedded può essere configurato per avere un unica
funzione run-time, model step.
Quindi facendo riferimento allo pseudocodice di esecuzione del modello pre-
sentato prima si possono eliminare gli statements Loop...EndLoop e rag-
gruppare ModelOutputs, LogTXY e ModelUpdate in un singolo statement,
model step.

2.5.1 Funzioni del Modello Embedded


Il target Real-Time Workshop Embedded Coder genera le seguenti funzioni:

• model initialize: Si occupa di tutte le inizializzazioni del modello


e deve essere chiamata una volta prima di avviare l’esecuzione del
modello.

• Se è stata selezionata l’opzione di generazione del codice Single out-


put/update function allora si avrà

– model step(int T tid): Contiene il codice di uscita e di update


per tutti i blocchi del modello.

Altrimenti si avrà

– model output(int T tid): Contiene il codice di uscita per tutti


i blocchi del modello.
– model update(int T tid): Contiene il codice di update per tutti
i blocchi del modello.

• Se l’opzione di generazione del codice Terminate function required


è selezionata si avrà anche

17
– model terminate: Questa funzione contiene tutto il codice di
terminazione e deve essere chiamato come parte dello spegnimento
del sistema.

Altre informazioni più specifiche sono nel capitolo 3 relativo al Real-Time


Workshop Embedded Coder.
Ogni blocchetto Simulink ha un tempo di campionamento. I blocchi nella
categoria inherited acquistano il tempo di campionamento dai blocchi che li
precedono. I blocchi continui hanno un tempo di campionamento nominale
di zero. E’ possibile progettare blocchetti che lavorano a differenti tempi di
campionamento per le porte di ingresso e di uscita, questi blocchi hanno il
tempo di campionamento specificato sulle porte. Quindi è possibile avere
blocchi con differenti tempi di campionamento nel modello. Un possibile
vantaggio di utilizzare tempi di campionamento multipli è l’aumentata effi-
cienza che si ottiene quando si esegue il modello in un ambiente real-time
multitasking.
Simulink prevede una certa flessibilità nella creazione di sistemi multirate.
Tuttavia, la stessa flessibilità permette anche di costruire modelli per i quali
il generatore di codice non è in grado di generare codice real-time corretto
per l’esecuzione in un sistema multitasking.
Per far eseguire correttamente i modelli multirate in real-time a volte è nec-
essario modificare i modelli o istruire Simulink per farli modificare a lui. In
generale le modifiche riguardano il piazzamento di blocchetti Rate Transi-
tion tra i blocchi con tempi di campionamento differenti.
I prossimi paragrafi illustrano le procedure per utilizzare con successo un
modello in un ambiente multitasking.

2.6 Esecuzione di Modelli Multitasking


Nei casi in cui la parte continua del modello esegua ad un rate differente dalla
parte discreta oppure un modello abbia blocchi con tempi di campionamen-
to differenti Simulink assegna a ciascun blocco un identificatore di processo
(tid) per associare il blocco con il processo che va in esecuzione al tempo di
campionamento del blocco.
I tempi di campionamento si selezionano nel pannello Configuration Pa-
rameters - Solver. Per generare codice con Real-Time Workshop si deve
selezionare come tipo di solutore un solutore a passo fisso. Si hanno alcune
restrizioni sui tempi di campionamento che si possono utilizzare.

18
• Il tempo di campionamento di ciascun blocco deve essere un multiplo
intero del tempo di campionamento base(il più veloce).

• I blocchi continui vengono eseguiti utilizzando un algoritmo di inte-


grazione che gira al tempo di campionamento base. Il periodo di cam-
pionamento base è il massimo comun denominatore di tutti i rates del
modello se la dimensione del passo di integrazione è impostata su auto.

• Le parti continue e discrete del modello possono eseguire a rates differ-


enti solo se la parte discreta esegue ad un rate uguale o minore della
parte continua ed è un multiplo intero del rate di campionamento base.
Quando vengono eseguiti dei processi periodici in modalità multitasking, di
default i blocchi con frequenza di campionamento maggiore vengono eseguiti
dai processi con la più alta priorità, i successivi blocchi più veloci vengono
eseguiti da processi con la successiva priorità più alta. Questo rende l’ese-
cuzione del programma efficiente.
Quando i processi sono asincroni invece che periodici non c’è necessariamente
una relazione stretta tra tempi di campionamento e priorità dei processi. Le
priorità per i processi asincroni possono essere specificate utilizzando i bloc-
chi Async Interrupt e Task Synchronization.
Si può cambiare il significato del numero di priorità selezionando o deselezio-
nando l’opzione Higher priority value indicates higher task priority
nel pannello Solver.
Negli ambienti multitasking si possono definire processi separati e assegnare
loro delle priorità. Nei target bare-board invece non si possono creare task
separati. Tuttavia, i moduli di applicazione di Real-Time Workshop im-
plementano quello che in effetti è uno schema di esecuzione multitasking
utilizzando interrupts innestati seguiti da cambi di contesto programmatici.

2.7 Transizioni della Frequenza di Campiona-


mento
In un modello Simulink possono avvenire due tipologie di transizione tra
sample rate periodici:
• Un blocco più veloce che pilota un blocco più lento

• Un blocco più lento che pilota un blocco più veloce


Le prossime sezioni fanno riferimento esclusivamente a modelli con tempi di
campionamento periodici e senza offset. Altre considerazioni si applicano ai

19
modelli multirate che utilizzano processi asincroni (vedi paragrafo 2.9.1).
Nei sistemi single-tasking non ci sono problemi nell’avere più tempi di cam-
pionamento. Nei sistemi multitasking o pseudomultitasking invece differenti
frequenze di campionamento possono causare problemi facendo eseguire i
blocchi nell’ordine sbagliato. Per prevenire errori nei dati calcolati si deve
quindi controllare l’esecuzione del modello durante queste transizioni. Quan-
do si connettono blocchi più veloci e più lenti si devono aggiungere blocchetti
Rate Transition tra essi (o dobbiamo farli aggiungere da Simulink).

2.7.1 Problemi di Trasferimento Dati


Per capire il funzionamento dei blocchi Rate Transition devo introdurre i
concetti di integrità dei dati e determinismo associati al trasferimento dati
tra blocchi che eseguono a rates differenti.

• Integrità dei dati: Si ha un problema di integrità dei dati quando


il dato in ingresso ad un blocco cambia durante l’esecuzione di quel
blocco. Questo problema può essere causato dalla preemption.
Consideriamo il seguente scenario:

– Un blocco più veloce fornisce l’ingresso ad un blocco più lento.


– Il blocco più lento legge un valore di ingresso V1 dal blocco più
veloce e inizia i calcoli utilizzando quel valore.
– Durante i calcoli si ha preemption da parte di un’altra esecuzione
del blocco più veloce che genera un nuovo valore di uscita V2.
– A questo punto avviene un problema di integrità dei dati: Quando
il blocco più lento ritorna ad eseguire continua i suoi calcoli usando
tuttavia il nuovo valore di input V2.

Questo tipo di trasferimento dati viene chiamato non protetto. In


un trasferimento dati protetto l’uscita V1 del blocco più veloce viene
mantenuta fino a che il blocco più lento non finisce di eseguire.

• Determinismo: In un trasferimento dati deterministico la temporiz-


zazione del trasferimento dati è completamente predicibile ed è deter-
minata dal tempo di campionamento dei blocchi.
La temporizzazione di un trasferimento dati non deterministico dipende
dalla disponibilità dei dati, dai rates di campionamento dei blocchi e
dal tempo nel quale il blocco in ricezione comincia ad eseguire rispetto
al blocco pilota.

20
Utilizzando il blocchetto Rate Transition è possibile assicurare che i trasferi-
menti dati nella propria applicazione siano sia protetti che deterministici. Se
queste caratteristiche non sono desiderate è possibile tuttavia compromettere
l’integrità dei dati e il determinismo in favore di una minore latenza.

2.7.2 Assunzioni sul Trasferimento Dati


Quando si processano dei trasferimenti di dati tra i blocchi del modello,
Real-Time Workshop assume le seguenti cose:

• Le transizioni di dati avvengono tra un singolo processo in lettura e un


singolo processo in scrittura.

• La lettura o scrittura di una variabile di dimensione del byte è atomica.

• Quando due processi interagiscono tramite uno scambio di dati sola-


mente uno di loro può effettuare preemption sull’altro.

• Per i processi periodici, il processo con il rate più veloce ha la priorità


maggiore rispetto al processo con il rate più lento.

• Tutti i processi girano su di un singolo processore. Il time slicing non


è permesso.

• I processi non vanno in crash ne si riavviano.

2.7.3 Opzioni del Blocco Rate Transition


Molti parametri del blocco Rate transition sono rilevanti all’utilizzo durante
la generazione di codice per l’esecuzione real-time. Questo blocco gestisce sia
transizioni periodiche che asincrone. Quando viene inserito tra due blocchi
con differenti rates di campionamento configura automaticamente i rates di
campionamento del suo ingresso e uscita per l’appropiato tipo di transizione.
La decisione importante che viene fatta quando si configura il blocco Rate
Transition è la scelta del meccanismo di trasferimento dati. Questa scelta
dipende da considerazioni sulla sicurezza, utilizzo di memoria e prestazioni.
Facendo riferimento alla figura 2.4 il meccanismo di trasferimento dati è
controllato da due opzioni:

• Ensure data integrity during data transfer: Quando questa opzione


è attiva viene garantita l’integrità dei dati trasferiti. Se è disattivata il
trasferimento dati non è protetto.

21
Figura 2.4: Configurazione blocco Rate Transition

• Ensure deterministic data transfer (maximum delay): Questa


opzione è supportata per processi periodici con offset zero e rates che
sono multipli fra di loro. Quando questa opzione è attiva il blocco Rate
Transition si comporta come un blocco Zero-Order Hold nel caso di
transizione da veloce a lento o come un blocco Unit Delay nel caso
di transizione da lento a veloce. Per le transizioni asincrone questa
opzione non può essere selezionata.

Il blocco Rate Transition offre dunque tre differenti modalità di operazione


per il trasferimento dati.

• Protetta e Deterministica: Questa è la modalità più sicura ma intro-


duce della latenza nel sistema. Per le transizioni da veloce a lento
la latenza massima è un periodo di campionamento del processo più
lento, per le transizioni da lento a veloce invece è di due periodi di
campionamento del processo più lento.

• Protetta e Non Deterministica: In questa modalità le transizioni da


lento a veloce vengono fatte tramite double-buffer, le transizioni da

22
veloce a lento usano invece un semaforo. La latenza massima in questo
caso è minore uguale ad un periodo di campionamento del processo più
veloce.

• Non Protetta e Non Deterministica: In questa modalità è come se il


rate transition non ci fosse. La latenza è uguale a quella della modalità
precedente ma il codice prodotto è molto inferiore.

2.7.4 Automatic Rate Transition


Simulink può accorgersi di problemi di transizione dati in un modello mul-
titasking ed inseririre automaticamente i blocchi Rate Transition per ge-
stirli. Per far questo si deve abilitare l’opzione Automatically handle
data transfers between tasks nel pannello Solver dei parametri di con-
figurazione. In questo modo Simulink gestirà tutte le transizioni tra tem-
pi di campionamento periodici e processi asincroni, inserirà blocchi Rate
Transition non visibili nel diagramma del modello e Real-Time Workshop
genererà codice per questi blocchi come se fossero stati inseriti manualmente.
Questi blocchi operano nella modalità protetta e deterministica per i processi
periodici e solo protetta per i processi asincroni.

2.8 Utilizzo delle S-Functions


Le S-function aiutano a risolvere molte tipologie di problemi che sorgono
lavorando con Simulink e Real-Time Workshop. Questi problemi includono

• L’estenzione dell’insieme di algoritmi forniti da Simulink e Real-Time


Workshop

• Interfacciare il codice scritto a mano con Simulink e Real-Time Work-


shop

• Interfacciarsi all’hardware tramite device driver

• Generare codice altamente ottimizzato per sistemi embedded

Le S-functions sono scritte attraverso una intefaccia di programazione delle


applicazioni(API) che permette di implementare algoritmi generici in Simulink
con una grande flessibilità. Nello stesso tempo questa flessibilità viene ridot-
ta quando si va ad utilizare Real-Time Workshop. Nonostante le S-functions
forniscano una soluzione flessibile e generica per l’implementazione di com-
plessi algoritmi in Simulink l’API utilizzata genera overhead in termini di

23
memoria e risorse di calcolo. Nel caso di applicazioni su sistemi embed-
ded real-time queste risorse addizionali generalmente non sono disponibili.
Si possono però diminuire i requisiti dell’applicazione utilizzando il Target
Language Compiler fornito con il Real-Time Workshop per rendere le
S-function inlined.

2.8.1 Tipi di S-Function


L’implementazione delle S-function cambia in base ai propri requisiti. Ci
sono in generale delle situazioni comuni:

1. ‘Non mi interessa l’efficienza. Voglio scrivere una versione del mio al-
goritmo che giri su Simulink e Real-Time Workshop automaticamente.’

2. ‘Ho un sacco di codice scritto a mano che devo interfacciare. Voglio


poterlo richiamare da Simulink e Real-Time Workshop in una maniera
efficiente.’

3. ’Voglio implementare un algoritmo altamente ottimizzato che sembra


un blocco built-in e genera un codice efficiente.’

Per ognuna di queste richieste c’è una specifica terminologia adottata in


Matlab. Facendo riferimento alle situazioni si parlerà rispettivamente di:

1. Noninlined S-function

2. Wrapper S-function

3. Fully inlined S-function

2.8.2 Noninlined S-Functions


Una noninlined S-function è un funzione MEX C o C++ che viene trattata
allo stesso modo da Simulink e Real-Time Workshop. Sono richiesti calcoli e
memoria aggiuntiva per ogni istanza del blocco noninlined S-function. Tut-
tavia questo tipo di S-function è tipico durante la fase di prototipizzazione
quando l’efficienza non è importante. Il vantaggio guadagnato a sfavore del-
l’efficienza è l’abilità di cambiare i parametri del modello rapidamente.
Scrivere noninlined S-function non richiede nussun codice TLC.

24
2.8.3 Wrapper S-Functions
Una wrapper S-function è ideale per interfacciare il codice scritto a mano o
un grosso algoritmo incapsulato in diverse procedure. In questa situazione di
solito le procedure risiedono in moduli separati dalla S-function. Il modulo
S-function contiene delle chiamate alle proprie procedure. Poichè l’S-function
contiene solo chiamate e nessun codice viene chiamata wrapper S-function.
Oltre alla wrapper MEX S-function è necessario creare un TLC wrapper che
complementa la funzione. Il codice TLC rispecchia il codice dell’S-function
presentando solamente chiamate di funzione.

2.8.4 Fully Inlined S-Functions


Per far lavorare correttamente le S-function in ambiente Simulink è neces-
saria una certa quantità di codice di overhead. Quando Real-Time Workshop
genera codice da modelli che contegono S-function (senza file sfunction.tlc)
inserisce questo codice di overhead nel codice generato. Quindi se si vuol
ottimizzare il proprio codice real-time e eliminare l’overhead si deve rendere
le S-function inlined. Questo richiede la scrittura di un file TLC che istruisca
Real-Time Workshop su quali ottimizzazioni fare. Il Target Language Com-
piler processa i file sfunction.tlc per definire come inserire l’algoritmo della
S-function nel codice generato.
Una fully inlined S-function realizza il proprio algoritmo in Simulink e Real-
Time Workshop in una maniera indistinguibile dai blocchi built-in. Scrivere
una tale S-function richiede quindi di implementare il proprio algoritmo due
volte: una volta per Simulink (C/C++ MEX S-function) e una volta per
Real-Time Workshop (file TLC). La complessità del file TLC dipende dalla
complessità dell’algoritmo e dal livello di efficienza che si vuole ottenere.
La scrittura di una fully inlined S-function può richiedere il piazzamento del-
la routine mdlRTW nei file MEX sfunction.c o sfunction.cpp. La routine
mdlRTW permette di modificare l’informazione contenuta nel file model.rtw
che contiene i record del modello. Questo file viene processato dal Target
Language Compiler prima di cominciare ad eseguire sfunction.tlc e generare
codice.
Includere una routine mdlRTW è utile se si vuole passare parametri non-
tunable al file TLC. Questi parametri sono generalmente utilizzati per de-
terminare la modalità operativa del nostro algoritmo. Basandosi su questa
informazione, il file TLC rispettivo può generare codice altamente efficiente
e ottimizzato per la modalità operativa richiesta.

25
Nei prossimi paragrafi voglio mostrare come generare una semplice wrap-
per S-function e i vantaggi che conseguono dal rendere tale S-function inlined.

2.8.5 MEX S-Function Wrapper


Creare S-function utilizzando un wrapper permette di inserire algoritmi C/C++
in Simulink e Real-Time Workshop con pochi o addirittura nessun cambia-
mento alle proprie funzioni C/C++ originali.
Supponiamo di avere un algoritmo di nome my alg contenuto nel file my alg.c.
E’ possibile integrare tale algoritmo in Simulink creando un MEX S-function
wrapper (ad esempio wrapsfcn.c). Dopo aver fatto questo Simulink può
chiamare my alg da un blocco S-function. Nonostante questo la S-function
Simulink contiene un insieme di funzioni vuote richieste da Simulink per vari
scopi relativi all’API.
E’ possibile poi integrare my alg nel codice generato dal Real-Time Work-
shop creando una TLC wrapper S-function (wrapsfcn.tlc). Il vantaggio di
creare un wrapper TLC è che le chiamate di funzione vuote possono essere
eliminate ed anche l’overhead dell’esecuzione della funzione mdlOutputs che
ha l’unico compito di chiamare la funzione my alg.
Utilizzare una wrapper S-function per importare algoritmi nel proprio model-
lo Simulink significa che l’S-function funziona come un interfaccia che chiama
gli algoritmi C/C++ da mdlOutputs.
Vediamo ora un semplice esempio di una wrapper S-function:

// File wrapsfcn.c

#define S_FUNCTION_NAME wrapsfcn


#define S_FUNCTION_LEVEL 2
#include "simstruc.h"

extern real_T my_alg(real_T u); /* Dichiaro my_alg come extern */

/*
* mdlInitializeSizes - initializzo le dimensioni degli array
*/

static void mdlInitializeSizes(SimStruct *S)


{
ssSetNumSFcnParams( S, 0); /*numero di argomenti in ingresso*/
if (!ssSetNumInputPorts(S, 1)) return;
ssSetInputPortWidth(S, 0, 1);

26
ssSetInputPortDirectFeedThrough(S, 0, 1);
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetNumSampleTimes( S, 1);
}

/*
* mdlInitializeSampleTimes - questa impostazione indica che il tempo
* di campionamento è derivato dal blocco pilota
*/

static void mdlInitializeSampleTimes(SimStruct *S)


{
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}

/*
* mdlOutputs - calcola l’uscita chiamando my_alg
*/

static void mdlOutputs(SimStruct *S, int_T tid)


{
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
real_T *y = ssGetOutputPortRealSignal(S,0);
*y = my_alg(*uPtrs[0]); /* chiamo my_alg in mdlOutputs */
}

/*
* mdlTerminate - funzione chiamata quando termina il programma.
*/

static void mdlTerminate(SimStruct *S)


{
}

#ifdef MATLAB_MEX_FILE /* è un MEX-file? */


#include "simulink.c" /* meccanismo di interfaccia MEX-file */
#else
#include "cg_sfun.h" /* funzione della generazione di codice */
#endif

27
La routine mdlOutputs dell’S-function contiene una chiamata di funzione a
my alg che è la funzione C che contiene l’algoritmo da eseguire. Questo è
invece il codice di esempio per my alg.c:

#ifdef MATLAB_MEX_FILE
#include "tmwtypes.h"
#else
#include "rtwtypes.h"
#endif

real_T my_alg(real_T u)
{
return(u * 2.0);
}

La wrapper S-function wrapsfcn chiama my alg che calcola u ∗ 2.0.

2.8.6 TLC S-Function Wrapper


Nell’esempio precedente la chiamata a my alg è inserita nella sezione md-
lOutputs come

*y = my_alg(*uPtrs[0]);

Quando si va a creare una TLC wrapper S-function si ha come obbiettivo


il far inserire al Real-Time Workshop la stesso tipo di chiamata nel codice
generato.
Il codice generato quando si usa grt.tlc come system target file senza wraps-
fcn.tlc è il seguente:

#include <math.h>
#include <string.h>
#include "wrapper.h"
#include "wrapper.prm"

/* Start the model */


void mdlStart(void)
{
/* (no start code required) */
}

28
/* Compute block outputs */
void mdlOutputs(int_T tid)
{
/* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
{
/* Le S-functions noninlined creano un oggetto SimStruct e
* generano una chiamata alla routine mdlOutputs dell’S-function
*/
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnOutputs(rts, tid);
}

/* Outport Block: <Root>/Out */


rtY.Out = rtB.S_Function;
}

/* Perform model update */


void mdlUpdate(int_T tid)
{
/* (no update code required) */
}

/* Terminate function */
void mdlTerminate(void)
{
/* Level2 S-Function Block: <Root>/S-Function (wrapsfcn) */
{
/* Le S-functions noninlined richieddono un oggetto SimStruct e
* la chiamata alla routine mdlTerminate dell’S-function
*/
SimStruct *rts = ssGetSFunction(rtS, 0);
sfcnTerminate(rts);
}
}

#include "wrapper.reg"
/* [EOF] wrapper.c */

In aggiunta all’overhead illustrato sopra il file generato wrapper.reg contiene


l’inizializzazione della SimStruct per il blocco wrapper S-function.
E’ possibile ridurre significativamente questo overhead creando un wrapper

29
TLC per l’S-function.
Il codice generato effettua la chiamata alla S-function (wrapsfcn.c) in md-
lOutputs attraverso questo codice:

SimStruct *rts = ssGetSFunction(rtS, 0);


sfcnOutputs(rts, tid);

Questa chiamata ha dell’overhead computazionale: Simulink crea una strut-


tura SimStruct per il blocco, Real-Time Workshop costruisce una chiamata
attraverso un puntatore di funzione per eseguire mdlOutputs e infine md-
lOutputs chiama my alg.
Utilizzando un file wrapsfcn.tlc è possibile eumentare l’efficienza e ridurre
la dimensione del codice generato. Il codice seguente mostra come fare il
wrapper TLC per piazzare la chiamata di funzione nel codice generato.

%% File : wrapsfcn.tlc

%implements "wrapsfcn" "C"

%% Function: BlockTypeSetup

%function BlockTypeSetup(block, system) void


%openfile buffer
extern real_T my_alg(real_T u); /* questa linea viene messa in
wrapper.h */
%closefile buffer
%<LibCacheFunctionPrototype(buffer)>
%endfunction %% BlockTypeSetup

%% Function: Outputs

%function Outputs(block, system) Output


/* %<Type> Block: %<Name> */
%assign u = LibBlockInputSignal(0, "", "", 0)
%assign y = LibBlockOutputSignal(0, "", "", 0)
%% la linea seguente è espansa e messa in mdlOutputs
%% all’interno di wrapper.c
%<y> = my_alg(%<u>);
%endfunction %% Outputs

La prima sezione di questo codice dice a Real-Time Workshop di lavorare


sulla wrapsfcn S-function e di generare codice in C:

30
%implements "wrapsfcn" "C"
Il compito successivo è quello di istruire Real-Time Workshop che la rou-
tine my alg deve essere dichiarata extern nel file generato wrapper.h. Poichè
questa operazione va fatta una sola volta per ogni blocco wrapsfcn S-function
viene utilizzata la funzione BlockTypeSetup. In questa funzione si dice al
Target Language Compiler di creare un buffer e di inserire il buffer che con-
tiene la dichiarazione di my alg come extern all’interno del file di intestazione
generato wrapper.h.
Il passo finale è di inserire la chiamata alla funzione my alg. Questo viene
fatto nella funzione Outputs. In questa funzione si accede all’ingresso e us-
cita del blocco e si piazza una chiamata diretta a my alg che verrà inserita
in wrapper.c.
Il codice generato utilizzando il wrapper TLC è simile al codice generato di
default ma la funzione mdlTerminate non contiene più una chiamata ad una
funzione vuota e mdlOutputs chiama direttamente my alg.
void mdlOutputs(int_T tid)
{
/* S-Function Block: <Root>/S-Function */
rtB.S_Function = my_alg(rtB.U); /* chiamata a my_alg inserita
nel codice */
/* Outport Block: <Root>/Out */
rtY.Out = rtB.S_Function;
}
Oltre a questo wrapper.reg non crea più una SimStruct figlia per la S-function
il che fa risparmiare più di 1 K di memoria.

2.8.7 Fully Inlined S-Functions


Continuando l’esempio della sezione precedente è possibile eliminare comple-
tamente la chiamata a my alg specificando il codice esplicito (in questo caso
2.0 ∗ u) all’interno di wrapsfcn.tlc. Questo rende l’S-function fully inlined.
Per rendere inlined l’algoritmo dell’esempio basta sostituire nella sezione
Outputs del file wrapsfcn.tlc
%<y> = my_alg(%<u>);
con
%<y> = 2.0 * %<u>;
Questo è il codice prodotto in mdlOutputs:

31
void mdlOutputs(int_T tid)
{
/* S-Function Block: <Root>/S-Function */
rtB.S_Function = 2.0 * rtB.U; /* inserzione esplicita
dell’algoritmo */
/* Outport Block: <Root>/Out */
rtY.Out = rtB.S_Function;
}

Il Target Language Compiler ha rimpiazzato la chiamata a my alg con l’al-


goritmo stesso.

2.9 Utilizzo di Blocchi Asincroni di Interruzione


in Simulazione e Generazione del Codice
Questa sezione descrive un approccio a doppio-modello allo sviluppo ed im-
plementazione dei sistemi real-time che includono ISR. In Questa metodolo-
gia si sviluppa un modello che include l’impianto ed il controllore per la
simulazione e un’altro modello che include solamente il controllore per la
generazione del codice. Utilizzando una libreria Simulink si possono poi im-
plementare cambiamenti su entrambi i modelli simultaneamente.
La figura 2.5 mostra questo tipo di approccio e come le modifiche fatte nella
libreria si propaghino ai modelli. E’ possibile anche un approccio a modello

Figura 2.5: Approccio a doppio-modello

32
singolo dove la componente dell’impianto è attiva solamente in simulazione.
Durante la generazione di codice la componente dell’impianto è effettiva-
mente tagliata fuori dal sistema e il codice viene generato solo per il blocco
di interruzione e la parte di controllo del modello.

2.9.1 Rate Transitions e Blocchi Asincroni


Poichè una chiamata di funzione asincrona può fare preemption o essere
prelazionata da altro codice del modello si ha una inconsistenza quando più
di elemento di un segnale è collegato ad un blocco asincrono. Il problema
è che il segnale può essere in processo di essere scritto o letto quando si ha
la preemption ottenendo qualche dato vecchio e qualche dato nuovo. Questa
situazione può avvenire anche nel caso di un segnale scalare a volte. Per
esempio se il segnale è un double le operazioni di lettura e scrittura potreb-
bero richiedere due istruzioni di macchina.
I problemi che riguardano la preemption possono essere risolti dal blocco
Simulink Rate Transition come spiegato precedentemente. Tale blocco tut-
tavia non può essere usato per garantire il determinismo per i blocchi asin-
croni.
Simulink non assegna le priorità ai blocchi asincroni per cui quando si creano
blocchi di questo tipo deve essere possibile specificare un livello di priorità.

33
Capitolo 3

Real Time Workshop


Embedded Coder

Real-Time Workshop Embedded Coder è un prodotto che si aggiunge al Real-


Time Workshop ed è utilizzato per lo sviluppo di sistemi embedded.
Il Real-Time Workshop fornisce una struttra di lavoro per lo sviluppo di
codice che è ottimizzata per quanto riguarda la velocità, l’utilizzo di memoria
e la semplicità. Genera codice ottimizzato in ANSI o ISO C per micropro-
cessori a virgola fissa e a virgola mobile.
Estende dunque le capacità del Real-Time Workshop per la produzione e il
testing di applicazioni su embedded targets. Il target Embedded Real-Time
(ERT) fornito con il Real-Time Workshop è progettato per essere personaliz-
zato. E’ una buona base di partenza per sviluppare codice per un particolare
microprocessore e interfacciarsi ad un sistema di cross-development.
In aggiunta alle caratteristiche supportate dal Real-Time Workshop , l’Em-
bedded Coder fornisce diverse altre feature tra le quali :

• Genera codice ANSI/ISO C o C++ ed eseguibili a partire da mod-


elli Simulink e Stateflow con un’utilizzo di memoria, una velocità di
esecuzione e una leggibilità paragonabile al codice scritto a mano.

• Estende Real-Time Workshop e Stateflow Coder con configurazioni del


codice e ottimizzazioni essenziali per una produzione commerciale

• Partiziona in maniera concisa il codice multirate per uno scheduling


efficiente con o senza l’ausilio di un sistema operativo real-time (RTOS).

• Fornisce un ricco insieme di possibilità di commento per seguire nel


codice le varie componenti del modello e le richieste.

34
• Fornisce un Model Advisor che controlla la configurazione del modello
e suggerisce consigli per l’ottimizzazione del codice.
• Fornisce una strategia chiamata rate grouping per i modelli multi-rate
multitasking che genera funzioni separate per il processo con rate di
base e i processi con sub-rate nel modello.
• Fornisce la capacità di verificare il codice prodotto permettendo di im-
portare il codice nuovamente in Simulink tramite una S-function per
un test di tipo software-in-the-loop con un modello di impianto.
• Documenta il codice generato in un report HTML che descrive i mod-
uli del codice e le impostazioni di configurazione applicate in fase di
generazione del codice.

3.1 Stuttura Dati del Modello Real-Time


Real-Time Workshop Embedded Coder inserisce le informazioni del modello
radice nella struttura dati rtModel del modello real-time.
Per ridurre le richieste di memoria rtModel contiene esclusivamente le infor-
mazioni richieste dal modello. Di default rtModel contiene un campo error
status per monitorare il codice. Se non utilizzato questo campo può essere
rimosso per ridurre l’utilizzo di memoria.
Le definizioni dei simboli per rtModel nel codice generato sono le seguenti:
• Definizione di struttura (in model.h):

struct _RT_MODEL_model_Tag {
...
};

• Dichiarazione typedef (in model types.h):

typedef struct _RT_MODEL_model_Tag RT_MODEL_model;

• Dichiarazioni di puntatori e variabili (in model.c o .cpp):

RT_MODEL_model model_M;
RT_MODEL_model *model_M = &model_M_;

• Dichiarazione di variabile esportata (in model.h):

extern RT_MODEL_model *model_M;

35
3.2 Esecuzione di Programmi Stand-Alone
Di default Real-Time Workshop Embedded Coder genera programmi stand-
alone che non richiedono sistemi operativi real-time esterni. Un progamma
stand-alone richiede qualche minima modifica per essere adattato all’hard-
ware di interesse. L’architettura di programma supporta l’esecuzione di mod-
elli con uno o più rates di campionamento.
Il nucleo di un programma stand-alone è il ciclo main. Ad ogni iterazione il
ciclo main esegue un processo di background o un processo vuoto e controlla
che si verifichi la condizione di terminazione.
Il ciclo main è interrotto periodicamente da un timer. La funzione Real-Time
Workshop rt OneStep o è installata come interrupt service routine (ISR) del
timer o è chiamata da una ISR del timer ad ogni passo di clock.
L’attività di rt OneStep differisce in base al modello generato. In un modello
single-rate rt OneStep chiama semplicemente la funzione model step. In un
modello multi-rate rt OneStep assegna priorità e schedula l’esecuzione dei
blocchi in accordo al loro rate di esecuzione.
Real-Time Workshop Embedded Coder genera codice molto differente nei
modelli multi-rate a seconda dei seguenti fattori:
• Nel caso in cui il modello esegua in modalità singletasking oppure
multitasking.

• Nel caso in cui venga generato oppure no codice riutilizzabile.


Questi fattori si ripercuotono sull’algoritmo di scheduling utilizzato nel codice
generato.

3.3 Programma Main


Lo pseudocodice seguente mostra l’esecuzione di un programma main del
Real-Time Workshop Embedded Coder.
main()
{
Inizializzazione (include l’installazione di rt_OneStep come
interrupt service routine per un clock real-time)
Inizializza e avvia timer hardware
Attiva interrupts
While(not Error) and (time < final time)
Background task
EndWhile

36
Disattiva interrupts (Disattiva rt_OneStep)
Completa tutti i background tasks
Shutdown
}

Lo pseudocodice è una guida per un programma tipo che serve a pilotare il


proprio modello. Naturalmente il file ert main.c o .cpp deve essere modificato
in accordo alle proprie specifiche.

3.4 rt OneStep
Le operazioni di rt OneStep differiscono se il modello è single-rate o multi-
rate e in base alla modalità del solutore(SingleTasking o MultiTasking).

3.4.1 Single-Rate Singletasking


L’unica modalità del solutore valida per un modello single-rate è SingleTask-
ing.
Lo pseudocodice seguente mostra il design di rt OneStep in un programma
single-rate.

rt_OneStep()
{
Controlla overflow dell’Interrupt o altri errori
Attiva "rt_OneStep" (timer) interrupt
Model_Step() -- Passo temporale con output,logging,update
}

Per il caso single-rate rt OneStep è progettata per eseguire model step all’in-
terno di un singolo periodo di clock. Per assicurare questa temporizzazione
rt OneStep mantiene e controlla un flag di timer overrun.
All’inizio le interruzioni sono disabilitate fino a che non è stato controllato
il flag di overrun e le altre condizioni di errore. Se il flag è clear rt OneStep
lo setta e procede con gli interrupt del timer attivati. Il flag viene poi pulito
solamente in seguito ad un ritorno con successo da model step.
Quindi se rt OneStep è riinterrotto prima di aver completato model step
la nuova interruzione viene scoperta attraverso il flag di overrun. Questa
è una condizione di errore che può essere gestita a piacimento. Di default
rt OneStep segnala un errore e ritorna immediatamente.

37
3.4.2 Multi-Rate Multitasking
Il seguente pseudocodice mostra il design di rt OneStep in un programma
multitasking multi-rate.

rt_OneStep()
{
Controlla base-rate interrupt overrun
Attiva "rt_OneStep" interrupt
Determina quali rates devono eseguire in questo passo
Model_Step0() -- esegui codice con il passo base-rate
For N=1:NumTasks-1 -- itera i sub-rate tasks
If (sub-rate task N è schedulato)
Controlla sub-rate interrupt overrun
Model_StepN() -- esegui codice passo sub-rate
EndIf
EndFor
}

L’esecuzione di blocchi aventi differenti rates di campionamento è divisa in


più processi. Ad ogni blocco che esegue ad un certo rate di campionamento
viene assegnato un identificatore di processo (tid) che lo associa con un task
che esegue a quel rate.
Ai processi vengono assegnate le priorità in ordine decrescente con il rate. Il
processo con il rate base è il processo che esegue più velocemente nel sistema
e gli viene assegnata la più alta priorità (tid 0). Il processo più lento avrà di
conseguenza la priorità più bassa (tid NumTasks-1).

3.4.3 Rate Grouping


In un modello single-rate tutti i calcoli dei valori di uscita dai blocchi sono
effettuati in una funzione sola, model step. Nel caso di modelli multi-rate
multitasking Real Time Workshop adotta un’altra strategia chiamata Rate
Grouping. Questa genera funzioni model step separate per il rate base e
ciascun processo sub-rate nel modello. La convenzione per la nomenclatura
di queste funzione è model stepN dove N è l’identificatore del processo.
Ciascuna funzione model stepN esegue tutti i blocchi che condividono il tid
N.
Ad ogni tick del clock rt OneStep e model step0 gestiscono i contatori della
schedulazione e i flag di evento per ogni processo sub-rate. I contatori ven-
gono implementati nei campi Timing.TaskCounters.TIDn di rtModel, i flag
di evento sono invece implementati come array indicizzati dal tid. I contatori

38
della schedulazione sono gestiti dalla funzione rate monotonic scheduler che
viene chiamata da model step0. I contatori sono in effetti divisori del clock
rate che contano fino al periodo di campionamento associato con ciascun pro-
cesso sub-rate.
I flag di evento indicano se un determinato processo è schedulato per l’ese-
cuzione. rt OneStep gestisce i flag di evento con la funzione model SetEventsFor-
ThisBaseStep. Quando un contatore indica che il tempo di campionamento
di un processo è passato model SetEventsForThisBaseStep imposta il flag di
evento per quel processo.
Ad ogni invocazione rt OneStep aggiorna la struttura dati del suo schedu-
latore e esegue un passo del processo base-rate. Successivamente itera tra i
flag dello schedulatore in ordine di tid chiamando incondizionatamente mod-
el stepN per ogni task il cui flag è impostato. Questo assicura che i processi
sono eseguiti in ordine di priorità.
Naturalmente le interruzioni devono essere disabilitate prima della chiamata
a rt OneStep. L’array dei flag di evento e le variabili di loop usate sono
salvate come variabili locali nello stack cosı̀ da assicurare che il codice sia
rientrante.
L’ rt OneStep per modelli multi-rate gestisce anche un array di flag per il
timer overrun. La logica con cui si controlla l’overrun di ogni singolo processo
è la stessa usata per i modelli single-rate.

3.4.4 Multi-Rate Singletasking


In un programma multi-rate singletasking tutti i tempi di campionamen-
to nel modello devono essere multipli interi della dimensione del passo fisso
del modello. Il funzionamento di rt OneStep in questo caso è una versione
semplificata di quella multi-rate multitasking. Il Rate Grouping non è utiliz-
zato. L’unico processo è il processo base-rate quindi viene generata una sola
funzione model step:
void model_step(int_T tid)
Ad ogni tick del clock rt OneStep controlla i flag di overrun e chiama mod-
el step passando come argomento tid 0. La funzione di scheduling per un pro-
gramma multi-rate singletasking è rate scheduler. Lo schedulatore gestisce i
contatori di schedulazione ad ogni tick del clock. I contatori sono implemen-
tati in un array indicizzato da tid ovvero per ogni rate di campionamento c’è
un contatore e l’array è contenuto nella struttura Timing dentro rtModel.
Anche in questo caso i contatori si comportano da divisori del rate del clock
e contano fino ai periodi di campionamento associati ai processi sub-rate.
Quando un contatore raggiunge il periodo di un dato rate rate scheduler

39
azzera il contatore. Questa condizione indica che tutti i blocchi che girano a
quel rate devono essere eseguiti nella prossima chiamata a model step. mod-
el step è responsabile per il controllo dei contatori.

3.5 Linee Guida per la modifica di rt OneStep


rt OneStep non richiede una modifica estensiva. Le uniche modifiche richieste
sono le riattivazioni delle interruzioni dopo che si sono controllati i flag di
overrun e le condizioni di errore. Se possibile si dovrebbe anche

• Salvare e ripristinare il contenuto della FPU in ingresso e uscita da


rt OneStep.

• Impostare gli ingressi del modello associati con il rate base prima di
chiamare model step0.

• Acquisire le uscite del modello associate al rate base dopo la chiamata


a model step0.

• Se il modello è multi-rate multitasking ripetere le ultime due procedure


per ogni sub-rate e rispettiva chiamata model stepN.

I commenti generati in rt OneStep mostrano le posizioni appropiate per ag-


giungere il proprio codice.
Volendo è possibile gestire differentemente il comportamento in caso di er-
rore di overrun. Le strutture dati ed il funzionamento logico dei contatori
e flag non possono però essere modificati perchè sono critici per il corret-
to funzionamento di qualsiasi programma Real-Time Workshop Embedded
Coder.

40
Capitolo 4

Ottimizzazioni fixed-point

Questo capitolo fornisce alcuni consigli per lo sviluppo di modelli fixed-point


e la generazione di codice da tali modelli.
Seguendo questi consigli è possibile ridurre le richieste di ROM, RAM, tempo
di esecuzione del codice generato e aumentare l’accuratezza dei risultati nelle
operazioni a virgola fissa.

4.1 Rappresentazione fixed-point


La rappresentazione fixed-point permette di esprimere un numero reale come
un intero specificando la sua lunghezza (in bits) e la locazione del suo pun-
to binario. La figura 4.1 mostra la rappresentazione del numero 6.5 nella
notazione fixed-point in un tipi di dati ad otto bit.
Convertire un numero decimale in un suo equivalente fixed-point è molto
semplice:

• La parte intera del numero fixed-point è l’equivalente binario della parte


intera del numero decimale. Nell’esempio 6 viene convertito in 110.

• La parte frazionaria del numero fixed-point è l’equivalente binario della


frazione decimale divisa per la risoluzione. La risoluzione è 2−E dove
E è il numero di bit alla destra del punto binario. Nell’esempio la
risoluzione è 2−4 = 0.0625. Quindi la parte frazionaria del numero
fixed-point sarà 0.5/0.0625 = 8 che in binario diventa 1000.

La frazione determina la risoluzione che è il più piccolo valore diverso da zero


che il numero fixed-point può rappresentare. La parte intera invece determina
il range di valori del numero fixed-point. Quindi cambiare la locazione del

41
Figura 4.1: Rappresentazione fixed-point

punto binario in un numero fixed-point causa un tradeoff tra il range di valori


assumibili e la risoluzione.
Termini addizionali nel contesto fixed-point sono lo scaling , il bias e lo slope.
Lo slope ed il bias insieme formano lo scaling di un numero fixed-point. La
locazione del punto binario cambia lo scaling. Quindi possiamo scrivere V=
S*Q + B dove Q è il valore fixed-point quantizzato, V è il valore reale, S è
lo slope, B è il bias.
Si deve dunque scegliere uno slope ed un bias tali che il valore quantizzato
Q sia correlato al valore reale V con un range e una risoluzione ragionevoli
per l’applicazione.
E’ altresı̀ importante scegliere un buon metodo di arrotondamento. Quando il
microcontrollore converte un numero fixed-point da una risoluzione maggiore
ad una inferiore si devono trattare i bit in esubero. Se il microcontrollore
scarta questi bit extra la conversione può risultare imprecisa. Questo è quello
che succede se si scegliere il metodo di arrotondamento floor. Tuttavia questo
metodo è il più semplice, il più comune ed il più efficiente dei metodi di
arrotondamento.
Alternativamente è possibile scegliere altri metodi di arrotondamento per
conservare i bit extra per l’accuratezza. Simulink a tal proposito supporta
quattro metodi di arrotondamento: Floor, ceiling, zero e nearest.
Ci possono essere situazioni dove sia importante gestire bene il possibile
overflow del valore quantizzato. Per questo simulink fornisce due metodi di

42
gestione dell’overflow: Wrap e saturate. L’overflow avviene quando il numero
che deve essere salvato come risultato di una operazione matematica supera il
numero di bit che il tipo dati del risultato può contenere. Il metodo saturate
deve essere utilizzato solo nel caso in cui sia essenziale per la sicurezza poichè
aumenta l’uso della ROM e il tempo di esecuzione.

Per ciascuna uscita dei blocchi nel modello è possibile specificare la lunghez-
za della parola e la locazione del punto binario. In base al tipo di operazioni
matematiche eseguite su uno o più numeri fixed-point il risultato potrebbe
richiedere una lunghezza di parola maggiore. Per prima cosa è necessario
simulare il modello cercando le uscite che approssimano nel miglior modo i
valori ottenuti da una simulazione floating point dello stesso modello. Una
scelta inappropiata del range e della risoluzione può fornire un risultato in-
accurato e aumentare la dimensione del codice. Nel caso peggiore si possono
anche ottenere risultati errati a causa di underflow e overflow.

Quando si sceglie un tipo di dati si deve tenere in considerazione il range


numerico, la risoluzione, l’errore di quantizzazione e un metodo per gestire
le condizioni aritmetiche eccezionali. La scelta dipende dalle richieste della
propria specifica applicazione ( accuratezza , tempo di risposta) , dal proprio
embedded target (dimensione di parola, velocità del processore, etc..) e da
altri fattori.

E’ piuttosto semplice specificare tipi di valori fixed-point all’interno di


Simulink e di Stateflow. Entrambi supportano due metodi di scaling: A
punto binario e [Slope Bias]. Le figure 4.2 e 4.3 mostrano come impostare
tali valori.
Se si vuole progettare il proprio modello per ridurre il consumo di RAM,
di ROM e il tempo di esecuzione richiesto per eseguire il codice genera-

43
Figura 4.2: Simulink fixed-point

Figura 4.3: Stateflow fixed-point

to dal modello da Real-Time Workshop Embedded Coder ci sono numerosi


accorgimenti da prendere. Tra questi:

1. Utilizzare tipi di dati base per conservare RAM e ROM e tempo di


esecuzione

2. Minimizzare il numero di tipi di dati che non combaciano (ROM , tempo


di esecuzione)

3. Minimizzare il numero di scaling che non combaciano (ROM , tempo


di esecuzione)

4. Evitare di utilizzare lo scaling fixed-point con bias (ROM, tempo di


esecuzione)

5. Arrotondare con floor e non saturare se possibile (ROM, tempo di


esecuzione)

44
6. Ottimizzare l’ordine delle operazioni di divisione e moltiplicazione dan-
do come primo ingresso l’ingresso di moltiplicazione al blocco apposito
(ROM, tempo di esecuzione)

7. Limitare l’utilizzo di tabelle di lookup spaziate irregolarmente (RAM,


ROM, tempo di esecuzione)

8. Utilizzare sottosistemi riutilizzabili (ROM vs RAM)

9. Utilizzare l’operatore ’C’ in Stateflow (ROM, tempo di esecuzione)

10. Attivare l’opzione Real-Time Workshop Embedded Coder Local block


outputs (RAM)

11. Attivare l’opzione Real-Time Workshop Embedded Coder Parameter


inlining (RAM)

Se invece il nostro interesse è quello di preservare l’accuratezza ci dovremo


comportare diversamente.

45
Capitolo 5

Impostazioni Real Time


Workshop

Passiamo adesso a vedere le opzioni di compilazione usate in Real Time


Workshop per la generazione del codice.
Per accedere alle finestre di configurazione di Real Time Workshop dobbiamo
selezionare sul file modello Simulink Simulation - Configuration Param-
eters , si aprirà dunque una finestra con tutta una serie di opzioni: mostrerò
le opzioni di interesse per la generazione di codice embedded ottimizzato.

In figura è mostrato il pannello Solver. Dobbiamo tener conto che il codice


dovrà eseguire su di un microcontrollore per cui è importante impostare tra
le opzioni come Type Fixed-Step e come Solver un solutore discreto.
Il secondo pannello di configurazione importante è il pannello di ottimiz-
zazione del codice Optimization per cui mi soffermerò sul significato di
alcune impostazioni.

5.1 Block Reduction Optimization


Quando viene attivata questa impostazione Simulink riduce certi gruppi di
blocchi in un singolo blocco più efficente e li rimuove completamente. Questo
garantisce una esecuzione del modello più veloce durante la simulazione e nel
codice generato. L’aspetto del modello Simulink non cambia. I blocchi per
cui è possibile questa ottimizzazione sono di tre tipologie.
• Accumulator Folding. Simulink riconosce determinate strutture come
accumulatori e le riduce ad un singolo blocco.

46
• Rimozione di Conversioni di Tipo Ridondanti. Blocchi di con-
versione di tipo non necessari sono rimossi. Per esempio un blocco di
conversione di tipo int con ingresso e uscita di tipo int è ridondante e
viene rimosso.

• Dead Code Elimination. Tutti i blocchi o segnali in un percorso


di codice non utilizzato sono eliminati. (nota: perchè un blocco sia
considerato parte di un percorso di codice non utilizzato deve rispettare
determinate condizioni).

5.2 Conditional Input Branch Execution


Questa ottimizzazione taglia fuori il codice non necessario generato da un
flusso in ingresso ad un blocco Switch. Quando questa opzione è attiva, invece
di eseguire ad ogni passo temporale tutti i blocchi che pilotano le porte di
ingresso del blocco Switch, vengono eseguiti solamente i blocchi che servono
a calcolare l’ingresso di controllo e l’ingresso dati selezionato dall”ingresso di
controllo.

47
5.3 Implement Logic Signals as Boolean Data
Simulink è impostato per non segnalare un errore quando un segnale di tipo
double va a pilotare un blocco con ingresso booleano. Questo è stato fatto
per mantenere la compatibilità con precedenti versioni di Simulink che sup-
portavano solo i tipi double. Spuntando questa opzione invece si seleziona un
controllo rigido sul tipo booleano. Questa opzione è raccomandata : il codice
generato richiede meno memoria in quanto un segnale booleano è tipicamente
di un byte mentre un segnale double richiede otto bytes di memoria.

5.4 Signal Storage Reuse


Questa opzione istruisce Real Time Workshop a riutilizzare la memoria dei
segnali. Questo fa diminuire le richieste di memoria del programma real-time.
Disattivare questa opzione rende tutte le uscite dei blocchi globali e uniche
che in molti casi accresce significativamente l’utilizzo di RAM e ROM.

48
5.5 Inline Parameters
Selezionare questa opzione ha due effetti:

• Real-Time Workshop utilizza nel codice generato il valore numerico dei


parametri del modello anzichè il loro nome simbolico. Se il valore di un
parametro è una variabile del workspace o una espressione contenente
una o più variabili dello spazio di lavoro, la variabile o l’espressione
sono valutati al tempo di generazione del codice. Un parametro inlined
viene in effetti trasformato in una costante e non è più visibile dal
codice scritto esternamente ne è più modificabile a run-time.

• Il pulsante Configure viene attivato. Cliccando su questo pulsante si


apre il dialog box Model Parameter Configuration. Questo dia-
log pemette di rimuovere parametri individuali dall’essere inlined e di
dichiararli tunable o costanti globali. Diachiarare un parametro tun-
able fa generare al Real-Time Workshop una dichiarazione di memo-
ria che permetterà di interfacciare il parametro con codice esterno.
Questo permette inoltre al codice di modificare il valore del parametro
a run-time.

L’opzione Inline Parameters istruisce anche Simulink a propagare i tempi


di campionamento costanti. Simulink calcola il segnale di uscita dei blocchi
con tempo di campionamento costante una volta durante l’avviamento del
modello. Questo migliora le prestazioni perchè questi blocchi non devono
calcolare le loro uscite ad ogni passo del modello.
Quando il parametro Inline parameters è attivo è possibile anche attivare
l’opzione Inline invariant signals che inserisce anch’esso valori costanti
nel codice.

5.6 Application Lifespan


Il campo Application lifespan permette di specificare per quanto tempo una
applicazione che dipende dal tempo trascorso può eseguire prima che si abbia
overflow del timer. Questa impostazione determina dunque la dimensione in
bytes usate dai timers nel codice generato e permette di diminuire l’utilizzo
della RAM. Utilizzare 64 bits per memorizzare i dati temporali permette a
modelli con un passo di 0.001 microsecondi di eseguire per più di 500 anni,
cosa che difficilmente è richiesta. Per eseguire un modello con dimensione
del passo di un millisecondo per un giorno è richiesto un timer a 32-bit ( e
può continuare ad eseguire per 49 giorni).

49
5.7 Enable Local Block Outputs
Quando questa opzione viene attivata i segnali dei blocchi sono dichiarati lo-
calmente nelle funzioni invece di essere dichiarati globalmente quando questo
è possibile.
E’ possibile attivare questa opzione solo quando viene attivata l’0pzione
Signal Storage Reuse.

5.8 Reuse Block Outputs


Quando questo check box è selezionato Real-Time Workshop riutilizza la
memoria dei segnali quando possibile. Se disattivato i segnali vengono salvati
in locazioni uniche. Anche questa opzione è selezionabile solo se è attiva
l’opzione Signal Storage Reuse.

5.9 Ignore Integer Downcasts in Folded Ex-


pressions
Questa opzione specifica come Real-Time Workshop debba gestire le oper-
azioni a 8-bit sui microprocessori a 16-bit e le operazioni a 8 e 16 bit nei
microprocessori a 32-bit. Per assicurare la consistenza tra simulazione e gen-
erazione di codice i risultati delle espressioni intere a 8 e 16 bit devono essere
esplicitamente castate su 8 o 16 bit. Questa opzione migliora l’efficienza del
codice eliminando le variabili intermedie.

5.10 Inline Invariant Signals


Un segnale invariante è un segnale di uscita da un blocco che non cambia
durante la simulazione Simulink. Con questa opzione ci si assicura che tale
segnale sia inlined.

5.11 Eliminate Superfluous Temporary Vari-


ables (Expression Folding)
Questa opzione attiva l’Expression Folding. L’expression folding è una tecni-
ca di ottimizzazione del codice che minimizza il calcolo dei risultati intermedi
in uscita dai blocchi e il salvataggio di questi risultati in buffers o variabili

50
temporanee. Quando questa opzione è attiva Real-Time Workshop riunisce
i calcoli dei blocchi in una singola espressione invece di generare espressioni
separate e dichiarazioni di memoria per ogni blocco del modello.
Questa riduzione può aumentare notevolmente l’efficienza del codice gener-
ato generando codice molto simile al codice scritto a mano. In molti casi
interi gruppi di calcolo vengono ridotti in una linea di codice altamente ot-
timizzata. Molti blocchi Simulink supportano l’expression folding.
Un semplice esempio di come l’expression folding modifica il codice generato
da un modello è il seguente.

Con l’expression folding attivato questo modello genera una singola linea di
calcoli per l’uscita come mostrato nella funzione di uscita.

static void exprfld_output(int_T tid)


{

/* local block i/o variables */


/* Outport: ’<Root>/Out1’ incorporates:
* Gain: ’<Root>/k1’
* Gain: ’<Root>/k2’
* Product: ’<Root>/Product’
*/

exprfld_Y.Out1 = exprfld_U.i1 * exprfld_P.k1_Gain *


(exprfld_U.i2 * exprfld_P.k2_Gain);

}
I commenti generati indicano i calcoli dei blocchi che sono stati combinati
in una singola espressione. I commenti documentano anche i parametri dei
blocchi che appaiono nell’espressione.

51
Se l’expression folding è disattivata lo stesso modello calcola i risultati tempo-
ranei sia dei guadagni dei blocchi che dei valori dei prodotti prima dell’uscita
finale come mostrato nel codice seguente.

static void exprfld_output(int_T tid)


{

/* local block i/o variables */


real_T rtb_k2_i;
real_T rtb_Product_i;

/* Gain: ’<Root>/k1’ */
rtb_Product_i = exprfld_U.i1 * exprfld_P.k1_Gain;

/* Gain: ’<Root>/k2’ */
rtb_k2_i = exprfld_U.i2 * exprfld_P.k2_Gain;

/* Product: ’<Root>/Product’ */
rtb_Product_i *= rtb_k2_i;

/* Outport: ’<Root>/Out1’ */
exprfld_Y.Out1 = rtb_Product_i;

5.12 Loop Unrolling Threshold


Il campo Loop unrolling threshold nel pannello di ottimizzazione determina
quando un segnale o parametro ampio(con più di un elemento) debba essere
inserito in un ciclo for o se debba essere generato con degli statements sepa-
rati per ogni elemento del segnale. Il valore di default è 5. Questo vuol dire
che se un parametro ha 5 o più elementi verrà utilizzato un ciclo for , se un
parametro ha 4 elementi verranno prodotti 4 differenti statements nel codice
del modello.

52
5.13 Remove Code from Floating-Point to In-
teger Conversions That Wraps Out-of-
Range Values
Questa opzione fa rimuovere a Real-Time Workshop il codice che assicura che
l’esecuzione del codice generato produca gli stessi risultati della simulazione
quando avviene una conversione che va fuori range. Questo riduce la dimen-
sione e aumenta la velocità del codice prodotto a scapito della possibilità
di produrre risultati che non corrispondono a quelli della simulazione se si
hanno valori fuori scala.

5.14 Parameter Structure


Il menù Parameter structure permette di controllare come vengono generati i
dati dei parametri per i sottosistemi riutilizzabili. Questo menù viene attivato
quando si attiva l’opzione Inline Parameters. Le opzioni del menù sono
due:
• Hierarchical : Quando è attiva questa impostazione Real-Time Work-
shop Embedded Coder genera per ogni sottosistema riutilizzabile un
file di intestazione separato che definisce una struttura di parametri
indipendente.
• Non-hierarchical : Con questa configurazione attiva Real-Time Work-
shop Embedded Coder genera una unica struttura dati dei parametri.
Questa è una struttura dati di tipo piatto che può ridurre in molti casi
il padding del compilatore tra le word risultando in un codice compilato
più efficiente.

5.15 Sottopannello Data Initialization


Queso sottopannello contiene delle opzioni relative all’inizializzazione dei
dati.
• Remove root-level I/O zero initialization : Il codice di inizial-
izzazione per le porte di ingresso e di uscita al livello root non viene
generato.
• Use memset to initialize floats and doubles to 0.0 : Se non
si utilizza memset per inizializzare floats e doubles viene generato del
codice aggiuntivo apposito.

53
• Remove internal state zero initialization : Se l’opzione è disattiva
viene generato del codice che inizializza a zero le strutture di lavoro
interne.

• Optimize initialization code for model reference : Se un blocco


in un sitema può resettare i suoi stati interni Real-Time Workshop
genera codice di inizializazione run-time per il blocco in questione.

5.16 Remove code that protects against divi-


sion arithmetic exceptions
Questa opzione rimuove il codice che protegge dalla divisione per zero a vir-
gola fissa. Attivando questa opzione i risultati della simulazione potrebbero
differire da quelli prodotti dal codice generato in esecuzione.

Un’altro pannello importante per la corretta generazione del codice em-


bedded è il pannello Hardware Implementation mostrato in figura 5.1.
Questo pannello ci permette di selezionare la famiglia di dispositivi a cui
appartiene il nostro microcontrollore target. Se non disponibile è anche pos-
sibile usare un device generico e impostare manualmente la tecnologia e le
caratteristiche del dispositivo. Nel caso di interesse è sufficiente selezionare
sotto la voce Device type la famiglia Infineon C16x. L’emulazione hardware
non ci interessa dato che utilizziamo Matlab solo per generare il codice.

Il pannello più importante è il pannello Real-Time Workshop(figura 5.2).


Qui viene specificato il System target file da utilizzare nel processo di
creazione del codice. Il pulsante Browse permette di selezionare alcuni tar-
get già ottimizzati per la generazione del codice.
Il sottopanello Build process specifica inoltre il make command da es-
eguire ed il Template makefile. E’ possibile passare anche delle opzioni al
TLC per personalizzare la produzione del codice e la compilazione. Per quan-
to riguarda la mia configurazione ho scelto l’Embedded target per Infineon
C166 quindi il system target file c166.tlc e il template makefile c166.tmf (an-
che se di fatto non lo utilzzo dato che non genero l’eseguibile tramite Matlab).
Ho anche spuntato il check box Generate Code only poichè sono interes-
sato solo alla generazione del codice.

54
Figura 5.1: Pannello Hardware Implementation

In figura 5.3 è riportato il pannello Interface. In questo pannello è possibile


selezionare numerose opzioni. Prima di tutto si può scegliere lo standard di
generazione del codice matematico floating-point, nel mio caso l’ ANSI-C, ma
soprattutto è qui che si sceglie se il codice può supportare o no determinate
feature.
In figura sono selezionati i supporti per i numeri a virgola fissa e per il tempo
assoluto. Il floating-point è attivo solo perchè necessario in fase di debug per
visualizzare correttamente le informazioni. Può essere quindi disattivato in
fase di produzione del codice finale una volta eliminati i blocchi di debug.
Nel sottopannello Code interface ci sono numerose altre opzioni. L’unica
selezionata è Single output/update function che fa generare una sola
funzione che comprende uscita e update degli stati dato che non siamo in
tempo continuo e non dobbiamo derivare nulla.

Nel pannello subito sotto(figura 5.4), Templates, ci interessa solo il sot-


topannello Custom templates. Qui andiamo ad impostare come file di
template per la personalizzazione il file modificato precedentemente
myc166customfiles.tlc e chiediamo di generare un file main di esempio di tipo
BareBoardExample.

L’ultimo pannello a cui siamo interessati è il pannello C166 Options dove

55
Figura 5.2: Pannello Real-Time Workshop

Figura 5.3: Pannello interface

andiamo a deselezionare tutto e attiviamo solamente use prebuilt RTW


libraries (in realtà potremmo deselezionare tranquillamente anche questa

56
Figura 5.4: Pannello Templates

opzione). La figura 5.5 mostra il pannello in questione.

57
Figura 5.5: Pannello C166 Options

58