4.2 Zbernica I²C na ESP32
Zbernice I²C v MicroPython
Klasický ESP32 má dve hardvérové zbernice I²C, ich identifikátorom (id) je číslo 0 a 1. Môžeme ich pripojiť cez objekt I2C z modulu machine:
from machine import I2C
i2c = I2C({id zbernice})
Predvolené GPIO sú:
- zbernica s id 0: SCL = 18, SDA = 19;
- zbernica s id 1: SCL = 25, SDA = 26.
Iné MCU môžu mať iný počet hardvérových zberníc I²C s inými predvolenými pinmi. Na ESP32 je však možné GPIO zmeniť pomocou parametrov, rovnako aj komunikačnú frekvenciu pre SCL:
i2c = I2C({id zbernice}, scl = {pin SCL}, sda = {pin SDA}, freq = {frekvencia})
Oficiálne podľa dokumentácie by sme konštruktoru mali posielať piny ako objekty typu Pin. V aktuálnej verzii MicroPython však funguje aj obyčajné číslo GPIO.
Predvolená frekvencia zbernice I²C je 400 kHz, uvádzané maximum je 5 MHz - záleží od MCU, aj od zariadenia. Nami používané I²C periférie spolupracujú s ESP32 do 1,25 MHz. V prípade ESP32-C3 je možné úspešne nastaviť maximálne 0,95 - 1,1 MHz.
Softvérovo riadená zbernica I²C
Ak potrebujeme využiť viac zberníc I²C, ako je k dispozícii na danom MCU, je možné využiť softvérové riadenie zbernice cez objekt SoftI2C, ktorému však neposielame id:
from machine import SoftI2C
i2c = SoftI2C(scl = {pin SCL}, sda = {pin SDA}, freq = {frekvencia})
Takéto softvérové riešenie je výrazne pomalšie (zaťažuje aj CPU), čo môže byť problém pri komunikácii s displejom alebo pamäťou. Pre senzory to však nepredstavuje žiadne obmedzenie.
Pull-up rezistory pre I²C
V predošlej kapitole sme si spomínali, že oba piny zbernice potrebujú pull-up rezistory. Väčšina rozširujúcich modulov periférnych zariadení má na plošnom spoji implementovaný pull-up rezistor, preto to obvykle nie je potrebné riešiť. Navyše MicroPython pri inicializácii objektu (na ESP32) zaktivuje interné pull-up rezistory pre príslušné GPIO.
Nemá teda žiadny zmysel riešiť pull-up rezistory pri I²C?
To záleží od okolností. Niektoré MCU nemajú interné pull rezistory, tak ich je nutné pridať externe.
ESP32 má interné pull rezistory, no sú pomerne „slabé“ - ich odpor je dosť vysoký, typicky okolo 45 kΩ. Pre krátke káble a bežné nízke frekvencie to postačuje. Pokiaľ by sme však chceli pripojiť zariadenie (displej) na frekvencii okolo 1 MHz, zväčší sa vplyv kapacity samotného vodiča a cez interný pull-up rezistor nemusí pretiecť dostatočný prúd na zmenu logickej hodnoty včas.
Vyvedené I²C zbernice zo zariadení
Na nami používaných mikrokontroléroch je zapojenie nasledovné:
- M5StickC Plus (aj vo verzii 2) využíva 3 zbernice I²C, prvé dve sú v našom firmvéri už pripravené v podobe objektov:
- GROVE konektor je pripojený na GPIO 33 (SCL) a 32 (SDA), objekt
M5Stick.i2c_grove- prepojený cez hardvérovú zbernicu s id 1; - vnútorné zariadenia I²C sú pripojené na GPIO 22 (SCL) a 21 (SDA), objekt
M5Stick.i2c- riadený softvérovo; - moduly HAT s I²C (to však nie sú všetky) používajú GPIO 26 (SCL) a 0 (SDA).
- GROVE konektor je pripojený na GPIO 33 (SCL) a 32 (SDA), objekt
- Senzory s I²C zo sady D1 Mini kit majú SCL pripojený k D1 a SDA k D2, čo konkrétne znamená:
- na ESP32 D1 Mini GPIO 22 a 21,
- na ESP32-C3 D1 Mini GPIO 19 a 18.
Práca s I²C v MicroPython
Po inicializovaní zbernice I²C obvykle najskôr zisťujeme, aké zariadenia sú pripojené. Pre detekciu pripojených zariadení slúži objektová funkcia scan() - nemá žiadne parametre a vracia zoznam adries nájdených zariadení.
from machine import I2C, Pin
import M5Stick
print("Interná zbernica I²C:", M5Stick.i2c)
zoznam = M5Stick.i2c.scan()
print("- nájdené zariadenia:", len(zoznam))
for adresa in zoznam:
print(" »", hex(adresa))
print()
print("GROVE zbernica I²C:", M5Stick.i2c_grove)
zoznam = M5Stick.i2c_grove.scan()
print("- nájdené zariadenia:", len(zoznam))
for adresa in zoznam:
print(" »", hex(adresa))
print()
i2c = I2C(0, scl = Pin(26), sda = Pin(0))
print("HAT zbernica I²C:", i2c)
zoznam = i2c.scan()
print("- nájdené zariadenia:", len(zoznam))
for adresa in zoznam:
print(" »", hex(adresa))
Typickým je blok programu, ktorý najskôr zistí, či je očakávané zariadenie prítomné na zbernici a ak je, až vtedy začne s ním pracovať, napríklad:
from machine import SoftI2C, Pin, Signal
i2c = SoftI2C(scl = Pin(26), sda = Pin(0))
if 0x23 in i2c.scan():
import knižnica
# práca so senzorom
else:
print("Nie je pripojený správny senzor!")
Treba však myslieť aj na to, že zariadenie môže byť odpojené aj počas prevádzky, napríklad z dôvodu zlého kontaktu. Pri jeho používaní je veľmi vhodné ošetriť tento stav zachytávaním výnimiek.
Softvérové riešenie napájania
Pripomeňme si, že senzory a ďalšie periférne zariadenia s I²C majú typicky 4 piny, ktoré musíme prepojiť s MCU - dva sú napájacie a dva slúžia na komunikáciu cez zbernicu. Ako v MicroPython nastaviť komunikačné GPIO samotnej zbernice, sme si už ukázali.
No i napájanie môžeme riešiť softvérovo - niektoré zariadenia nepotrebujú nepretržité napájanie a napríklad senzor stačí zapnúť až pred meraním a vypnúť ho po skončení merania. Ak pripojíme napájacie vodiče senzora (VCC aj GND) na dva bežné GPIO piny, v pokojovom stave na oboch nastavíme logickú hodnotu 0 (aby netiekol prúd, čím ušetríme energiu). Pred meraním jednoducho prepneme pin, ktorý slúži ako VCC, na logickú 1 (3,3 V), čím senzor dočasne oživíme. Pozor, vždy po zapnutí napájania musíme opäť inicializovať zbernicu a zariadenie!
Týmto spôsobom môžeme napájať len také zariadenia, ktorých odber neprekročí maximálny prúd! (pozri kapitolu 2.4 Porty GPIO) Môžeme tiež využiť obmedzovač prúdu, no pri prílišnom obmedzení nemusí zariadenie správne fungovať. Vo všeobecnosti možno očakávať, že bežné senzory nebudú mať žiadny problém, displej však takto zrejme fungovať nebude.