Grundlagen
Gegenüber dem ESP8266 besitzt der ESP32 erheblich mehr GPIOs. Aber bei einem großen Projekt wie ESPuino können auch diese knapp werden. Hinzu kommen verschiedene ESP32-Limitierungen:
- GPIO 0 und 2 dĂĽrfen nicht beliebig beschaltet werden, da sie fĂĽr den Boot/Flashvorgang besondere Aufgaben haben.
- GPIO 34, 35, 36 und 39 sind streng genommen keine GPIOs sondern GPIs. D.h. man kann sie nur als Input-Kanäle verwenden und man hat bei ihnen auch keine Möglichkeit, interne Pullup-Widerstände zuzuschalten.
- Im Falle eines ESP32-WROVERs hat man zwar PSRAM zur VerfĂĽgung, erkauft sich dies jedoch mit zwei fehlenden GPIOs: 16 und 17.
Nun ist das Thema bei Mikrocontrollern nicht neu und es gibt dafür eine Lösung: Port-Expander. Das sind ICs, die mit dem Bus-Protokoll I2C an den ESP32 angeschlossen werden und ihrerseits dann weitere Ein- und Ausgänge bereitstellen. Im Folgenden geht es ausschließlich um den Port-Expander PCA9555. Dieser stellt zwei Ports bereit, die jeweils aus acht Channels (Pins) bestehen. Diese können unabhängig voneinander als Eingänge oder Ausgänge konfiguriert werden. Hinweis: Ein solcher Port-Expander gehört bei ESPuino gewissermaßen zur Grundausstattung und wird z.B. bei ESPuino-mini 4Layer verwendet.
Eingänge
Der PCA9555 stellt zwei Ports (0 und 1) mit jeweils acht Pins (0 bis 7) zur VerfĂĽgung.
ESPuino-Interna: Per Default sind beide Ports mit allen Channels im „Input-Modus“, so dass man hier per I2C keine zusätzliche Register-Parametrierung vornehmen muss, sofern ein Ausgang nicht notwendig ist. Die Abfrage der Input-Kanäle erfolgt über die Register 0 und 1. Ein Port mit acht Channels wird immer durch 8 Bit repräsentiert.
Ausgänge
Aktuell sind beim ESPuino nur drei Ausgangstypen vorgesehen. Und zwar GPIO_PA_EN
, GPIO_HP_EN
und Power
. D.h. man kann den Port-Expander nutzen, um die Verstärker für Lautsprecher und Kopfhörer zu aktivieren/deaktivieren. Und man kann ihn nutzen, um eine Mosfet-Schaltung anzusteuern.
ESPuino-Interna #1: Nachdem es beim Übergang in den Deepsleep Probleme gab, dass der ESP32 wieder aufgewacht ist, da es auf HP_DETECT durch die Spannungsabschaltung eine Signaländerung gibt (löst einen Interrupt aus), wird auch dieser Eingang kurz vor dem Shutdown als Ausgang umgeschaltet. Grund ist hier aber nur, dass ein Pin, der als Ausgang konfiguriert ist, keinen Interrupt werfen kann und somit der ESP32 fälschlicherweise nicht wieder aufwacht.
ESPuino-Interna #2: Soll ein Pin als Ausgang konfiguriert werden, so muss die Bitmaske im Register 6 bzw. 7 angepasst werden. D.h. per Default steht die Bitmaske eines Ports auf 255; jedes Bit, das gesetzt ist, ist ein Input-Kanal. Will man IO0_1 (siehe Bild) als Ausgang konfigurieren, so muss 253 gesetzt werden, weil das zugehörige Bit auf 0 gesetzt wird. Das Setzen der Ausgänge (high oder low) erfolgt im Anschluss über die Register 2 und 3.
Adresse
Über die Eingänge A0, A1 und A2 steuert man die I2C-Adresse des PCA9555. Beispiel: Legt man alle drei auf GND, so lautet sie 0x20
.
Weitere Beschaltung
VDD: 3.3V
VSS: GND
PullUp-Widerstände (4.7 k) für SCL, SDA und INT (für INT reichen auch 10k).
Interrupt
Es gibt verschiedene Möglichkeiten, einen Port-Expander auszulesen. ESPuino tut dies entweder zyklisch oder über einen Interrupt. Der Interrupt hat den Vorteil, dass man hierüber den ESPuino auch aufwecken kann und es zeitsparender ist, als die Input-Register ständig zu pollen. Möchte man den ESPuino via Interrupt aufwecken, so muss WAKEUP_BUTTON
auf den ESP32-GPIO konfiguriert werden, an dem der Interrupt-Pin des PCA9555 angeschlossen ist (PE_INTERRUPT_PIN
). Hinweis: Das Feuern des Interrupts (und damit das Aufwecken) lässt sich nicht auf einzelne Eingänge des PCA9555 limitieren! D.h. jede Änderung an einem Eingang des PCA9555 resultiert in einem Interrupt, was im Gegenzug den ESP32 aufweckt.
Was kann alles am Port-Expander angeschlossen werden?
Alles, was ein Schalter ist:
- Eingang: Taster
- Eingang: Erkennung, ob Kopfhörer eingesteckt
- Eingang: Taster des Drehencoders (nicht jedoch CLK und DT; dies unterstĂĽtzt die verwendete Lib nicht (Stand 02/2022)
- Eingang: RFID: PN5180.IRQ
- Ausgang: Aktivierung/Deaktivierung des Verstärkers für den Lautsprecher (
GPIO_PA_EN
) - Ausgang: Aktivierung/Deaktivierung des Verstärkers für den Kopfhörer (
GPIO_HP_EN
) - Ausgang: Ansteuerung der Mosfet-Schaltung (
POWER
)
Können am gleichen I2C-Bus weitere Slaves angeschlossen werden?
Aber natĂĽrlich. Dies ist in Form von RFID_READER_TYPE_MFRC522_I2C
auch jetzt bereits möglich: Hierbei wird ein RC522 (dafür ist eine spezielle RC522-Platine notwendig, da die Standard-Platine nur SPI unterstützt!) per I2C angebunden. Technisch möglich wäre z.B. auch, dass man ein Display anschließt. Dies wird aktuell von ESPuino jedoch nicht unterstützt. In jedem Fall ist darauf zu achten, dass jeder Slave eine eindeutige Adresse besitzt.
Können am gleichen I2C-Bus mehrere PCA9555 angeschlossen werden?
Technisch ja, aber ESPuino unterstützt dies nicht. 16 zusätzlich Ein- und Ausgänge werden hoffentlich reichen, oder?
Werden andere Port-Expander-Typen als PCA9555 unterstĂĽtzt?
Nein. Das führt vom Testaufwand einfach zu weit…
Lassen sich Taster auf GPIOs und Port-Expander mischen?
Ja. FĂĽr GPIOs stehen weiterhin 0 bis 39 und fĂĽr den Port-Expander 100 bis 115 bereit. D.h. man kann z.B. NEXT_BUTTON
auf 14 legen, während man PREVIOUS_BUTTON
auf 103 legt. Und so weiter…
Alle Buttons wecken den ESPuino auf. Kann man das auch einschränken, so dass z.B. nur ein einzelner Button zum Aufwecken benutzt werden kann?
Mit einem Workaround ist dies möglich: Aufwecken nur über Drehencoder.
Wie wird der Port-Expander in ESPuino konfiguriert?
Allgemein:
settings.h
:
PORT_EXPANDER_ENABLE
aktivieren.expanderI2cAddress
festgelegen. Dies ist die Adresse des PCA9555 am I2C-Bus (siehe weiter oben unter Adresse).
Spezifisch:
settings-<develboard>.h
:
ext_IIC_CLK
undext_IIC_DATA
festlegen. Dies sind die GPIOs für den I2C-Bus (SCL und SDA).- Taster, die am PCA9555 hängen, können nun mit den Zahlen 100 bis 115 angesteuert werden. Hierbei ist: Port 0 / Eingang 0 => 100 … Port 0 / Eingang 7 => 107. Und: Port 1 / Eingang 0 => 108 … Port 1 / Eingang 7 => 115.
- (optional)
PE_INTERRUPT_PIN
festlegen. Dies ist der GPIO, ĂĽber den die Interrupts des PCA9555 empfangen werden. Ich empfehle eindringlich, diesen zu benutzen, da das Pollen auf dem Expander nicht fĂĽrchterlich schnell ist. Und nicht vergessen, dass ein externer PullUp-Widerstand notwendig ist, wenn der GPIO >=34 ist.
Löten:
Gibt es in verschiedenen SMD-Größen. Ich habe meine als TSSOP24 bestellt und zum Testen auf eine entsprechende Adapterplatine gelötet. Bisschen größer ist SOP24. Und wer gar nicht SMD-Löten mag, für den gibt es auch noch DIP24: PCA9555N Product Information|NXP und PCA9555N NXP 16bit I2C/SMBus I/O ports DIP24 NEW [3 pcs] #BP | eBay
Adapterplatinen: https://www.ebay.de/itm/10PCS-SOP24-SSOP24-TSSOP24-1mm-to-DIP24-2-54mm-PCB-Adapter-Converter-Plate/152761240660