Lolin D32 pro mit SD_MMC, PN5180, max. fünf Buttons und Port-Expander (SMD)

Mir ist vor ein paar Tagen mit diesem PCB noch ein kleines Problem aufgefallen, das mir bisher so nicht bekannt war. Und zwar gibt es ja den Pin HP_DETECT, der erkennt, ob eine Kopfhörerplatine angeschlossen und in deren Buchse ein Klinkenstecker eingesteckt ist. Ist kein Stecker eingesteckt, so wird HP_DETECT dauerhaft über einen 10k-Pullup-Widerstand, der auf der Kopfhörerplatine sitzt, auf 3.3 V „gezogen“. Umgekehrt wird er auf GND gezogen, wenn ein Stecker eingesteckt ist. Bei allen PCBs, die ich zuvor gemacht habe, war HP_DETECT an einen eigenen GPIO angeschlossen, hier jedoch am Port-Expander. Der Port-Expander besitzt 16 I/Os und bei allen Anschlüssen, die als Input konfiguriert sind (per Default sind das alle - man muss Outputs explizit in Software konfigurieren), überwacht er kontinuierlich, ob sich ein Signalzustand ändert. Ist das der Fall, so wirft er einen Interrupt, den der ESP32 registriert. Über diesen Mechanismus weckt man den ESP32 aus dem Deepsleep auch auf.

Problem:
Geht der ESP32 in den Deepsleep, so schaltet die Mosfet-Schaltung u.a. an der Kopfhörerplatine die 3.3 V weg. Aufgrund verschiedener Querströme, die es dann noch gibt, ist die 3.3 V-Schiene dann jedoch nicht spannungslos, sondern pendelt sich so bei 0.7 / 0.8 V etwa ein. Ist nun kein Klinkenstecker eingesteckt, wenn der ESP32 in Deepsleep gehen soll, so erzeugt dieser Vorgang offenbar kurzzeitig ein Floating, das dazu führt, dass der Port-Expander einen Interrupt wirft und der ESP32 sofort wieder aufwacht. Blöd.

Weiterhin:

  • Ist ein Stecker eingesteckt, so gibt es dieses Problem nicht. Weil dann wird HP_DETECT stabil auf GND gezogen.
  • Ist ein Stecker eingesteckt und er wird im Deepsleep ausgesteckt, so wacht der ESP32 nicht auf. Das ist auch der Grund, weswegen ich „kurzzeitiges Floating“ oben geschrieben habe.
  • Interessanterweise scheint das Problem beim PCA9555 (von NXP) nicht aufzutreten, während das aber beim PD9555 der Fall ist. Ich habe meine Port-Expander immer beim gleichen Händler bestellt und zuerst PCA9555 erhalten, zuletzt jedoch PD9555. Die scheinen sich an dem Punkt offenbar einen „Tick“ zu unterscheiden.

Gar nicht so einfach…
Auf meiner Kopfhörerplatine gibt es den Widerstand R17, den ich bisher unbestückt gelassen habe. Lötet man hier einen 10k-Widerstand ein, so ist das Problem weg. Ich kann den R17 jedoch in die Kopfhörerplatine nicht einfach immer einlöten, weil wenn jemand die Kopfhörerplatine ohne ein Board mit Port-Expander verwendet, so würde dieser 10k-Widerstand MAX98357a.SD auf GND ziehen und es käme kein Ton mehr aus dem Lautsprecher. Umgekehrt tritt der Fehler bei solchen Boards aber auch gar nicht auf, so dass man den R17 hier ohnehin nicht benötigt. Man muss also abwägen, welcher Fall vorliegt.

Fix:

  • Im Bereich des IDC-Konnektors kann man zwischen zwei Pins extern einen 10k-Widerstand löten. Verwendet man die die Kopfhörerplatine auf Basis des PCM5102 so ist dies sogar notwendig, weil man das Problem nicht anders in den Griff kriegt (da gibt es keinen „R17“).
  • Verwendet man die Kopfhörerplatine auf Basis des UDA1334, so kann man sich aussuchen, ob man den Widerstand R17 einlötet oder ob man einen Widerstand unten an den IDC-Konnektor lötet. Problem mit dem R17 ist so ein bisschen, dass er zwischen dem IDC-Konnektor und der Kopfhörerbuchse liegt und man da ohne Auslöten der IDC-Buchse nicht wirklich drankommt. Ja, mit heißer Luft schon, aber dann schmilzt der IDC-Konnektor weg.
  • Für künftige Revisionen für PCBs für den Lolin D32 pro werde ich direkt auf dem PCB einen Widerstand vorsehen, der im Bereich des IDC-Konnektors liegt. Ist dieser eingelötet, so braucht’s keinen R17 mehr und man kann die Kopfhörerplatine universal verwenden.

Edit: Wie in den nachfolgenden Beiträgen beschrieben, führt 10k anderweitig zu Problemen. Ich bin jetzt letztlich doch wieder bei der Variante ohne R17 gelandet und habe es in Software gelöst, indem ich den Pin am Port-Expander kurz vor dem Shutdown auf Output schalte. Damit kann der „falsche“ Interrupt nicht mehr ausgelöst werden.