• Non ci sono risultati.

3 Analisi del set-up sperimentale

3.4 Generatore di traffico casuale

3.4.2 Analisi del programma Traffico_casuale

A differenza del programma analizzato nel paragrafo precedente, Traffico Casuale viene creato attraverso l’editor dell’ambiente di sviluppo µVision2 che permette di codificare le istruzioni in linguaggio C. Queste istruzioni, opportunamente convertite in formato Hex, vengono trasferite al microcontrollore (attraverso collegamento seriale utilizzando l’applicazione FLIP) ed eseguite per generare sul bus CAN il modello di traffico casuale. In Appendice A è ripirtato il listato dei comandi di Traffico Casuale a cui faremo riferimento per giustificare le scelte progettuali adottate.

Il programma pricipale main( ), prima di invocare le funzioni che inizializzano le periferiche del microcontrollore, attiva la modalità di funzionamento a frequenza doppia in tutti i dispositivi del T89C51CC01 ad eccezione del Timer1: in questo modo il valor massimo degli intervalli di tempo generati risulta il più grande possibile e pari a 10.5 ms.

Le funzioni che inizializzano le periferiche vengono chiamate init_can( ), init_uart( ) ed init_timer1( ). La prima di esse effettua le stesse operazioni già

analizzate per il generatore di traffico periodico: imposta il bit-rate di trasmissione sul bus CAN e configura i canali 0 e 1 a trasmettere un messaggio con identificatore pari a 0 (priorità massima nel sistema) e contenuto rappresentato da un solo byte di valore 55 h. Entrambi i canali sono inoltre configurati a generare un’interruzione alla fine di ogni trasmissione ma non vengono ancora abilitati a trasmettere. In questo modo viene creato lo stesso buffer circolare (costituito da due locazioni) il cui funzionamento è stato analizzato nel paragrafo 3.3. E’ importante notare che la scelta del parametro Lmes, che caratterizza il modello di

traffico casuale, viene effettuata in questa fase del programma. Ciascun messaggio attivato ha infatti una lunghezza fissa di 58 bit (47 di servizio, 8 nel campo Data e 3 di stuffing) e quindi Lmes= 58*Tbit. L’occupazione media del bus può essere

inoltre espressa attraverso la seguente relazione:

W.L.casuale= (58*Tbit * λtot*100)%

La scelta di inviare messaggi di dimensioni così ridotte (avvalorata fra l’altro dall’analisi di un benchmark fornito dalla SAE [6]) è giustificata dalla natura stessa del traffico casuale. Tali trasmissioni infatti vengono effettuate generalmente in seguito ad avvenimenti sporadici (ed a volte critici) con lo scopo di notificare al sistema il verificarsi dell’evento. Per questo motivo non è necessario inviare un contenuto informativo specifico in quanto la trasmissione stessa del messaggio rappresenta di per sé tale notifica; quindi il campo Data dei messaggi casuali assume poca importanza e viene ridotto (nel nostro modello) ad un unico byte.

La funzione init_uart( ) permette di impostare la velocità di trasmissione della UART del microcontrollore a 115.2 kbps utilizzando l’overflow del Timer2.

La funzione init_timer1( ) permette invece di impostare il Timer1 in modalità di funzionamento 16-bit Timer abilitandolo ad inviare una richiesta di interruzione al raggiungimento dell’overflow.

Una volta conclusa la fase di inizializzazione delle periferiche, il programma principale preleva i campioni generati da Genera Intervalli sul PC invocando la funzione chiedi_byte( ). Tale sottoprogramma, secondo il protocollo

di comunicazione seriale stabilito, memorizza in SBUF il carattere “a” (inviandolo attraverso la UART al PC) ed attende di ricevere dal PC il dato utile inviato su due byte a cominciare dalla parte più significativa. I byte prelevati vengono memorizzati in un buffer circolare di tipo FIFO chiamato buffer_mem e costituito da 100 locazioni di un byte ciascuna; poiché ogni campione è codificato su 16 bit, buffer_mem può contenere al massimo 50 campioni. La funzione chiedi_byte( ) viene eseguita 50 volte fino al completo riempimento del buffer. Il primo campione ricevuto viene quindi prelevato dalla cima di buffer_mem e memorizzato nel registro TH1&TL1 con cui viene caricato il contatore del Timer1. Il timer viene quindi acceso in modo da effettuare il conteggio dell’intervallo di tempo proporzionale a tale valore. Per garantire il continuo rifornimento di campioni provenienti dal PC, il programma principale controlla periodicamente che buffer_mem sia pieno e, in caso contrario, invoca la funzione chiedi_byte( ). Al raggiungimento dell’overflow del Timer1 viene generata una richiesta di interruzione che attiva la routine di interrupt driver_timer1. Tale sottoprogramma ha lo scopo di effettuare il caricamento di un nuovo valore nel registro TH1&TL1, prelevandolo da buffer_mem, ed abilitare in trasmissione uno dei due canali configurati da init_can( ). L’attivazione dei message object avviene secondo le seguenti modalità:

o se entrambi i canali risultano disponibili, viene abilitato quello con indice inferiore (nel nostro caso il canale 0);

o se uno dei due è già attivo in fase di trasmissione, viene abilitato l’altro che si accoda in attesa che il bus ritorni libero.

Poiché tuttavia, in una distribuzione esponenziale i valori numerici più piccoli sono quelli più probabili, è possibile che il Timer1 invii una richiesta di interruzione quando nessuno dei due canali risulta disponibile. In questo caso la routine driver_timer1 registra l’accodamento incrementando il valore del contatore num_mes (inizializzato a zero). Per tener conto di tali accodamenti ed abilitare l’invio del corrispondente messaggio quando il bus ritorna libero, viene utilizzata la routine di interrupt driver_can. Per questo motivo, quando un canale completa la trasmissione del proprio messaggio, viene inviata una richiesta di interruzione che attiva la routine; driver_can controlla quindi se num_mes = 0 e,

in caso contrario, riattiva in trasmissione il message object che ha richiesto l’interruzione del programma; infine viene decrementato il contenuto di num_mes. Consideriamo il seguente esempio: il primo overflow del Timer1 determina l’attivazione in trasmissione del canale 0; il secondo avviene prima che tale trasmissione sia terminata e quindi attiva il canale 1. Supponiamo che la successiva richiesta di interruzione del Timer1 sia inviata quando ancora il message object 0 sta trasmettendo il primo messaggio: in questo caso il contatore num_mes viene incrementato ad 1. Non appena il canale 0 conclude la trasmissione, il canale 1 inizia immediatamente la contesa per l’accesso al bus mentre la routine driver_can riattiva in trasmissione il message object 0 ed azzera il contenuto del contatore. Quando anche il canale 1 termina l’invio del proprio messaggio, il message object 0 inizia immediatamente a trasmettere mentre driver_can, rivelando la condizione num_mes = 0, manda in esecuzione l’istruzione IRET che restituisce il controllo del programma a main( ). In questo modo è possibile trasmettere, uno di seguito all’altro, tutti i messaggi casuali attivati prima che la trasmissione del messaggio precedente sia terminata.

Prima di concludere l’analisi del programma Traffico Casuale è necessario fare alcune considerazioni sulle scelte progettuali adottate.

Per prima cosa si può notare che la routine driver_timer1, oltre ad attivare la trasmissione dei messaggi sul bus, deve anche caricare il nuovo contenuto nel registro TH1&TL1. Per un corretto funzionamento del Timer1, il suo caricamento può avvenire soltanto a timer spento. Per questo motivo la routine driver_timer1 spegne il timer all’inizio della sua esecuzione (TR1=0) e lo riaccende dopo avervi memorizzato il nuovo campione da contare (TR1=1). Poiché il tempo di “inattività” del Timer1 dura all’incirca 25 µs, segue che tutti gli intervalli generati (ed il loro valore medio) risultano incrementati di tale quantità. Per evitare questo inconveniente avremmo potuto usare il Timer2 (e non il Timer1) che prevede la modalità di funzionamento 16-bit-autoreload. In questo caso, il caricamento del nuovo valore da contare sarebbe avvenuto automaticamente all’overflow del timer e non dopo 20 µs. Il Timer2 deve tuttavia essere utilizzato per generare il clock della UART ad una frequenza di 115.2 kbps e garantire il range massimo di variazione di 1/λtot. Anche il Timer1 prevede una modalità di funzionamento di

tipo autoreload ma come contatore ad 8 bit e non a 16. In questo caso però l’intervallo di tempo massimo che intercorre fra due attivazioni successive di un messaggio è pari a 192 µs e risulta decisamente troppo piccolo per il nostro modello di traffico. Bisogna inoltre notare che, negli esperimenti effettuati sul bus CAN, non è mai stato utilizzato un valore di 1/λtot inferiore alle centinaia di

microsecondi e quindi l’incremento di 20 µs dovuto alla routine driver_timer1 risulta del tutto trascurabile.

E’ lecito domandarsi inoltre perché il programma Genera Intervalli sia stato eseguito sul PC e non direttamente sul microcontrollore dato che il trasferimento dei dati attraverso il collegamento seriale comporta una perdita di tempo di 300µs (ed oltre) per campione.

La funzione chiedi_byte( ), invocata dal programma Traffico Casuale, avrebbe potuto generare da sola i campioni utili da caricare nel Timer1 senza inviarne richiesta al PC; avrebbe quindi eseguito le istruzioni previste nel primo e secondo blocco del diagramma di flusso analizzato nel paragrafo precedente. Il microcontrollore lavora tuttavia con un oscillatore esterno a 16 MHz e la CPU impiega un tempo pari a 375 ns (se il bit X2 del registro CKCON è stato settato) per eseguire una singola istruzione e quindi:

o la funzione y = rand( ), utilizzata per generare un numero compreso fra 0

ed 1 con distribuzione di probabilità uniforme, viene eseguita in 200 µs

o la funzione y = -1/λ * ln(1-x) viene eseguita in 2 ms circa

o le restanti istruzioni che approssimano il valore di x e ne adattano il

contenuto alla dinamica del Timer1 vengono eseguite in quasi 600 µs. Per questo motivo, generando internamente al microcontrollore i campioni utili, il tempo impiegato risulta complessivamente pari a circa 3 ms per campione. Questo valore avrebbe però limitato la dinamica di 1/λtot innalzandone

Documenti correlati