Der I²C / TWI -bus - HTW Dresden€¦ · 3 Schaltung TWI mit 128 bit EEPROM und Temperatursensor...
Transcript of Der I²C / TWI -bus - HTW Dresden€¦ · 3 Schaltung TWI mit 128 bit EEPROM und Temperatursensor...
1
Der I²C / TWI -bushttp://www.mikrocontroller.net/articles/AVR_TWI
● Two Wire Interface (TWI)● Bus zum Datenaustausch zwischen mehreren Bau-
steinen und Controllern in der Regel innerhalb eines Gerätes.
● Wird von einer Vielzahl von Bausteinen unterstützt.● Basiert auf einer Entwicklung von Phillips (I²C-Bus).● Ermöglicht auch die Kommunikation zwischen Control-
lern.● Bitserielle Übertragung● Verbindung über die Leitungen GND, SCL, SDA.
● Two Wire Interface (TWI)● Bus zum Datenaustausch zwischen mehreren Bau-
steinen und Controllern in der Regel innerhalb eines Gerätes.
● Wird von einer Vielzahl von Bausteinen unterstützt.● Basiert auf einer Entwicklung von Phillips (I²C-Bus).● Ermöglicht auch die Kommunikation zwischen Control-
lern.● Bitserielle Übertragung● Verbindung über die Leitungen GND, SCL, SDA.
2
● Die Kommunikation wird immer durch einen Master eingeleitet
● Bis zu 127 Slaves können über den Bus erreicht werden
● Jedes Gerät wird über Gerätenummer identifi-ziert
● Die Gerätenummer 0 ist reserviert und dient als broadcastadresse.
● Unter
http://www.peterfleury.epizy.com/avr-software.html
findet man eine sehr gute Implementation eines TWI Masters für Atmega.
● Die Kommunikation wird immer durch einen Master eingeleitet
● Bis zu 127 Slaves können über den Bus erreicht werden
● Jedes Gerät wird über Gerätenummer identifi-ziert
● Die Gerätenummer 0 ist reserviert und dient als broadcastadresse.
● Unter
http://www.peterfleury.epizy.com/avr-software.html
findet man eine sehr gute Implementation eines TWI Masters für Atmega.
3
● Die Gerätenummer ist eine 7-bit- Zahl.● Bei Atmega ist Sie mit 2 multipliziert, ist also
linksbündig in einem Byte gespeichert und ist somit geradzahlig.
● Die Gerätenummer besteht oft aus zwei Teilen, einem festen Teil (4-6 bit) und einem variablen Teil, der durch externe Beschaltung gebildet wird.
● Das Bit 8, das niederwertigste Bit dient der übermittlung der Übertragungsrichtung (read/write)
● Die Gerätenummer ist eine 7-bit- Zahl.● Bei Atmega ist Sie mit 2 multipliziert, ist also
linksbündig in einem Byte gespeichert und ist somit geradzahlig.
● Die Gerätenummer besteht oft aus zwei Teilen, einem festen Teil (4-6 bit) und einem variablen Teil, der durch externe Beschaltung gebildet wird.
● Das Bit 8, das niederwertigste Bit dient der übermittlung der Übertragungsrichtung (read/write)
Gerätenummer
4
Schaltung TWImit 128 bit EEPROM und Temperatursensor DS1621
Für die beiden Widerstände wird 4,7K empfohlen
5
Typische Anschlusspins
● SDA: Datenleitung● SCL: Clockleitung● A1, A2, A3 Codierungsanschlüsse für
Adresseinstellung● VCC/VDD Betriebsspannung (5V)● GND● Die Anschlussbelegung ist IMMER dem
Datenblatt zu entnehmen. Die Anschlussbelegung von Bausteinen in gleicher Gehäuseausführung ist nicht einheitlich!
● SDA: Datenleitung● SCL: Clockleitung● A1, A2, A3 Codierungsanschlüsse für
Adresseinstellung● VCC/VDD Betriebsspannung (5V)● GND● Die Anschlussbelegung ist IMMER dem
Datenblatt zu entnehmen. Die Anschlussbelegung von Bausteinen in gleicher Gehäuseausführung ist nicht einheitlich!
6
Typische Bausteinehttp://www.mikrocontroller.net/articles/I2C
https://rn-wissen.de/wiki/index.php/I2C_Chip-%C3%9Cbersicht
serielle EEPROMs (24Cxx )
I/O-Portexpander (PCF8574,MCP23008 (8-bit) von Microchip, MCP23017 (16-bit) von Microchip )
I2C MUX, zum Anschluss von ICs mit gleicher, fester Adresse (PCA9545A )
AD-Wandler (MCP3424, auch für Raspberry)
DA-Wandler (TDA8444, 8x6Bit )
Uhrenbausteine (PCF8583, mit 256 Bytes RAM )
LCD-Treiber
Temperatursensoren (DS1621, LM75, TMP101 von TexasInstruments ,TMP175 von TI)
serielle EEPROMs (24Cxx )
I/O-Portexpander (PCF8574,MCP23008 (8-bit) von Microchip, MCP23017 (16-bit) von Microchip )
I2C MUX, zum Anschluss von ICs mit gleicher, fester Adresse (PCA9545A )
AD-Wandler (MCP3424, auch für Raspberry)
DA-Wandler (TDA8444, 8x6Bit )
Uhrenbausteine (PCF8583, mit 256 Bytes RAM )
LCD-Treiber
Temperatursensoren (DS1621, LM75, TMP101 von TexasInstruments ,TMP175 von TI)
Für Raspberry Addons viel benutzt
7
long distance treiber
https://www.nxp.com/docs/en/data-sheet/P82B96.pdf
P82B96
8
Adressierung von Bausteinen
● Jeder Baustein hat eine Grundadresse, diese ist aus dem Manual zu ermitteln (manchmal et-was tricky versteckt) DS1621: 1001 .
● Über die Adressbits werden die Bits 1,2 und 3 gebildet.
● Bit 0 bleibt frei, über dieses Bit wird die Über-tragungsrichtung (r/w) gesteuert.
● Jeder Baustein hat eine Grundadresse, diese ist aus dem Manual zu ermitteln (manchmal et-was tricky versteckt) DS1621: 1001 .
● Über die Adressbits werden die Bits 1,2 und 3 gebildet.
● Bit 0 bleibt frei, über dieses Bit wird die Über-tragungsrichtung (r/w) gesteuert.
1 0 0 1 A2 A1 A0 r/w
Bit 0Bit 7
http://www.elektronik-magazin.de/page/i2c-bus-adressliste-23
9
Arbeitsweise
● SCL und SDL liegen auf 1.● SDL nach 0 bei SCL=1 zeigt an, dass ein Ge-
rät Daten übertragen will (Start condition).● Wärend einer Übertragung, kann sich der Zu-
stand von SDA ändern, wenn SCL=0 ist. Wenn SCL=1, sind die Daten gültig und dürfen sich nicht ändern.
● Für 1 Byte werden 9 bit übertragen, das 9. Bit zeigt an, ob die Übertragung eines weiteren Bytes folgt (ack:Acknowledge, nak:not Ack…).
● SCL und SDL liegen auf 1.● SDL nach 0 bei SCL=1 zeigt an, dass ein Ge-
rät Daten übertragen will (Start condition).● Wärend einer Übertragung, kann sich der Zu-
stand von SDA ändern, wenn SCL=0 ist. Wenn SCL=1, sind die Daten gültig und dürfen sich nicht ändern.
● Für 1 Byte werden 9 bit übertragen, das 9. Bit zeigt an, ob die Übertragung eines weiteren Bytes folgt (ack:Acknowledge, nak:not Ack…).
11
TWGCE General Call Enable (Broadcast: dev0x00, nur bei Slave belegt)1: General Call Enable, 0: not
TWGCE General Call Enable (Broadcast: dev0x00, nur bei Slave belegt)1: General Call Enable, 0: not
TWDR TWI DatenRegister
7 6 5 4 3 2 1 0
TWD7 TWD6 TWD5 TWD4 TWD3 TWD2 TWD1 TWD0
R/W R/W R/W R/W R/W R/W R/W R/W
TWDR TWI DatenRegister
7 6 5 4 3 2 1 0
TWD7 TWD6 TWD5 TWD4 TWD3 TWD2 TWD1 TWD0
R/W R/W R/W R/W R/W R/W R/W R/W
TWAR TWI SlaveAdressRegister
7 6 5 4 3 2 1 0
TWA6 TWA5 TWA4 TWA3 TWA2 TWA1 TWA0 TWGCE
R/W R/W R/W R/W R/W R/W R/W R/W
TWAR TWI SlaveAdressRegister
7 6 5 4 3 2 1 0
TWA6 TWA5 TWA4 TWA3 TWA2 TWA1 TWA0 TWGCE
R/W R/W R/W R/W R/W R/W R/W R/W
12
TWCR - TWI Control Register
TWCR TWI ControlRegister
7 6 5 4 3 2 1 0
TWINT TWEA TWSTA TWSTO TWWC TWEN TWIE
R/W R/W R/W R/W R R/W R R/W
TWCR TWI ControlRegister
7 6 5 4 3 2 1 0
TWINT TWEA TWSTA TWSTO TWWC TWEN TWIE
R/W R/W R/W R/W R R/W R R/W
Bit Description
TWINT TWI-Interruptflag
TWEA Ack wird gesendet
TWSTA TWI start senden
TWSTO TWI Stop senden
TWWC Fehleranzeige
TWEN TWI enable
TWIE TWI Interrupt enable
Bit Description
TWINT TWI-Interruptflag
TWEA Ack wird gesendet
TWSTA TWI start senden
TWSTO TWI Stop senden
TWWC Fehleranzeige
TWEN TWI enable
TWIE TWI Interrupt enable
13
TWSR TWI StatusRegister
7 6 5 4 3 2 1 0
TWS7 TWS6 TWS5 TWS4 TWS3 - TWPS1 TWPS0
R R R R R R R/W R/W
TWSR TWI StatusRegister
7 6 5 4 3 2 1 0
TWS7 TWS6 TWS5 TWS4 TWS3 - TWPS1 TWPS0
R R R R R R R/W R/W
Bit Description
TWS7
Statusbits
TWS6
TWS5
TWS4
TWS3
TWPS1Vorteiler
TWPS0
Bit Description
TWS7
Statusbits
TWS6
TWS5
TWS4
TWS3
TWPS1Vorteiler
TWPS0
14
Implementation von P. Fleuryvoid i2c_init(void);
void i2c_stop(void);
unsigned char i2c_start(unsigned char addr);
unsigned char i2c_rep_start(unsigned char addr);
void i2c_start_wait(unsigned char addr);
unsigned char i2c_write(unsigned char data);
unsigned char i2c_readAck(void);
unsigned char i2c_readNak(void);
void i2c_init(void);
void i2c_stop(void);
unsigned char i2c_start(unsigned char addr);
unsigned char i2c_rep_start(unsigned char addr);
void i2c_start_wait(unsigned char addr);
unsigned char i2c_write(unsigned char data);
unsigned char i2c_readAck(void);
unsigned char i2c_readNak(void);
15
Hinweise zur Nutzung des Archivs● Im Archiv befinden sich folgende Dateien:
– i2cmaster.h (einbinden in Anwendung)– i2cmaster.S (I²C Library für gewöhnliche Pins)– twimaster.c (I²C Library AVR-TWI-basiert)– test_i2cmaster.c (Testbeispiel mit 24C02)
● i2Cmaster.h mit include einbinden● twimaster.c ins Makefile einbauen● Die Verwenung von i2cmaster.S sollte auch gehen, ist
aber nicht sinnvoll, wenn der Prozessor TWI unterstützt und die IO-Leitungen nicht anderweitig belegt sind.
● Im Archiv befinden sich folgende Dateien:
– i2cmaster.h (einbinden in Anwendung)– i2cmaster.S (I²C Library für gewöhnliche Pins)– twimaster.c (I²C Library AVR-TWI-basiert)– test_i2cmaster.c (Testbeispiel mit 24C02)
● i2Cmaster.h mit include einbinden● twimaster.c ins Makefile einbauen● Die Verwenung von i2cmaster.S sollte auch gehen, ist
aber nicht sinnvoll, wenn der Prozessor TWI unterstützt und die IO-Leitungen nicht anderweitig belegt sind.
16
Schreiben eines Bytes ->24C02
i2c_init();
ret=i2c_start(addr); // R/W=1:Read,0:Write
i2c_write(eepromAddr);
i2c_write(val)
i2c_stop();
i2c_init();
ret=i2c_start(addr); // R/W=1:Read,0:Write
i2c_write(eepromAddr);
i2c_write(val)
i2c_stop();
17
Schreiben von N Bytes ->24C02i2c_init();ret = i2c_start(Dev24C02+I2C_WRITE); if ( ret==0 ){ // issuing start condition ok, device accessible i2c_write(00); // write start address = 0 (muss /8 teilbar sein) int i; for (i=0;i<N;i++) { i2c_write(send[i]); if ((i+1)%8==0) { //set next address i2c_stop(); i2c_start_wait(Dev24C02+I2C_WRITE); i2c_write(i+1); //Next Address page } }i2c_stop();}// end if
i2c_init();ret = i2c_start(Dev24C02+I2C_WRITE); if ( ret==0 ){ // issuing start condition ok, device accessible i2c_write(00); // write start address = 0 (muss /8 teilbar sein) int i; for (i=0;i<N;i++) { i2c_write(send[i]); if ((i+1)%8==0) { //set next address i2c_stop(); i2c_start_wait(Dev24C02+I2C_WRITE); i2c_write(i+1); //Next Address page } }i2c_stop();}// end if
I2C_WRITE ist 0 undkann deshalb entfallen
Versand eines Datenbytes
Geht so nur, wenn Startadresse0 ist. Ansonsten muss dieStartadresse noch addiert werden!
18
Lesen mehrerer Bytes aus 24C02
i2c_start_wait(Dev24C02+I2C_WRITE); // device and write mode i2c_write(0x00); // write address = 0 i2c_rep_start(Dev24C02+I2C_READ); // device and read mode for (i=0;i<N-1;i++) { read[i] = i2c_readAck(); // read one Byte if (read[i]>=' ') lcd_putc(read[i]); } read[i] = i2c_readNak(); // read last Byte lcd_putc(read[i]); i2c_stop(); // set stop condition = release bus
i2c_start_wait(Dev24C02+I2C_WRITE); // device and write mode i2c_write(0x00); // write address = 0 i2c_rep_start(Dev24C02+I2C_READ); // device and read mode for (i=0;i<N-1;i++) { read[i] = i2c_readAck(); // read one Byte if (read[i]>=' ') lcd_putc(read[i]); } read[i] = i2c_readNak(); // read last Byte lcd_putc(read[i]); i2c_stop(); // set stop condition = release bus
19
TWI Atmega als slavehttp://www.rn-wissen.de/index.php/TWI_Slave_mit_avr-gcc
● Ermöglicht Kommunikation zwischen mehreren Atmel Controllern
● Slaveadresse festlegen● Sende- / Empfangspuffer definieren● void init_twi_slave (uint8_t dev_addr);● ISR (TWI_vect)● Includes:
– #include <util/twi.h> // Statuscodes in TWSR ...– #include <avr/interrupt.h> – #include <stdint.h> //definiert den Datentyp uint8_t
● Ermöglicht Kommunikation zwischen mehreren Atmel Controllern
● Slaveadresse festlegen● Sende- / Empfangspuffer definieren● void init_twi_slave (uint8_t dev_addr);● ISR (TWI_vect)● Includes:
– #include <util/twi.h> // Statuscodes in TWSR ...– #include <avr/interrupt.h> – #include <stdint.h> //definiert den Datentyp uint8_t
20
/*ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann ein Statuscode, anhand dessen die Situation festgestellt werden kann. */
ISR (TWI_vect) { uint8_t data=0;
//TWI-Statusregister prüfen und nötige Aktion bestimmen
switch (TW_STATUS) { /* ein master hat Kommunikationswunsch mit unserer Adresse signalisiert*/
// 0x60 Slave Receiver, wurde adressiert case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert
TWCR_ACK; // Datenbyte empfangen, ACK danach buffer_adr=0xFF;//Bufferposition ist undefiniert
break;
/*ISR, die bei einem Ereignis auf dem Bus ausgelöst wird. Im Register TWSR befindet sich dann ein Statuscode, anhand dessen die Situation festgestellt werden kann. */
ISR (TWI_vect) { uint8_t data=0;
//TWI-Statusregister prüfen und nötige Aktion bestimmen
switch (TW_STATUS) { /* ein master hat Kommunikationswunsch mit unserer Adresse signalisiert*/
// 0x60 Slave Receiver, wurde adressiert case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert
TWCR_ACK; // Datenbyte empfangen, ACK danach buffer_adr=0xFF;//Bufferposition ist undefiniert
break;
21
// 0x80 Slave Receiver,Daten empfangen case TW_SR_DATA_ACK:
if (TWCR&&(1<<TWINT)) data=(uint8_t)TWDR; //Daten lesen
else data=0;
if (buffer_adr == 0xFF) //erster Zugriff,0x60 Bufferposition (Addresss) setzen
{
//Kontrolle ob gewünschte Adresse im erlaubten Bereich
if(data<=buffer_size) buffer_adr= data; //Bufferposition wie adressiert setzen
else buffer_adr=0; //Adresse auf Null setzen.(Sinnvoll?)
TWCR_ACK; // ACK danach, um nächstes Byte anzufordern }
else //weiterer Zugriff, Daten empfangen
{
rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben buffer_adr++; //increment Buffer-Adresse für nächsten Schreibzugriff
if(buffer_adr<(buffer_size-1)) //im Buffer ist noch Platz für mehr als ein Byte
TWCR_ACK; // ACK danach, um nächstes Byte anzufordern
else //es kann nur noch ein Byte kommen, dann ist der Buffer voll
TWCR_NACK; //letztes Byte lesen, dann NACK, um Ende zu signaliseren
} break;
// 0x80 Slave Receiver,Daten empfangen
case TW_SR_DATA_ACK:
if (TWCR&&(1<<TWINT)) data=(uint8_t)TWDR; //Daten lesen
else data=0;
if (buffer_adr == 0xFF) //erster Zugriff,0x60 Bufferposition (Addresss) setzen
{
//Kontrolle ob gewünschte Adresse im erlaubten Bereich
if(data<=buffer_size) buffer_adr= data; //Bufferposition wie adressiert setzen
else buffer_adr=0; //Adresse auf Null setzen.(Sinnvoll?) TWCR_ACK; // ACK danach, um nächstes Byte anzufordern
}
else //weiterer Zugriff, Daten empfangen
{
rxbuffer[buffer_adr]=data; //Daten in Buffer schreiben buffer_adr++; //increment Buffer-Adresse für nächsten Schreibzugriff
if(buffer_adr<(buffer_size-1)) //im Buffer ist noch Platz für mehr als ein Byte
TWCR_ACK; // ACK danach, um nächstes Byte anzufordern
else //es kann nur noch ein Byte kommen, dann ist der Buffer voll
TWCR_NACK; //letztes Byte lesen, dann NACK, um Ende zu signaliseren
} break;
22
case TW_ST_SLA_ACK: //?!?
//0xB8 Slave Transmitter, weitere Daten wurden angefordert
case TW_ST_DATA_ACK:
if (buffer_adr == 0xFF) //zuvor keine Leseadresse angegeben!
buffer_adr=0;
TWDR = txbuffer[buffer_adr]; //Datenbyte senden
buffer_adr++; //bufferadresse für nächstes Byte weiterzählen
if(buffer_adr<(buffer_size-1)) //noch mehr als ein Byte im Sendepuffer
TWCR_ACK; //nächstes Byte senden, danach ACK erwarten
else
TWCR_NACK; //letztes Byte senden, danach NACK erwarten
break;
case TW_ST_SLA_ACK: //?!?
//0xB8 Slave Transmitter, weitere Daten wurden angefordert
case TW_ST_DATA_ACK:
if (buffer_adr == 0xFF) //zuvor keine Leseadresse angegeben!
buffer_adr=0;
TWDR = txbuffer[buffer_adr]; //Datenbyte senden
buffer_adr++; //bufferadresse für nächstes Byte weiterzählen
if(buffer_adr<(buffer_size-1)) //noch mehr als ein Byte im Sendepuffer
TWCR_ACK; //nächstes Byte senden, danach ACK erwarten
else
TWCR_NACK; //letztes Byte senden, danach NACK erwarten
break;
23
// 0xC0 Keine Daten mehr gefordert case TW_ST_DATA_NACK: // 0x88 case TW_SR_DATA_NACK:
// 0xC8 Last data byte in TWDR has been transmitted // (TWEA = “0”); ACK has been received case TW_ST_LAST_DATA:
// 0xA0 STOP empfangen case TW_SR_STOP:
//Übertragung beenden, warten bis zur nächsten Adressierung default: TWCR_RESET;
break; } //end.switch (TW_STATUS)
// 0xC0 Keine Daten mehr gefordert case TW_ST_DATA_NACK: // 0x88 case TW_SR_DATA_NACK:
// 0xC8 Last data byte in TWDR has been transmitted // (TWEA = “0”); ACK has been received case TW_ST_LAST_DATA:
// 0xA0 STOP empfangen case TW_SR_STOP:
//Übertragung beenden, warten bis zur nächsten Adressierung default: TWCR_RESET;
break; } //end.switch (TW_STATUS)
24
25