Přepínač I2C sběrnice (multiplexer)

 

Nedávno jsem obdržel dotaz, jak by bylo možné přes I2C připojit k Raspberry Pi více obvodů se stejnou I2C adresou.

Normálním způsobem to samozřejmě možné není. Každé zařízení připojené na sběrnici musí mít unikátní I2C adresu.
Existují ale obvody, které dokáží I2C sběrnici přepínat.

Jedním z nich je například obvod PCA9516.
Perfektně se hodí pro práci s Raspberry Pi:
 - Je napájený pomocí 3,3V
 - komunikace s RasPi také probíhá na 3,3V napěťových úrovních
 - na straně u periférií je ale možné komunikační úrovně zvolit (5V, nebo 3,3V)
Typické připojení různých periférií (s různou rychlostí i různým napájecím napětím) je vidět na obrázku z katalogového listu.
Přepínání na požadovanou sběrnici se provádí pomocí 4 ovládacích pinů.
Když jsou piny v "0" je příslušná větev odpojená.


Tady je jednoduchý příklad, kterým jsem připojil k RasPi tři obvody ATtiny85 se stejnou I2C adresou.
Je to jen příklad. Místo ATtiny je možné použít třeba větší množství čítačů, RTC obvodů, tlakoměrů, měřičů osvětlení a dalších I2C obvodů, které mají jen omezený počet volitelných adres.

Schéma:


Program:

V obvodech ATtiny85 je mírně upravený ukázkový program z knihovny TinyWireS.zip.
Úprava spočívá v tom, že jsem zrušil blikání LED, které způsobovalo dlouhou pauzu mezi přijetím čísla a odesláním odpovědi.
V každém obvodu pak byla nastavena jiná hodnota, která se před odesláním přičítá k přijatému číslu:
 - první ATtiny odesílá přijatou hodnotu zvýšenou o 10
 - druhé ATtiny přičítá 20
 - a třetí ATtiny vrací o 30 větší hodnotu, než přijalo
V každém ATtiny byla nastavena stejná I2C adresa: 0x51

ATtiny_1.ino
ATtiny_2.ino
ATtiny_3.ino



Přepínání v Pythonu na Raspberry Pi vypadá třeba takhle (i2cswitch.py):

#!/usr/bin/env python

# Priklad ovladani I2C multiplexeru PCA9516
# Jako SLAVE zarizeni jsou pripojeny 3 kusy ATtiny85 s adresami 0x51
# V nich je pouzity mirne upraveny ukazkovy priklad z knihovny TinyWireS.zip  
# (Prvni ATtiny vraci cislo o 10 vetsi, nez prijme. Druhe ATtiny pricita 20, treti ATtiny pricita 30 )
# (Z ukazkoveho prikladu bylo odstraneno dlouhe blikani LEDkou, ktere signalovalo prijate cislo)  
#=========================================================================================================

import smbus
import RPi.GPIO as GPIO  
import time
import random


addr=0x51    # I2C adresa vsech zarizeni na sbernici je stejna (0x51)
bus = smbus.SMBus(1)


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(7, GPIO.OUT)     # pin pro zapnuti I2C_1
GPIO.setup(8, GPIO.OUT)     # pin pro zapnuti I2C_2
GPIO.setup(25, GPIO.OUT)    # pin pro zapnuti I2C_3




#---------------------------------------------------------
#  podprogram pro prepinani jednotlivych I2C kanalu
def prepni(kanal_I2C): 

  if (kanal_I2C == 1):
    GPIO.output(7, True)          # zvoleny kanal je True,  
    GPIO.output(8, False)         # ostatni (pokud obsahuji zarizeni se stejnou adresou) musi byt False
    GPIO.output(25, False)

  if (kanal_I2C == 2):
    GPIO.output(7, False) 
    GPIO.output(8, True)
    GPIO.output(25, False)

  if (kanal_I2C == 3):
    GPIO.output(7, False) 
    GPIO.output(8, False)
    GPIO.output(25, True)
    
#----------------------------------------------------------    



while (True):                           # nekonecna smycka

  for i in range (1,4):                 # vycitat se bude z kanalu I2C_1 az I2C_3

    prepni(i)                           # prepnuti na pozadovany I2C kanal
    nahoda = random.randint(0,9)        # generovani nahodneho cisla od 0 do 9

    bus.write_byte(addr,nahoda)         # do arizeni na zvolenem I2C kanale se posle nahodne cislo
    odpoved = bus.read_byte(addr)       # a precte se odpoved

    print (nahoda , odpoved)            # vypis vstupniho nahodneho cisla a odpovedi 

    time.sleep(1)                       # nejaky cas na dokonceni operace v pripojenych zarizenich 
                                        #  (pauzy u blikani LED zdrzuji dalsi komunikaci a tim zaplnuji buffer)  

Výsledek vypadá takto:

První číslo ne náhodně vygenerevané číslo od 0 do 9, druhé číslo je odpověď od příslušného ATtiny (přičteno 10, 20, nebo 30).

Ukázkové video na YouTube: