Più dispositivi I2C

Premessa: sto imparando ::slight_smile:
Se dirò qualche str... perdonatemi :-[

Vorrei capire meglio questo protocollo I2C. Mi par di capire che potrei mettere più dispositivi I2C insieme, ed interrogarli singolarmente semplicemente usando un ID, giusto?

Mi spiego. Ho acquistato uno shield Nueletronics 3310 LCD e mi sono autocostruito uno shield con un DS1307 ed un sensore LM335Z. Semplificando, leggo dal mio shield data, ora e temp e li visualizzo sull'LCD. In pratica, mi sono fatto un rudimentale orologio/termometro.

Se io volessi in futuro inserire un altro shield magari con un altro dispositivo I2C (una EEPROM per fare ad esempio il log della temperatura per vedere durante l'arco del giorno come varia) potrei collegarlo all'ATmega tramite sempre gli stessi pin SCL/SDA e gestire memoria e RTC insieme?

Si, esattamente, i2c e' un bus che funziona con due fili, percui puoi attaccare fino a un numero massimo di 127 chip i2c sul tuo bus e gestirli sempre con gli stessi due fili, indicando indirizzi differenti.

Ogni integrato ha un indirizzo base diverso e molti integrati hanno tre pin configurabili, di solito segnati come A1 A2 e A3 per variare questo indirizzo (puoi impostarli come VCC o GND). Questo significa che per alcuni tipi di integrati puoi averne fino a 8 sullo stesso bus.

Cerca uno sketch che si chiama i2c scanner, e' utile quando inizi a smandrappare con i2c!

Federico

PS: ho appena passato tutta la serata a smadonnare su un pcf moltiplicatore di porte su i2c :slight_smile:

Ti ringrazio per la risposta.
Ma aiutami a capire una cosa. Chi stabilisce questo indirizzo base?
Per esempio, nel caso del DS1307, leggendo la documentazione non mi pare che ci sia specificato quale indirizzo usa, eppure viene usato generalmente 0x68 (ad esempio Adafruit nel suo sketch di esempio). Da dove è stato ricavato/impostato?

infatto credo che il DS1307 abbia un indirizzo fisso non puoi impostarlo tu.

E' vero, rileggendo la documentazione ho trovato l'indirizzo 0b1101000 che è appunto 0x68.
E questo risolve il problema del DS1307.

E, per esempio, ho trovato anche l'indirizzo della Eeprom 24LC64. Si legge infatti:

A control byte is the first byte received following the START condition from the master device (Figure 3-2). The control byte consists of a four bit control code; for the 24XX64 this is set as 1010 binary for read and write operations. The next three bits of the control byte are the chip select bits (A2, A1, A0). The chip select bits allow the use of up to eight 24XX64 devices on the same bus and are used to select which device is accessed.

Quindi, ricapitoliamo....
Dalla scheda tecnica del dispositivo I2C si estrae la parte fissa dell'indirizzo, oppure addirittura l'intero indirizzo come nel caso del DS1307. In quest'ultimo caso si usa direttamente, mentre nel primo caso al valore fisso si aggiunge la parte impostata mediante i piedini A0, A1 e A2.

Quindi per indirizzare un 24LC64 posso mettere 1010000 mettendo A0, A1 e A2 a "0". Se aggiungo un altro chip, questo lo posso impostare su 1010001 mettendo A0 e A1 a "0" e A2 a "1".

Ovviamente immagino che "0" stia per GND e "1" per Vcc.

si funziona come hai descritto :wink:

Ciao a tutti.
Mi accodo a questo thread perché ho anch'io un problema con il bus I2C con una o più periferiche (potenziali).
Ho provato con lo sketch I2C scanner, se lo eseguo collegando solo Arduino mi dà (chiaramente) nessun device found, e ci mette un paio di secondi o giù di lì.
Ho collegato un mio shield sul quale vorrei provare delle EEPROM AT24Cxx e un clock DS1307 (o PCF8563).
Sullo shield al momento ci sono solo i tre zoccoli vuoti, due piste lunghe 5cm collegate con SDA e SCL e due resistenze di pullup da 4k7 collegate fra ciascuna pista e la 5V.
Se lancio I2C Scanner con lo shield collegato verifica un paio di indirizzi, tre al massimo e poi si blocca e rimane lì.
Il bus I2C va terminato in qualche modo? Possono crearsi capacità che mi bloccano il bus?
Vi ringrazio per ogni suggerimento.
Ciao
TT:

Ciao TicioTIX

Non ho ancora provato di usare la sketch I2Cscanner, ma mi immagino che fa una scansione, stampa i risultati e poi si ferma. Percui é giusto.

Il bus non deve essere terminato, deve essere messo con 2 resistenza a 5V come Tu hai giá fatto. Il valore dipende dalla capacitá delle piste di collegamento.
Se Ti funziona ( lo scanner riconosce tutti i dispositivi collegati) vuol dire che le resistenze hanno i valori giusti. Se in futuro aggiungi altri dispositivi e allunghi le piste puó essere necessario mettere delle resistenze piú piccole, ma fallo solo se non funziona piú.

Ciao Uwe

Ciao Uwe.
Sono d'accordo con te...il problema è che non funziona.
Mi spiego meglio: I2C scanner funziona, non trova niente se niente è collegato, ma funziona. Se lo lancio su Arduino nudo va benissimo, completa il suo ciclo di controlli e ritorna. Non trova periferiche I2C perché non ce ne sono.
Poi stacco Arduino dalla USB, inserisco lo shield nudo (senza periferiche) su Arduino, ricollego la USB, I2C scanner riparte e io mi aspetterei facesse la stessa cosa.
Ma non arriva alla fine della scansione. Prova i primi 2 o tre indirizzi e poi si blocca. Come se quel bus, senza periferiche ma con le due resistenze di PullUp non rispondesse correttamente.
Ciao e grazie.
TT:

Tu dici che sul Terminale incomincia a stampare un parte della lista degli indirizzi e non va avanti?

Dovrei controllare il codice. vediamo se ho tempo piú tardi.
Ciao Uwe

Ciao a tutti.
Ho proseguito con i miei esperimenti "smanazzando" un po' il codice di i2c scanner.
Quello che ho notato è che collegando lo shield si alza paurosamente il tempo "di avvio" (pardon per l'espressione...) del bus.
Ho sparso un po'di millis() in giro per il codice e, solo con l'arduino, la verifica di ogni indirizzo viaggia sotto i 10ms.
Ho installato lo shield e controllando la procedura di scrittura su I2c, in twi.c, funzione
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait),
mi trovo un:

// wait until twi is ready, become master transmitter
while(TWI_READY != twi_state)
{
continue;
}

e mi risulta che da quel ciclo non ne usciamo vivi....
Ho modificato in:

#include <wiring.h>
#define MAX_TIMEOUT 100
uint16_t Elapsed = millis();

// wait until twi is ready, become master transmitter
while(TWI_READY != twi_state)
{
if ((millis()-Elapsed)>MAX_TIMEOUT) return 8;
//continue;
}

alzando MAX_TIMEOUT fino a 100 ma esce sempre dal ciclo con RetValue=8.
La mia paura è che quel bus abbia delle capacità che si oppongono alle variazioni di tensione (castroneria??) impedendo un corretto funzionamento del bus.
Ciao e grazie.
TT:

Ciao TicioTIX, anche io devo usare delle periferiche I2C e ho letto qualcosa in rete di un tipo che dice di mettere le R di pullup da 1.5k, in effetti c'è più corrente e forse si riduce pure un pò la capacità tuttavia 400pF sono tanti, difficile raggiungerli con un solo dispositivo.

Se il codice dello scanner lavora per gli altri allora è corretto. Per le resistenze c'è anche la possibilità di mettere due resistenze aggiuntive tra ogni linea del dispositivo e il BUS, però mi pare di aver capito che ciò è utile quando ci sono più dispoditivi.

Ciao

Ciao Mauro...
Hai ragione sul fatto che I2C Scanner funzioni correttamente, infatti se lo uso senza shield e periferiche il problema non si pone.
Sembra in effetti che Arduino non riesca a "tirare giù" il bus.
Non so quanto serva (sono decisamente insufficiente in elettronica analogica ...) ma in giro ho anche trovato schemi di "terminatori attivi".
Credo si tratti in realtà di un "pullup intelligente". Questo è lo schema )
ma mi sfuggono i dettagli del suo funzionamento.
Ciao
TT:

Hai ragione sul fatto che I2C Scanner funzioni correttamente, infatti se lo uso senza shield e periferiche il problema non si pone.

Attenzione io non ho detto che funziona e il fatto che sembra funzionare se non c'è nessun dispositivo sul BUS, non vuole dire che funziona.

Mi spiego la mia non una conferma, cercavo di escludere il software per focalizzare l'attenzione sull'hardware, o viceversa.

Mentre per il circuito che hai postato posso dirti che si tratta di un doppio generatore di corrente costante.

A vederlo così, non mi sembra meglio delle sole resistenze, la porta così vede un'alta impedenza in AC, quindi c'è vantaggio con alta frequenza di trasmissione.
Mentre nei confronti della DC la corrente sul collettore, dovrebbe essere più stabile rispetto alle resistenze, tuttavia come vedi la base dei due generatori è libera in AC, questo comporta una maggiore sensibilità ai disturbi, che possono anche inquinare il segnale.

Per rederlo meno sensibile si può mettere un condensatore tra base e GND, minimo 100nF max 10uF.

Per il software invece dovresti vedere su quale codice si blocca, magari e proprio lì il problema, cioè il master aspetta risposta che non arriva dallo slave.

Ok ciao.

Grazie Mauro.
Anche secondo me il problema è nel mio hardware, anzi ne sono praticamente certo.
La mia strategia era usare il software (sono un programmatore C) per vedere se riesco a capire cosa non vada nell'hardware.
Se ho ben capito lo scanner invia un messaggio ad ogni indirizzo e si aspetta uno 0xFF se è presente uno slave e qualcos'altro se non è presente (di norma un NAK).
Se lo lancio con solo l'arduino collegato ricevo sempre in risposta uno SLA_NACK.
Se collego il mio shield a zoccoli vuoti la funzione di scrittura su TWI si blocca sull'attesa dello stato di TWI_READY, di fatto quindi prima ancora inviare qualunque cosa sul bus.
Quindi di fatto non ha troppo senso parlare di corretto funzionamento (ovverossia corretta rilevazione slave) di I2C Scanner ... non mi va in READY il bus...
Ciao e sempre grazie.
TT:

Ciao a tutti.
Come volevasi dimostrare: era un banale problema hardware.
Sono bastate un paio di analogRead sui due pin SDA e SCL all'avvio di Arduino (prima della Wire.begin()) per notare che SDA era molto vicino ai 5V, mentre SCL era sotto i 2.
Ho ripassato il circuito separando bene col cutter le saldature ravvicinate e si è messo a funzionare tutto.
Ciao e grazie per i consigli (che non mancherò di sfruttare).
TT:

EUREKA :slight_smile:
E quindi ora lo scanner funge.
ciao e buon divertimento.