Homepage Wiki Forum Buy

I2C

Aus GNUBLIN

Schwierigkeitsgrad Voraussetzung Gnublin Familie
Gnublin logo advanced.png I2C Wissen, Anschluss Bauteil an Schnittstelle Alle

Inhaltsverzeichnis


I2C [1] ist ein klassischer Mikrocontroller Bus. Mit zwei Drähten kann man bis zu 128 Teilnehmer adressieren. GNUBLIN bietet eine I2C Schnittstelle für die Ansteuerung von Perihperie oder externen Bausteinen an.

Gnublin board spi1.jpg

Gnublin board spi new.png


Belegung:


  • 9 - I2C_SDA1
  • 10 - I2C_SCL1


Anfänger

Ansteuerungs Beispiel mit den i2c-tools

Die I2C Tools sind ein hilfreiches Werkzeug, wenn man Daten selbst schnell über den Bus senden will. Dabei kann man Daten senden,empfangen und den Bus nach möglichen Teilnehmer Adressen abfragen.

Senden:

i2cset <I2CINTERFACE> <SLAVEADRESSE> <REGISTERADRESSE> <DATEN>
  • I2CINTERFACE //Bestimmt welches dev file benutzt wird (z.B. i2c-1 = 1)
  • SLAVEADRESSE //Slave Adresse
  • REGISTERADRESSE //Meist eine Adresse im Adressraum des Slave (dieser Besitzt ja auch Register mit Adressen)
  • DATEN //Daten, die an den Slave gesendet werden.

Beispiele:

root@gnublin-debian:~# i2cset 1 0x20 0x07 0x00
root@gnublin-debian:~# i2cset -y 1 0x20 0x03 0x00

Empfangen:

i2cget <I2CINTERFACE> <SLAVEADRESSE> <REGISTERADRESSE> <MODUS>
  • I2CINTERFACE //Bestimmt welches dev file benutzt wird (z.B. i2c-1 = 1)
  • SLAVEADRESSE //Slave Adresse
  • REGISTERADRESSE //Meist eine Adresse im Adressraum des Slave (dieser Besitzt ja auch Register mit Adressen)
  • MODUS //Gibt an ob ein Byte b oder ein Wort w gelesen werden soll

Beispiele:

root@gnublin:~# i2cget 1 0x49 0x00 b
root@gnublin:~# i2cget 1 0x49 0x00 w

Teilnehmer Adressen herausfinden:

Im folgendem Beispiel wurden vier LM75 Temperatur Sensoren angeschlossen und dann der Bus abgescannt.

root@gnublin:~# i2cdetect 1 WARNING! This program can confuse your I2C bus, cause data loss and worse! I will probe file /dev/i2c-1. I will probe address range 0x03-0x77. Continue? [Y/n] y x 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- 49 4a 4b 4c -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 6e -- 70: -- -- -- -- -- -- -- --

Wie man nun sehen kann werden auf dem BUS 5 Geräte erkannt:0x49-0x4c und 0x6e. Die Adresse 0x6e ist die eigene Slave-Adresse des I2C Controllers. Der Betrieb als Slave wird vom Treiber aber nicht unterstützt.

Hinweis: Der Kernel erzeugt bei älteren Versionen des I2C-Treiber Timeoutmeldungen auf der Standardausgabe (Auf dem Gnublin die serielle Konsole). Diese können ignoriert werden.

Für Fortgeschrittene

Für Fortgeschrittene wäre es nun an der Zeit mal ein eigenes kleines Programm in C zu schreiben um auf die I²C Schnittstelle zuzugreifen.

Ansteuerungs Beispiel in C

Das folgende Beispiel ist im Ordner /root/examples/misc/pca9555/i2c-test zu finden. Es ist auch schon vorkompiliert und kann gleich gestartet werden.


  
#include <stdio.h> 
#include <fcntl.h> 
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define ADDR 0x20   //<----Adresse des Slaves 

int main (int argc, char **argv) { 

    int fd; 
    char filename[32]; 
    char buffer[128]; 
    int n, err; 

    if (argc == 0) {
        printf("usage: %s <device>\n", argv[0]);
		    exit(1);
		}

    sprintf(filename, argv[1]); 
    printf("device = %s\n", filename);

    int slave_address = ADDR; 

    if ((fd = open(filename, O_RDWR)) < 0) { 
        printf("i2c open error"); 
        return -1; 
    } 
    printf("i2c device = %d\n", fd);

    //<----Vorbereiten des I2C Slaves
    if (ioctl(fd, I2C_SLAVE, slave_address) < 0) {
        printf("ioctl I2C_SLAVE error"); 
        return -1; 
    } 

    /* slave address is not in buffer */
    buffer[0] = 0x06;  /* command byte: write config regs */ 
    buffer[1] = 0x00;  /* port0 all outputs */
    err = write(fd, buffer, 2);					
    //<---- Weitergabe der zu sendenden Daten an den Controller Treiber
    if (err != 2) { 
        printf("write: error %d\n", err); 
        return -1; 
    } 
    /* slave address is not in buffer */
    buffer[0] = 0x07;  /* command byte: write config regs */ 
    buffer[1] = 0x00;  /* port1 all outputs */
    err = write(fd, buffer, 2);					
    //<---- Weitergabe der zu sendenden Daten an den Controller Treiber
    if (err != 2) { 
        printf("write: error %d\n", err); 
        return -1; 
    } 

    n = 0;
    while (1) {
			buffer[0] = 0x03;  /* command byte: write output regs */ 
			buffer[1] = 0x01;  /* port1 data  */
                        //<---- Weitergabe der zu sendenden Daten an den Controller Treiber
			if (write(fd, buffer, 2) != 2)  
			    {
			    printf("write error 0"); 
			    return -1; 
			    } 
      usleep(100000);
			buffer[0] = 0x03;  /* command byte: write output regs */ 
			buffer[1] = 0xff;  /* port1 data  */
                        //<---- Weitergabe der zu sendenden Daten an den Controller Treiber
			if (write(fd, buffer, 2) != 2)
			    {
			    printf("write error 1"); 
			    return -1; 
			    } 
      printf("%d\n", n++);
      usleep(100000);
    }
}

Dieses Programm kann man nun mit

gcc "c-Dateiname" -o Programmname

kompilieren und mit :

./Programmname

ausführen.

Wenn man den PCA9555 Baustein angeschlossen hat dann sollte eine LED an irgend einem Pin des Port0 vom PCA9555 blinken.

Oder sollte man ein Oszi angeschlossen haben, so sollte man folgende Ausgabe sehen:

Tek-i2c.jpg

Oben ist das Clock Signal SCL, unten das Datensignal SDA. Man sieht schön das Startbit, die Adresse 0x20, das Acknowledge Bit und das Stopbit.

Achtung: Bei der I2C Busadresse des PCA9555 muss man aufpassen. Im ersten Byte auf dem Bus ist die Slave Adresse nur 7 Bit gross (Bit 7 bis Bit1). Das nullte Bit ist das R/notW bit. Bei der Slave Adresse im Linux Anwendungsprogramm nimmt man nur die Bits 7 bis 1. Der PCA9555 mit allen drei Adress Bits A2, A2 und A0 gleich 0 hat daher die Slave Adresse 0x20.


Mögliche Fehler

Wird folgender Fehler im dmesg ausgegeben:

i2c i2c-1: LPC313x-I2C1: Bus is still active after xfer. Reset it...
i2c i2c-1: LPC313x-I2C1: Bus busy. Slave addr = 7f, cntrl = 0, stat = 2a60

kann eine mögliche Ursache sein, dass mehere I2C Module an den Bus angschlossen sind und mehr als 1x die PullUp Widerstände-Jumper gesteckt sind.

In anderen Sprachen