Il protocollo LIN (Local Interconnect Network) è nato dall’esigenza di diversi costruttori di automobili e semiconduttori per rispondere alle necessità di utilizzare e realizzare reti a basso costo in grado di permettere lo scambio di informazioni tra sensori e attuatori. La velocità massima di trasmissione è di 19200 baud. Questo mezzo trasmissivo è una valida alternativa ad un altro già blasonato bus, il CAN. Infatti, questo è utilizzato per applicazioni a basso costo, in cui non si richiedono alte velocità di trasmissione. In ogni modo, il bus LIN non sostituisce il CAN.
Il protocollo LIN
Il bus LIN è particolarmente utilizzato in applicazioni automotive, quali la regolazione degli specchietti retrovisori e dei sedili, il funzionamento del sistema di condizionamento dell’abitacolo o per la gestione della chiusura centralizzata della vettura. Un frame LIN tipico consiste di una serie di campi, la figura 1 mostra la divisione del frame: Synch Break, Synch Field, Identifier, Data Field e il campo checksum.
Ogni byte che compone ogni singolo campo è codificato secondo lo standard USART su 10 bit (start bit, otto bit di dati e uno stop bit), la codifica utilizzata è 8N1 come è mostrato dalla figura 3.
Il protocollo LIN definisce una comunicazione di tipo Master/Slave, basata sulla trasmissione di tipo message broadcast (Message Frame). Ogni Message Frame è costituito da un campo Header e un altro Response. Dalla figura 1 notiamo che il campo Header è formato da tre sezioni: Sync Break, che contraddistingue l’inizio della trasmissione, Sync Field, questa sezione sovrintende alla sincronizzazione della frequenza di trasmissione del nodi Slave con quella del Master; per ultimo abbiamo, poi, la sezione Identifier. Questa ultima sezione permette di descrivere il contenuto informativo del messaggio. Il campo Header è sempre generato dal nodo Master, mentre il campo Response è sia generato dal master e sia dallo slave: il campo Response è utilizzato per trasmettere di buffer di dati (come si evince dalla figura 1). Il campo Synchronization Break marca l’inizio del messaggio LIN. Questo campo è sempre spedito dal Master task e comporta per lo slave di preparare il campo synchronization field. La presenza del campo Sync Break è di fondamentale importanza perché permette al nodo Slave di riconoscere l’inizio di ogni trasmissione. I principali errori che si possono verificare in questo protocollo sono diversi, quali:
Errore di bit. Il bit di output è differente da quello trasmesso. Questo errore appartiene allo Slave ed è rilevato durante la trasmissione.
Errore di checksum. Questo errore è rilevato da un nodo in ricezione. In questo caso il checksum contenuto nel messaggio non coincide con quello calcolato dall’unità ricevente. Questo errore è rilevato, dal Master, durante la ricezione quando riceve messaggi dagli Slave.
Errore di parità nell’Identifier. Rilevato da uno Slave in ricezione. In questo caso l’identificativo del messaggio è corrotto e il messaggio stesso è ignorato. Questo errore è rilevato durante la trasmissione.
La parte Slave del protocollo non risponde. Questo errore è rilevato dal master in ricezione. Tipicamente è evidenziato quando il campo Response non è completato nel tempo massimo previsto dal nodo Slave.
Problemi di sincronizzazione del frame del messaggio. Questo errore è rilevato da uno Slave in ricezione. In questo caso la frequenza di trasmissione rilevata eccede i margini di tolleranza sulle frequenze definite in fase di progetto per ogni applicazione. Un errore di questo tipo è rilevato durante la trasmissione. Uno Slave durante la ricezione può rilevare un errore di parità nell’identifier, un errore del controllo di parità, oppure l’assenza di risposta dallo Slave se riceve da un altro Slave, o ancora una errata sincronizzazione del frame. Il ruolo del campo Sync Break è di fondamentale importanza. I nodi slave, grazie al Sync Break, sono in grado di riconoscere l’inizio della trasmissione. Siccome il campo Sync Break deve essere mantenuto a livello basso per 13 bit-time, mentre tutti gli altri campi hanno la struttura del formato seriale 8N1 della durata di 10 bit-time, risulta di difficile realizzazione del protocollo su periferiche standard, quali le seriali asin2crone (UART) o le sincrone SPI o I C. Infatti, in una seriale asincrona non è possibile generare un Sync Break con queste caratteristiche poiché questa seriale introduce, in modo automatico, il bit di stop. La proposta della Fujitsu è quella di utilizzare le seriali di tipo sincrone (USART), in questo modo si evita di utilizzare, in modo automatico, i bit di start e stop. In una in rete LIN l’accesso è controllato da un nodo master in modo da non richiedere un controllo di collisioni e di arbitraggio nei nodi slave. La specifica del driver di linea e del ricevitore segue lo standard ISO 9141 per singolo filo con alcuni miglioramenti. La velocità massima di trasmissione è di circa 20 kbit/s, derivando dai requisiti sulla compatibilità elettromagnetica (EMC) e dalla sincronizzazione del clock. Un nodo nelle reti LIN non usa alcune informazioni sulla configurazione di sistema, tranne per la denominazione del nodo Master. I nodi possono essere aggiunti alla rete LIN senza richiedere cambiamenti software o hardware negli altri nodi slave gia presenti nella rete. Tipicamente il numero dei nodi di una rete LIN è di 12 nodi (al massimo si possono avere 64 nodi). La sincronizzazione del clock, la semplicità della comunicazione UART ed il singolo filo come mezzo fisico per la comunicazione sono i fattori principali dell’efficacia economica del protocollo LIN.
La proposta Fujitsu
La figura 2 mostra il diagramma a blocchi del componente della Fujitsu.
Da questo diagramma si nota la presenza di una serie di registri che permettono la gestione della funzionalità LIN. Attraverso il Serial Mode Register (SMR) è possibile selezionare quattro modi operativi impostando gli opportuni valori nei due bit MDx, vedi tabella 1.
La modifica dei vari modi di funzionamento è permesso solo quando la trasmissione e/o la ricezione è disabilitata, i bit RXE e TXE del registro SCR (Serial Control Register) devono essere messi a zero. In ogni caso il costruttore suggerisce di resettare il dispositivo, utilizzando a questo scopo il bit UPCL del registro SMR, per rendere operativo il cambio del modo di funzionamento. A titolo di esempio, impostando il registro SMR al valore 0x83, si configura il dispositivo in modo 2 (operazioni sincrona) con la conseguente abilitazione, mentre con 0x87, si resetta il dispositivo stesso. Il registro SCR è utilizzato per controllare la funzionalità del dispositivo; infatti, attraverso questo registro è possibile impostare la parità, controllare gli errori ricevuti, impostare il bit di Stop o di Start, selezionare i caratteri o abilitare/disabilitare la ricezione e la trasmissione. Il registro SMR (Serial Mode Register) permette, oltre a impostare la modalità di funzionamento, anche di scegliere il clock da utilizzare (esterno o interno). In ogni caso la tabella 2 mostra il significato dei singoli bit.
Un altro registro importante per le nostre applicazioni è certamente il registro SSR, o Serial Status Register. La tabella 3 mostra la descrizione funzionale di ogni singolo bit del registro.
L’uso pratico del registro è abbastanza interessante; infatti, attraverso questo registro è possibile controllare ogni tipologia di errore ed è possibile abilitare ogni singola funzionalità semplicemente scrivendo sul relativo bit di abilitazione. Il componente della Fujitsu mette a disposizione il registro ESCR (Extended Status/Control Register) e il registro ECCR (Extended Communication Control Register). Questi due registri sono utilizzati per gestire correttamente il bus LIN. Per completare la nostra descrizione è necessario riportare altri due registri, i registri di ricezione e di trasmissione dei nostri dati nella rete. Il registro RDR, Reception Data Register, è un registro a 8 bit e contiene i dati ricevuti. Il componente della Fujitsu mette a disposizione nel registro SSR un bit RDRF che, opportunamente testato, permette di controllare la presenza di dati nel buffer interno. Inoltre, se fosse abilitato anche la ricezione degli interrupts in ricezione, oltre a comunicare la presenza di dati in ingresso, permette di generare anche un interrupts. Analogamente, la stessa cosa avviene per la trasmissione dei dati attraverso il registro TDR, il Trasmissione Data Register. In questo caso, il registro contiene i dati che occorre spedire.
Esempi
I listati 1 e 2 forniscono dei brevi esempi sui possibili usi del dispositivo. Il listato 1 propone una possibile implementazione del componente in modalità 0 senza l’abilitazione degli interrupts. Viceversa, l’altro listato mostra la possibilità di utilizzare gli eventi asincroni (interrupts) all’interno della nostra applicazione. In questo ultimo caso, la trasmissione inizia immediatamente dopo l’abilitazione degli interrupts svolta attraverso il bit TIE del registro SSR0. Il listato 3 pone in evidenza le definizioni utilizzate per gli eventi asincroni presenti nel file vectors.c.
#include “mb96300.h” void InitUsart0(void) { BGR0 = 1249; // 19200 Baud @ 24MHz SSR0 = 0x00; // LSB first read only default 1 written 0 SMR0 = 0x0d; // enable SOT0, reset, Asynchronous normal mode SCR0 = 0x17; // 8N1, clear possible errors, enable RX, TX PIER08_IE2 = 1; // Enable SIN0 Port Pin } void Putch0(char TXchr) // sends a char { while (SSR0_TDRE == 0); // wait for transmit buffer empty TDR0 = TXchr; // put TXchr into transmission buffer } unsigned char Getch0(void) // Waits for and returns incoming char { unsigned char RXchr; for(;;) { while(SSR0_RDRF == 0) // Wait for data received { __wait_nop(); } RXchr = RDR0; // Save receive register if ((SSR0 & 0xE0) != 0)// Check for errors PE, ORE, FRE { SCR0_CRE = 1; // Clear error flags } else { return (RXchr); // Return received character } } }
Listato 1 |
#include “mb96300.h” #define MAXBUF 100; unsigned char RXbuf[MAXBUF]; // RX Buffer unsigned char TXbuf[MAXBUF]; // TX Buffer unsigned char RXptr = 0; // RX Buffer Pointer unsigned char TXptr = 0; // TX Buffer Pointer void InitUsart0(void) { BGR0 = 1249; // 19200 Baud @ 24MHz SSR0 = 0x00; SMR0 = 0x0d; SCR0 = 0x17; // 8N1, clear errors, enable RX, TX PIER08_IE2 = 1; // Enable SIN0 Port Pin } // Reception Interrupt Service __interrupt void RX_USART0(void) { if ((SSR0 & 0xE0) != 0) // Check for errors { SCR0_CRE = 1; } if (RXptr < MAXBUF) { Rxbuf[RXptr] = RDR0; RXptr++; // Update Buffer Pointer } } // Transmission Interrupt Service __interrupt void TX_USART0(void) { TDR0 = TXbuf[TXptr]; // Send Buffer Data TXptr++; // Update Buffer Pointer if (TXptr == MAXBUF) // End of Buffer reached? { SSR0_TIE = 0; // Disable TX Interrupt } } // Main Function void main(void) { InitIrqLevels(); __set_il(7); // allow all levels __EI(); // globally enable interrupts // Initialize USART0 InitUsart0(); // Fill Transmission Buffer . . . // Start communication SSR0_RIE = 1; // Enable Reception Interrupts SSR0_TIE = 1; // Enable Transmission Interrupts . . . }
Listato 2 |
ICR = ((101 & 0xFF) << 8) | 6; // LIN-UART 0 RX ICR = ((102 & 0xFF) << 8) | 6; // LIN-UART 0 TX . . . __interrupt void RX_USART0(void); // prototipo __interrupt void TX_USART0(void); // prototipo . . . #pragma intvect RX_USART0 101 // LIN-UART 0 RX #pragma intvect TX_USART0 102 // LIN-UART 0 TX
Listato 3 |