La comunicazione I2C per il microcontrollore MAXQ2000

Il bus I2C (o IIC Inter Integrate Communication) è un bus di comunicazione seriale sincrono ideato dalla Philips che utilizza due sole linee di comunicazione, una linea di clock e una linea dati bidirezionale. In questo articolo vedremo come configurare e utilizzare la libreria maxqi2c per interfacciare periferiche con porta di comunicazione I2C ai microcontrollori della famiglia MAXQ. La libreria è formata da 2 file maxqi2c.h e maxqi2c.c, il software si può scaricare dal sito MAXIM Integrated ed è scritto interamente in linguaggio C.  Con questa libreria è possibile realizzare un driver I2C con funzione master per bus funzionanti in standard mode fino a 100KHz e in fast mode fino a 400KHz.

IL BUS I2C

Il bus I2C è un bus di comunicazione seriale con architettura master slave, il dispositivo master controlla la comunicazione sul bus e genera il segnale di clock. Le periferiche I2C si collegano al bus con un driver open collector, per il corretto funzionamento le linee del bus devono essere collegate a due resistenze di  pullup  che realizzano l’and  logico  di tutte le periferiche. Le specifiche prevedono tre velocità massime predefinite per la trasmissione sul bus I2C: standard mode (100Kbps) fast mode (400Kbps) e high speed  mode (3.4Mbps).  Ogni  dispositivo con interfaccia I2C definisce, tra le sue caratteristiche, la velocità massima a cui può comunicare. Il dispositivo più lento collegato al bus determina la massima velocità di comunicazione. Il numero massimo di dispositivi collegabili al bus I2C è limitato dalla capacità di carico che non deve superare i 400pF per garantire i fronti corretti nella commutazione del segnale. Anche le resistenze di pullup del bus devono essere dimensionate in base alla velocità di comunicazione e ai dispositivi collegati come indicato in [2]. Philips ha a catalogo circa 400 dispositivi diversi con interfaccia I2C e molti altri costruttori hanno realizzato  su licenza diverse periferiche.   Per citare le più comuni: I/O expander, RTC, EEprom, LCD controller. Poiché il bus dispone di una sola linea dati la comunicazione  è  necessariamente half  duplex. L’indirizzamento dei dispositivi avviene via software, ogni byte è trasferito dal bit più significativo (MSB). Chi trasmette invia il bit  sulla linea dati quando il clock è basso, mentre con il clock alto la linea dati deve rimanere stabile. Per il sincronismo della comunicazione ci sono due condizioni di controllo definite START e STOP:

  • Nella  condizione  di  START  il  dispositivo master commuta bassa la linea dati quando il clock è alto.
  • Nella condizione di  STOP il  dispositivo  master commuta alta la linea dati quando il clock è alto.

Entrambe le condizioni non si possono manifestare mai durante la normale comunicazione perché la linea dati dev’essere stabile e quando il clock è alto. Il master segnala a tutti  gli salve collegati l’inizio di una comunicazione generando la condizione di START. In ogni istante può interrompere la comunicazione in corso generando la condizione di STOP che riporta il bus nella condizione di riposo. Lo START è sempre seguito da un byte inviato dal master che rappresenta l’indirizzo  del dispositivo slave a cui è destinata la comunicazione. Il bit meno significativo dell’indirizzo  determina il verso della comunicazione se 1 si tratta di una lettura (il master trasferisce dati dallo slave) se 0 si tratta di una scrittura (il master invia dati allo slave). Il  dispositivo slave indirizzato  risponde  a questo byte inviando il bit di ACK che consiste nel pilotare bassa la linea dati per un ciclo di clock. Dopo aver ricevuto l’ACK il master continua a generare il clock mentre i dati sono trasmessi dal master in caso di scrittura o dallo slave in caso di lettura. Dopo la trasmissione di  ogni  byte il dispositivo che riceve il dato deve inviare il bit  di ACK come risposta. Se non viene inviato l’ACK chi trasmette interpreta la condizione come NAK e termina la comunicazione in errore. Al termine il master genera la condizione di  STOP per  concludere la  comunicazione.  La comunicazione master/slave non dev’essere necessariamente continua ma può interrompersi anche per un tempo indefinito (il master blocca il segnale di clock), il dispositivo indirizzato rimane selezionato finché non rileva la condizione di STOP. Anche lo slave può bloccare la linea di clock forzandola a livello basso per un certo tempo. In questo modo segnala al master la necessità di ritardare il trasferimento dei dati. Quando lo slave rilascia la linea di clock il master riprende la comunicazione dal punto in cui è stata interrotta.

LA FAMIGLIA MAXQ

I microcontrollori  MAXQ di Maxim sono dei microcontrollori  RISC (solo 33  istruzioni)  a 16bit  con architettura Harvard. Alcuni modelli sono: il MAXQ2000 che include un moltiplicatore hardware, un LCD driver in grado di pilotare fino  a  132  segmenti e numerose periferiche di comunicazione  seriale/SPI. Poi si sono aggiunti il MAXQ3120 con convertitore sigma-delta 16bit e il MAXQ3210.  La frequenza di  clock può  arrivare a 20MHz con consumi relativamente ridotti.  Sono in grado di eseguire un’istruzione per ciclo raggiungendo così i 20Mips.

LA LIBRERIA I2C PER IL MICROCONTROLLORE MAXQ2000

Le funzioni che compongono la libreria sono quattro [1] [3]:

  • i2cInit: la funzione di inizializzazione del  driver software del bus I2C
  • i2cIsAddrPresent: verifica se l'indirizzo slave, passato come parametro, è collegato al bus
  • i2cSend: invia dati allo slave indirizzato
  • i2cRecv: riceve dati dallo slave indirizzato

la libreria utilizza quattro variabili globali da configurare prima di ogni chiamata alle funzioni di libreria

  • i2cData: puntatore al primo dato  del buffer  dati TX/ o RX
  • i2cDataLen: Lunghezza del buffer dati da trasmettere o ricevere (byte indirizzo escluso)
  • i2cDataAddr: Indirizzo del dispositivo slave
  • i2cDataTerm: Comportamento del driver al termine della comunicazione

I ritardi tra le diverse fasi della comunicazione sul bus I2C sono stati realizzati all’interno della libreria con dei loop di ritardo software. I loop di ritardo sono stati calcolati supponendo di utilizzare un quarzo a 20MHz per il microcontrollore  e dovranno essere modificati se si utilizza un quarzo diverso. Prima di utilizzare la libreria si devono definire i parametri di configurazione hardware che si trovano all’inzio del file maxqi2c.h. Le costanti SDA_PORT,  SDA_PORT_BIT,  SCLK_PORT e SCLK_PORT_BIT definiscono quali pin del microcontrollore sono dedicati al bus I2C, nella configurazione standard rispettivamente P0.0 e P0.1. La definizione  I2C_400_KHZ  o I2C_100_KHZ permette di scegliere la massima velocità di comunicazione in funzione dei dispositivi collegati e del bus realizzato. L’ultima  costante da definire è I2C_CLOCK_STRETCHING da utilizzare nel caso di  periferiche slave particolarmente  lente. Abilitando  questa costante la  procedura  di  lettura  dati  da  una  periferica i2cRecv controlla lo stato della linea di clock prima di iniziare la lettura dei dati. Si deve fare attenzione perché il controllo è bloccante e la procedura rimane in loop  infinito  finché la periferica non  rilascia la linea di clock.

LE FUNZIONI DI LIBRERIA

Come si può vedere esaminando il file maxqi2c.c le funzioni di basso livello implementate nella libreria realizzano tutte le azioni principali della comunicazione I2C. La tabella 1 elenca tutte le funzioni utilizzate nella libreria.

Tabella 1. Le funzioni di basso livello della libreria maxqi2c.c

Tabella 1. Le funzioni di basso livello della libreria maxqi2c.c

Funzione i2cInit()

Non ha nessun parametro in ingresso. Si limita a configurare le linee hardware del microcontrollore  dedicate al bus I2C. Si veda il riquadro porte pushpull e bus I2C.

Funzione i2CIsAddrPresent()

Invia sul bus l’indirizzo del dispositivo slave e attende il bit ACK. Restituisce poi lo stato del bit ACK ricevuto.

In caso di ricezione corretta restituisce 1 o meglio I2C_XMIT_OK nel caso in cui non riceva l’ACK restituisce 0 o I2C_XMIT_FAILED.

Funzione i2cSend()
Configurazione delle variabili prima della chiamata alla procedura:

  • i2cData: Puntatore al primo byte del buffer dati da trasmettere
  • i2cDataLen: Lunghezza del buffer dati da trasmettere (byte indirizzo escluso)
  • i2cDataAddr: Indirizzo del dispositivo slave a cui inviare i dati
  • i2cDataTerm: Comportamento del driver al termine della comunicazione.

Se l’indirizzo i2cDataAddr è diverso da zero, la funzione invia l’indirizzo del dispositivo slave seguito dal buffer  dati  selezionato. Ad ogni  byte  inviato controlla la ricezione dell’ACK (funzione_i2c_low_level_recv_ack)  se riceve la risposta corretta invia il byte successivo altrimenti termina anticipatamente la comunicazione inviando sul bus la condizione di STOP e segnalando al software l’errore  restituendo  il  valore  I2C_XMIT_FAILED.  Nel caso di  comunicazione  corretta  invia  sul bus la condizione  di  STOP e restituisce il  valore I2C_XMIT_OK. Il comportamento della procedura può essere modificato  utilizzando le variabili i2cDataTerm e i2cDataAddr. Se  si assegna il  valore I2C_TERM_NONE alla variabile i2cDataTerm la procedura  non  termina  inviando  la  condizione  di STOP sul bus ma lascia sospesa la comunicazione con  lo  slave che rimane  selezionato. Successive chiamate alla i2CSend con  variabile i2cDataAddr uguale a zero permettono  di inviare altri dati allo salve selezionato senza riaprire la comunicazione con la procedura di START seguito da indirizzo e bit di direzione. La tabella2 riassume le configurazioni ammesse per le due variabili.

Tabella 2. Possibili combinazioni delle variabili I2cDatTerm e I2cDataAddr per la procedura i2cSend

Tabella 2. Possibili combinazioni delle variabili I2cDatTerm e I2cDataAddr per la procedura i2cSend

Funzione i2CRecv()

Configurazione delle variabili prima della chiamata alla procedura.

  • i2cData: Puntatore al primo byte del buffer dati da ricevere
  • i2cDataLen: Lunghezza del buffer dati da ricevere (byte indirizzo escluso)
  • i2cDataAddr: Indirizzo del dispositivo slave da cui leggere i dati
  • i2cDataTerm: Comportamento del driver al termine della comunicazione.

Se l’indirizzo i2cDataAddr è diverso da zero, la funzione invia l’indirizzo del dispositivo slave attende l’ACK da parte dello slave e inizia a leggere dati. Ad ogni  byte  ricevuto  invia il  bit  di  ACK (funzione _i2c_low_level_send_ack)  e ripete il ciclo di lettura del byte successivo. Se la procedura non riceve l’ACK dallo slave dopo aver inviato l’indirizzo allora invia sul bus la condizione di  STOP e termina  segnalando al software l’errore restituendo il valore I2C_XMIT_FAILED.  Se la comunicazione termina correttamente il master invia sul bus la condizione di STOP e restituisce il valore I2C_XMIT_OK. Il comportamento della procedura può essere modificato  utilizzando  le variabili i2cDataTerm e i2cDataAddr. se si assegna il valore I2C_TERM_ACK alla variabile i2cDataTerm la procedura non termina inviando la condizione di STOP sul bus ma restituisce l’ACK all’ultimo  dato  ricevuto e lascia sospesa  la comunicazione con  lo  slave che resta selezionato. Successive chiamate  alla  i2CSend con  variabile i2cDataAddr uguale a zero permettono  di leggere altri  dati  allo salve indirizzato  senza riaprire la comunicazione con la procedura di START seguito da indirizzo e bit di direzione. Se invece alla variabile  i2CDataTerm viene assegnato il  valore I2C_TERM_NACK_AND_STOP la procedura termina chiudendo la comunicazione con lo slave indirizzato. La tabella3  riassume le  configurazioni  ammesse per le due variabili.

Tabella 3. Possibili combinazioni delle variabili I2cDatTerm e I2cDataAddr per la procedura i2cRecv

Tabella 3. Possibili combinazioni delle variabili I2cDatTerm e I2cDataAddr per la procedura i2cRecv

 

Bibliografia

[1]  Maxim appnote 3588 (www.maxim-ic.com/appnotes.cfm/appnote_number/3588)

[2]  The I2C bus specifications  v 2.1-january 2000 (link)

[3] Esempio di progetto: http://www.maxim-ic.com/tools/other/appnotes/4267/4267_software.zip

PORTE PUSHPULL E I2C

Non si può utilizzare un driver pushpull per le porte collegate al bus I2C. Utilizzando un driver pushpull, infatti, a riposo tutti  i dispositivi devono lasciare le linee del bus nello stato high e quindi il transistor alto del driver pushpull dev’essere in saturazione.  Se un dispositivo pilota il bus I2C a livello basso si crea un cortocircuito tra la porta pushpull e il driver I2C che porta bassa la linea del bus. Se il dispositivo da collegare, come il MAXQ2000, non ha I/O configurabili come open collector si deve adottare una tecnica di controllo particolare per evitare di danneggiare il driver d’uscita. Si simula il comportamento  di una porta open collector utilizzando solamente il transistor basso del driver pushpull. Il bit corrispondente nel registro di output della porta dev’essere sempre impostato a zero. Lo stato della porta viene modificato utilizzando il registro di direzione in/out  anziché il registro di output che deve sempre rimanere a zero. Per trasmettere un bit a 0 si configura la porta in output e la linea del bus si porta bassa, per trasmettere un bit a 1 si configura la porta in input. Quando la porta è in input il pullup del bus può mantenere alta la linea dati. Gli altri dispositivi connessi al bus interpretano questa condizione come trasmissione di un bit a 1. La procedura i2cInit configura a zero i bit del registro di output  dei pin selezionati per la comunicazione I2C e configura le line in input per lasciare il bus nello stato di riposo. Si osserva che le macro SDA e SCL definite nel file maxqi2c.h sono riferite al registro direzione della porta anziché al registro di output

 

 

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS

STAMPA     Tags:, , ,

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio Di Paolo Emilio 17 agosto 2017

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Iscriviti e ricevi GRATIS
Speciale Pi

Fai subito il DOWNLOAD (valore 15€) GRATIS