Langue: FR

ESP32 core 3.x - pinMode() peut casser votre bus SPI

Notes · Publié le

Ma carte SD avait besoin d’une résistance de tirage (pull-up) sur MISO. Beaucoup de modules SD n’en ont pas, et les cartes SD en ont besoin. L’ESP32 a des pull-ups internes, donc la ligne évidente après le démarrage du bus est celle-ci.

sdSpi.begin(PIN_SD_SCLK, PIN_SD_MISO, PIN_SD_MOSI, PIN_SD_CS);
pinMode(PIN_SD_MISO, INPUT_PULLUP);   // don't do this in core 3.x

Dans l’Arduino core pour ESP32 version 3.x, cette ligne débranche MISO du bus SPI. L’ESP32 peut toujours envoyer à la carte, mais il n’entend plus ses réponses, donc SD.begin() échoue. Rien dans le code n’a l’air faux.

Pourquoi ça arrive

Le core 3.x a ajouté un « gestionnaire de périphériques » (peripheral manager). Il retient quel périphérique possède chaque broche (SPI, I2C, UART, PWM, etc.). Quand on appelle pinMode(), le core reprend la broche comme simple GPIO et la libère de ce qui la possédait avant. Pour la broche MISO du SPI, cette libération lance le code SPI qui détache MISO du bus. On le voit dans le code source du core, dans esp32-hal-gpio.c (pinMode() appelle perimanClearPinBus()) et esp32-hal-spi.c (spiDetachBus_MISO()).

C’est une bonne idée en général. Deux pilotes ne peuvent plus se disputer une broche par accident. Mais pinMode() devient « retirer cette broche à son périphérique », et pas seulement « mettre le pull-up ».

La solution

Activer le pull-up directement avec la fonction ESP-IDF, qui ne change que le pull-up et laisse la broche attachée au SPI. Elle est disponible dans tout sketch Arduino pour ESP32.

#include <driver/gpio.h>

sdSpi.begin(PIN_SD_SCLK, PIN_SD_MISO, PIN_SD_MOSI, PIN_SD_CS);
// Cards need MISO pulled up and many modules lack the resistor. Not pinMode():
// in core 3.x that would detach the pin from the SPI bus.
gpio_pullup_en((gpio_num_t)PIN_SD_MISO);

Appelez-la après begin(), pour que rien ne reconfigure la broche ensuite. C’est ce qui tourne dans ma visionneuse de photos sur ESP32.

Le pull-up interne est faible (environ 45 kΩ). Ça suffit pour une carte SD à 20 MHz avec des fils courts. Avec de longs fils ou des erreurs à haute vitesse, une résistance externe de 10 kΩ entre MISO et 3,3 V est plus fiable.

Le même piège ailleurs

La règle est la même pour toute broche qu’un périphérique possède, pas seulement le SPI.

  • N’appelez pas pinMode() sur les broches I2C, UART, SPI ou PWM après avoir démarré ce périphérique.
  • Pour changer seulement le pull-up ou le pull-down d’une telle broche, utilisez gpio_pullup_en(), gpio_pulldown_en() ou leurs versions _dis().
  • Si un périphérique cesse de marcher après une mise à jour du core, cherchez les pinMode() sur ses broches.

Liens

← Retour aux articles