• Keine Ergebnisse gefunden

Der I²C / TWI -bus http://www.mikrocontroller.net/articles/AVR_TWI

N/A
N/A
Protected

Academic year: 2021

Aktie "Der I²C / TWI -bus http://www.mikrocontroller.net/articles/AVR_TWI"

Copied!
24
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Der I²C / TWI -bus

http://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/

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/

Gerätenummer

(4)

Schaltung TWI

mit 128 bit EEPROM und Temperatursensor DS1621

(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

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

(6)

Typische Bausteine

http://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 0 Bit 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…).

(10)

TWGCE General Call Enable (Broadcast: dev0x00, nur bei Slave belegt)

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

(11)

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

(12)

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 TWPS1

Vorteiler TWPS0

Bit Description

TWS7

Statusbits TWS6

TWS5 TWS4 TWS3 TWPS1

Vorteiler TWPS0

(13)

Implementation von P. Fleury

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);

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);

(14)

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.

(15)

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();

(16)

17

Schreiben von N Bytes ->24C02

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();

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 und kann deshalb entfallen

Versand eines Datenbytes

Geht so nur, wenn Startadresse 0 ist. Ansonsten muss die

Startadresse noch addiert werden!

(17)

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

(18)

TWI Atmega als slave

http://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

(19)

/*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;

(20)

// 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 // 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

(21)

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;

(22)

// 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)

(23)
(24)

Referenzen

ÄHNLICHE DOKUMENTE

mentiert werden, dass es niht in einen Deadlok geraten kann; wenn ja, wie; wenn nein,.

Seiko Epson does not assume any liability of any kind arising out of any inaccuracies contained in this material or due to its application or use in any product or circuit and,

Seiko Epson does not assume any liability of any kind arising out of any inaccuracies contained in this material or due to its application or use in any product or circuit and,

Input only : 12 bits (EXCL0 or EXCL1 is available by software) Output only : 30 bits (BZ, FOUT and TOUT are available by software) Bidirectional I/O : 26 bits (SRDY, SCLK, SIN and

Model No.Supply Voltage (V) Current Consumption Operating Standby (Halt) Clock frequency (Hz) Memory (bit) ROM RAMInputOutput Input/ Output Instructions I/O Port

SED1065 built in, SoundGenerator, SupplyVoltageDetection Watchdog, 10bit A/D Converter, HighSpeedOperation, no access to ext. 16bit timer) SoundGenerator, Display Memory, Clock

The specification of the OSC1 oscillation circuit can be selected from among four types: &#34;Crystal oscil- lation&#34;, &#34;CR oscillation&#34;, &#34;Crystal oscillation

OSC1: Stop, OSC3 = Stop, CPU, ROM, RAM: SLEEP status, Clock timer: Stop, Others: Stop status OSC1: Oscillating, OSC3 = Stop, CPU, ROM, RAM: HALT status, Clock timer: Operating,