I2C-Multiplexer PCA9516


Prof. Jürgen Plate

I2C-Multiplexer PCA9516

Es gibt spezielle I2C-Bausteine, die nur über eine Adresse verfügen. Was tun, wenn man mehrere dieser Chips verwenden möchten? Eine Lösung dieses Problems stellt das IC PCA9516 dar, denn er kann den I2C-Bus multiplexen. Die I2C-Bus-Hubs (Repeater) PCA9515 und PCA9516 dienen dazu, die Verbindung von I2C-Bussen zu ermöglichen, ohne die kapazitive Last eines Busses zum anderen Bus zu übertragen. Im Datenblatt des PC9516 wird angegeben, dass es sich um einen 5-Kanal-Hub handelt. Da ein Kanal der Master (Anschluss des Rechners) ist, schaltet der Multiplexer den Master-Bus auf vier unabhängige Slave-Busse durch.

Eine Adresse, die auf dem Master-Bus schon belegt ist, steht auf den Slave-Bussen logischerweise nicht mehr bereit. In der Praxis macht so der PCA9516 eine Adresse nur je einmal an jedem der vier Slave-Busse des PCA9516 verfügbar. Das folgende Bild zeigt das Blockdiagramm aus dem Datenblatt:

Die als "Buffer" bezeichneten Blöcke sind nichts weiter als bidirektionale Verstärker, der so ausgelegt ist, dass ein "lock-up" verhindert wird.

Die Eigenschaften des Bausteins können sich sehen lassen:

Der PCA9516 wird wahlweise in einem S016- oder in einem TSSOP16-Gehäuse geliefert, wobei das SO16-Gehäuse das Auflöten des Chips leichter macht.

Die Pinbelegung ist:

SymbolPinDescription
SCL01 serial clock bus 0
SDA0 2 serial data bus 0
SCL1 3 serial clock bus 1
SDA1 4 serial data bus 1
EN1 5 active HIGH bus 1 enable input
SCL2 6 serial clock bus 2
SDA2 7 serial data bus 2
GND 8 supply ground
EN2 9 active HIGH bus 2 enable input
SCL3 10 serial clock bus 3
SDA3 11 serial data bus 3
EN3 12 active HIGH bus 3 enable input
SCL4 13 serial clock bus 4
SDA4 14 serial data bus 4
EN4 15 active HIGH bus 4 enable input
VCC 16 supply power

Eine typische Anwendung ist schematisch im Bild unten gezeigt. In diesem Beispiel hat der System-Master einen 3,3-V-I2C-Bus, während einige Slaves einen 5-V-Bus besitzen. Alle Busse arbeiten mit 100 kHz solange Slave 3 aktiviert ist. Ist Slave 3 abgeschaltet, können der Master-Bus und Slave 1 und Slave 2 mit 400 kHz laufen. Jedes Segment des Hub kann mit jedem anderen Segment des Hub kommunizieren. Unbenutzte Ports sollten durch Ziehen des jeweiligen Enable-Pins (ENn) auf GND-Potential isoliert werden. Die Leitungen SDAx und SCLx müssen bei jedem Port die entsprechenden Pull-Up-Widerstände nach Vcc haben. Der primäre Bus-Master ist normalerweise an SDA0/SCL0 angeschlossen. Werden diese beiden Ports nicht verwendet, müssen die Anschlusspins trotzdem durch entsprechend dimensionierten Widerstände auf Vcc gezogen werden. Die PCA9516A ist 5,5-V-tolerant, so ist keine zusätzliche Schaltung erforderlich, um zwischen den verschiedenen Bus-Spannungen umzusetzen. Wird eine Seite des PCA9516A von einem Gerät auf dem I2C-Bus auf LOW gezogen, erkennt ein CMOS-Hysterese-Eingang die fallende Flanke und bewirkt, dass der interne Treiber auf der anderen Seite eingeschaltet wird, damit die andere Seite auch auf LOW gehen kann.

Das folgende Bild zeigt eine Applikationsschaltung, wobei hier alle Ports an 3,3 V angeschlossen sind. Es ist jedoch möglich, auch Peripherie mit 5 V Versorgungsspannung anzuschliessen. Es muss dann lediglich der Pin 1 des entsprechenden Jumpers (JP2 bis JP5) und der zugehörige Pull-Up-Widerstand (R11 bis R14) an die 5-V-Versorgung angeschlosenn werden anstatt an 3,3 V. JP1 wird an digitale GPIO-Ausgänge des Raspberry Pi angeschlossen, die dann den jeweiligen Kanal zwischen SDA0/SCL0 und SDAx/SCLx freischalten. Per Default werden diese Leitungen durch R7 bis R10 auf LOW-Pegel gezogen.

Das folgende Python-Programm scannt den I2C-Bus 1 auf angeschlossene Devices. Dabei wird zuerst der Bus selbst untersucht und dann alle alle Möglichkeiten, Devices über den Multiplexer zu finden. Dazu wird jeweils eine Enable-Leitung auf HIGH gesetzt und dann auf aktive I2C-Bausteine gescannt. Damit kann man auch erkennen, ob eine mit dem PCA9516 bestückte Platine wie gewünscht funktioniert.

#!/usr/bin/env python
#
# ======================================================================
# i2cmdetect.py
#
# Program to detect I2C slaves that are attached directly to bus 1
# but also checks for slaves attached to a multiplexer (PCA 9516).
# CH1 = GPIO4, CH2 = GPIO17, CH3 = GPIO27, CH4 = GPIO22
#
# (C) Thomas Baumann 2014, JPL 2016
# ======================================================================
#
import sys
import time
import os
import smbus

# Import GPIO module
try:
    import RPi.GPIO as GPIO
except RuntimeError:
    print("Error importing RPi.GPIO!")
    print("This is probably because you need superuser privileges. ")
except:
    print("Error importing RPi.GPIO!")
    print("Unexpected error: ", sys.exc_info()[0])
# end try

# Initialize GPIO
CH1 = 4
CH2 = 17
CH3 = 27
CH4 = 22
GPIO.setmode(GPIO.BCM)     # use chip numbers
GPIO.setwarnings(False)    # suppress already in use warnings
GPIO.setup(CH1, GPIO.OUT)  # CH1 enable
GPIO.setup(CH2, GPIO.OUT)  # CH2 enable
GPIO.setup(CH3, GPIO.OUT)  # CH3 enable
GPIO.setup(CH4, GPIO.OUT)  # CH4 enable

# Scanning routine
def PerformScan(I2C):
    Found = False
    for i in range(0x03, 0x78):
        try:
            I2C.write_quick(i)
            print("Device found at " + hex(i).upper().replace("X", "x"))
            Found = True
        except:
            pass
        #end try
    #next
    if Found == False:
        print("  no device found.")
    #end if

#end def

try:
    # Open I2C Bus
    I2C = smbus.SMBus(1)
    # Loop through multiplexer
    for i in range(0, 5):
        if i == 0:    # direct bus scan
            GPIO.output(CH1, False)
            GPIO.output(CH2, False)
            GPIO.output(CH3, False)
            GPIO.output(CH4, False)
            print("Scanning bus directly ...")
            PerformScan(I2C)
        elif i == 1:  # scan bus on channel 1
            GPIO.output(CH1, True)
            GPIO.output(CH2, False)
            GPIO.output(CH3, False)
            GPIO.output(CH4, False)
            print("Scanning bus channel " + str(i) + " ...")
            PerformScan(I2C)
        elif i == 2:  # scan bus on channel 2
            GPIO.output(CH1, False)
            GPIO.output(CH2, True)
            GPIO.output(CH3, False)
            GPIO.output(CH4, False)
            print("Scanning bus channel " + str(i) + " ...")
            PerformScan(I2C)
        elif i == 3:  # scan bus on channel 3
            GPIO.output(CH1, False)
            GPIO.output(CH2, False)
            GPIO.output(CH3, True)
            GPIO.output(CH4, False)
            print("Scanning bus channel " + str(i) + " ...")
            PerformScan(I2C)
        elif i == 4:  # scan bus on channel 4
            GPIO.output(CH1, False)
            GPIO.output(CH2, False)
            GPIO.output(CH3, False)
            GPIO.output(CH4, True)
            print("Scanning bus channel " + str(i) + " ...")
            PerformScan(I2C)
        #end if
    #next
    print("Done ...")
except:
    print("Can't access bus 1")
#end try

Copyright © Hochschule München, FK 04, Prof. Jürgen Plate
Letzte Aktualisierung: , Webseite: