• Non ci sono risultati.

2 DESCRIZIONE DI SISTEMA E SPECIFICHE

5.10 ECU e Telemetria

La centralina del cambio deve comunicazione con la centralina del motore (Engine Control Unit, ECU in seguito) per assolvere correttamente alcune funzioni (si veda paragrafo 2.8).

Durante la partenza lanciata la GCU deve abilitare sulla ECU la relativa funzione Launch-Control. Durante una cambiata in salita la GCU deve abilitare la funzione di taglio motore della ECU.

Questi compiti vengono eseguiti semplicemente pilotando, tramite due pin di I/O della GCU, gli ingressi di Launch e di Cut-Off, della ECU.

Oltre ai due compiti descritti la GCU deve acquisire dalla ECU il numero di giri e la temperatura del motore, ed inviare l’intero pacchetto dati della ECU dati alla telemetria. Come dettagliatamente specificato nel paragrafo 2.8 per comunicare con ECU si deve procedere come segue. Per iniziare la comunicazione, che avviene sulla porta SCIB, si devono inviare i caratteri di richiesta dati alla ECU, la quale, in silenzio fino a quel momento, riconosce i caratteri di richiesta dati e invia come risposta un pacchetto contenente tutti le informazioni che è in grado di comunicare. Il pacchetto dati viene acquisito interamente dalla GCU e la comunicazione della ECU viene bloccata inviando una stringa di caratteri di stop. Dal pacchetto acquisito il software rileva il numero di giri e la temperatura, e invia l’intero pacchetto sull’altra porta seriale, SCIA, verso la centralina della telemetria. Tutto questo si ripete con frequenza pari a 5 Hz.

La periferica SCI è configurata in modo da far uso di FIFO a 16 livelli in trasmissione e in ricezione e in modo da abilitare la trasmissione tramite gli interrupt. Si veda paragrafo 5.1.5.In particolare per la porta SCIB (che comunica con la ECU) la ricezione è attivata e disattivata, rispettivamente, dalle seguenti righe di codice: ScibRegs.SCIFFRX.bit.RXFFIENA=1 e ScibRegs.SCIFFRX.bit.RXFFIENA=0. Mentre la trasmissione è sempre attiva e avviene sulla base di un timer. La porta SCIA funziona solo in trasmissione, la quale è abilitata e disabilitata, rispettivamente, dalle seguenti righe di codice: SciaRegs.SCIFFTX.bit.TXFFIENA=1 e SciaRegs.SCIFFTX.bit.TXFFIENA=0.

Si analizza di seguito il codice.

È necessario inviare il pacchetto dati alla centralina della telemetria in maniera temporizzata, in modo che questa possa ricostruire l’andamento temporale dei dati forniti dalla centralina motore. Il protocollo prevede di far uso di una frequenza pari a 5 Hertz. Si ricordi che nel DSP è presente il GP Timer4 che genera la frequenza di campionamento, pari a 250Hz, per l’ADC. Abilitando l’interrupt di periodo (si fa generare al timer un interrupt quando ogni volta che il contatore è a zero) relativo a tale timer si ottiene una ISR che viene eseguita con frequenza di 250Hz. Facendo uso di un contatore (TeleTimer) è possibile abilitare la trasmissione alla 50-esima volte che si entra nella ISR. In tal modo si richiedono i dati alla ECU ogni 5Hz, i dati vengono acquisiti e ritrasmessi verso la centralina della telemetria. Per richiedere i dati alla ECU è necessario inviare alla ECU i seguenti 12 caratteri: 'T' '0' '0' '0' '0' '0' '0' '0' '0' '0' '8' 'v'. Appena trasmessi questi caratteri la ECU inizierà ad inviare gli 90 byte (o caratteri) che costituiscono il pacchetto dati. È quindi necessario abilitare l’interrupt di ricezione. I compiti descritti vengono assolti nella seguente ISR in esecuzione con frequenza di 5 Hz. Tra un’esecuzione e l’altra, dell’ISR, passa il tempo necessario alla ECU per trasmettere il pacchetto (che viene memorizzato), e per fare eco, di quest’ultimo, alla centralina della telemetria. Il codice relativo alla ISR di periodo del GP Timer4 è riportata di seguito.

interrupt void ISR_EVB_Timer4PINT(void) {

... manca codice (relativo ad altre funzioni)

if (TeleTimer==49) //ogni 5 hertz entro qui, (esattamente ogni 50 esecuzioni di ISR) { TeleTimer=0; ScibRegs.SCITXBUF =':'; ScibRegs.SCITXBUF = 'T'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '0'; ScibRegs.SCITXBUF = '8'; ScibRegs.SCITXBUF = 'v'; RXBi=0; ScibRegs.SCIFFRX.bit.RXFIFORESET=0; ScibRegs.SCIFFRX.bit.RXFFIENA=1; ScibRegs.SCIFFRX.bit.RXFFINTCLR=1; ScibRegs.SCIFFRX.bit.RXFIFORESET=1; } else

TeleTimer++; EvbRegs.EVBIFRB.all = BIT0; PieCtrl.PIEACK.all = PIEACK_GROUP5; EINT;

}

A questo punto, sulla porta SCIB dalla ECU, sono in arrivo i 90 caratteri che costituiscono il pacchetto dati. L’interrupt di ricezione è abilitato e la memoria FIFO a 16 livelli è vuota. Al sedicesimo carattere inviato dalla ECU alla GCU, la FIFO si riempie e viene eseguita la ISR relativa all’interrupt di FIFO di ricezione piena. Quest’ultima esegue il codice che svuota la FIFO memorizzando i dati in essa contenuti all’interno dell’array packet[] della classe CEcu (Ecu.packet[]). Svuotata la FIFO accadranno di nuovo gli eventi, appena descritti, per i secondi 16 byte inviati dalla ECU.

Durante la sesta volta che si esegue la ISR il pacchetto termina, tutti i dati sono stati acquisiti, particolare cura deve essere rivolta all’indicizzazione dell’array packet[]. A questo punto si deve inviare alla ECU i caratteri che ne bloccano la trasmissione. Tali caratteri sono: ':' '?' 'y'. Inviati tali caratteri si esegue un semplice controllo sui dati memorizzati: visto che i primi quattro caratteri di ogni pacchetto inviato dalla centralina sono ':' 'O' 'K' '!' 'õ', allora, se i primi quattro caratteri, memorizzati in packet[], corrispondono a ':' 'O' 'K' '!' 'õ' allora i dati vengono ritenuti validi e il contenuto di packet[] verrà inviato alla centralina della telemetria. Per assolvere tale compito viene abilitato l’interrupt di trasmissione della porta SCIA e visto che la FIFO di trasmissione è vuota viene generato immediatamente un interrupt di trasmissione per la porta SCIA.

La ISR di ricezione è sotto riportata.

interrupt void SCIRXINTB(void) { PieCtrl.PIEACK.bit.ACK9 = 1; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; Ecu.packet[RXBi] = ScibRegs.SCIRXBUF.all;RXBi++; if (RXBi>=89) { ScibRegs.SCIFFRX.bit.RXFFIENA=0; ScibRegs.SCITXBUF = ':'; ScibRegs.SCITXBUF = '?'; ScibRegs.SCITXBUF = 'y'; if ( ( Ecu.packet[0] == ':' && Ecu.packet[1] == 'O' && Ecu.packet[2] == 'K' && Ecu.packet[3] == '!' && Ecu.packet[4] == 'õ') ) { TXAi=0; SciaRegs.SCIFFTX.bit.TXINTCLR=1; SciaRegs.SCIFFTX.bit.TXFFIENA=1; } else {

//dati non validi ; } } ScibRegs.SCIFFRX.bit.RXFFINTCLR=1; EINT; }

Si nota che se il pacchetto ricevuto non è valido il pacchetto dati non viene inviato alla centralina della telemetria. Non vengono prese ulteriori azioni. Quindi, ogni tanto, la centralina della

telemetria può non ricevere un pacchetto, questo può portare a errori nel log temporale visto che la centralina si aspetta dati ogni 5Hz. Per evitare questo problema è sufficiente definire una variabile di dati non validi, che permette di inviare un pacchetto vuoto se i dati non sono validi.

La ISR di trasmissione su porta SCIA non fa altro che scrivere il pacchetto dati nel registro di invio della FIFO. Una volta che la ISR è stato eseguita sei volte (si genera un interrupt ogni volta che la FIFO, da sedici locazioni, si vuota) tutto il pacchetto è stato trasmesso e l’interrupt di trasmissione viene disabilitato. Il codice relativo è sotto riportato.

interrupt void SCITXINTA(void) { PieCtrl.PIEACK.bit.ACK9 = 1; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; SciaRegs.SCITXBUF=Ecu.packet[TXAi];TXAi++; if ( TXAi>=89) { SciaRegs.SCIFFTX.bit.TXFFIENA=0; }

else//dati ancora non tutti trasmessi

SciaRegs.SCIFFTX.bit.TXINTCLR=1; EINT;

}

Si nota che alla fine delle ISR sopra riportate è necessaria una riga analoga a SciaRegs.SCIFFTX.bit.TXINTCLR=1 che indica che l’interrupt è stato servito e il codice è pronto a servirlo nuovamente.

Adesso, conoscendo la formattazione del pacchetto, è possibile ricavare le informazioni sul numero di giri e la temperatura del motore e memorizzarle nelle variabili EngineRPM e EngineTEMP sempre della classe CEcu. Come descritto nel paragrafo 2.8 l’informazione sul numero di giri è contenuta in una variabile a 16 bit senza segno. La ECU invia i caratteri ASCII del cifre esadecimali che rappresentano il valore della variabile. Ad esempio, il valore di 0x157C verrà trasmesso tramite i seguenti quattro byte: 0x31, 0x35, 0x37, 0x43 che corrispondo ai codici ASCII scritti in esadecimale per i caratteri 1, 5, 7, C rispettivamente. Per interpretare tale valore è stato scritto un codice che permette di passare da esadecimale a decimale da cui calcolare il valore del numero di giri. Il codice relativo è sotto riportato. Si ricorda che non è stato possibile decriptare l’informazione sulla temperatura dal motore dal pacchetto inviato dalla ECU, quindi le funzioni relative alla temperatura sono vuote.

void CEcu::SetRPM(void) {

Uint16 IDig, IIDig, IIIDig, IVDig; NOP;

if (packet[10] <= 0x39 && packet[10] >= 0x30) IDig= (Uint16) (packet[10]-0x30);

if (packet[10] <= 0x46 && packet[10] >= 0x41) IDig= ((Uint16) (packet[10]-0x41)) + 10; if (packet[11] <= 0x39 && packet[11] >= 0x30) IIDig= (Uint16) (packet[10]-0x30);

if (packet[11] <= 0x46 && packet[11] >= 0x41) IIDig= ((Uint16) (packet[11]-0x41)) + 10; if (packet[12] <= 0x39 && packet[12] >= 0x30) IIIDig= (Uint16) (packet[12]-0x30);

if (packet[12] <= 0x46 && packet[12] >= 0x41) IIIDig= ((Uint16) (packet[12]-0x41)) + 10; if (packet[13] <= 0x39 && packet[13] >= 0x30) IVDig= (Uint16) (packet[13]-0x30);

if (packet[13] <= 0x46 && packet[13] >= 0x41) IVDig= ((Uint16) (packet[13]-0x41)) + 10; EngineRPM= (IDig<<12) + (IIDig<<8) + (IIIDig<<4) + (IVDig); }

Uint16 CEcu::GetRPM(void) {

} void CEcu::SetEngTemp(void) { EngineTEMP=packet[34];//codice fittizio } Uint16 CEcu::GetEngTemp(void) { return EngineTEMP; }