ESP32-C3 Réaffecter pins SPI I2C

Bonjour,

Pour ne pas avoir de croisement de pistes sur un CI (je suis un vieux : CI=circuit imprimé :grinning_face:) je souhaite réaffecter les pins du SPI et de l'I2C sur un ESP32-C3, carte super mini.

Quand on n'utilise pas de bibliothèque, c'est simple, on est libre de faire comme on veut.
Quand les bibliothèques se permettent d'activer elles-mêmes le SPI ou l'I2C sans laisser le choix à l'utilisateur, comment fait-on ?

Par défaut les pins sont définies dans le fichier "pins_arduino.h", c'est le cas avec platformio, je serais surpris qu'avec l'IDE arduino ce soit différent.

J'ai commencé par chercher comment il serait possible d'imposer l'usage d'un fichier "pins_arduino.h" particulier par projet.
C'est la solution qui me paraissait la plus propre.

Je n'ai rien trouvé, j'ai même consulté cinq IAs (oui, oui c'est possible :grinning_face:).
Ce qui est fort ennuyeux, c'est qu'avec strictement la même question, j'ai eu 5 solutions différentes, certaines contradictoires, et que je n'ai pas réussi à en faire fonctionner une seule.

Quand je regarde le contenu du fichier "pins_arduino.h", je me dis, peut-être que c'est une bêtise, que la déclaration en static + const ne facilite pas les choses.

static const uint8_t SDA = 8;
static const uint8_t SCL = 9;

static const uint8_t SS = 7;
static const uint8_t MOSI = 6;
static const uint8_t MISO = 5;
static const uint8_t SCK = 4;

Je précise que c'est plus pour le plaisir de réussir que par nécessité, ce ne sont pas deux croisements de pistes qui me bloquent.

Mais si quelqu'un a une solution "simple", je regarderai avec attention et grand intéret.
PS : "simple" = pas une solution comme Perplexity qui proposait de créer une nouvelle carte de A à Z à chaque fois qu'une pin est déplacée, sûr que cela devait fonctionner, mais à quel prix !
-----------------------------------------------------------------------------------------------------------
Il y a deux essais dont je souhaite vous parler.

  1. Premier essai avec un écran I2C
    écran oled I2C
    bibliothèque Adafruit SSD1306@^2.5.13 + Adafruit GFX

J'avais repèré dans la bibliothèque Adafruit, que l'initialisation de l' I2C est faite à l'intérieur de la méthode begin avec une ligne Wire.begin() sans argument, donc avec les valeurs de pins_arduino.h.

Je me dis : si j'ajoute une ligne Wire.begin(6 ,7 ) avant la ligne ecran.begin que va-t-il se passer ?
Note : dans "pins_arduino.h", 6 est Mosi et 7 est CS.

Dans setup() j'ai donc ces deux lignes :

Wire.begin(6 ,7 );
ecran.begin(SSD1306_SWITCHCAPVCC, 0x3C) ;

Je m'attendais à ce que le Wire.begin() sans argument de la bibliothèque Adafruit réinitialise l'I2C avec les valeurs de "pins_arduino.h" et annule ma ligne Wire.begin(6 ,7 );

Eh bien non, l'écran fonctionnait parfaitement.

  1. Même essais avec un écran SPI
    J'ai fait la même manip avec un écran SPI :
    SPI.begin(sck, miso, mosi, cs)
    GC9A01 (écran rond)
    Bibliothèque : diyables/DIYables TFT Round@^1.0.1 + adafruit Gfx

Cela n'a pas fonctionné.

Je ne peux que constater, je ne sais que dire.
Est-ce qu'il est possible de détecter une initialisation préalable ?
Certains auteurs sauraient le faire et d'autres non ?

Je rappelle que c'est surtout pour le plaisir de comprendre, je ne suis pas bloqué et accessoirement.....que j'ai pu faire des conneries.

Pour la librairie adafruit, si tu regardes Adafruit_SSD1306.h

  Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi = &Wire,
                   int8_t rst_pin = -1, uint32_t clkDuring = 400000UL,
                   uint32_t clkAfter = 100000UL);

Donc si tu crées l'instance en ne passant que les 2 premiers arguments c'est Wire qui est utilisé comme flux de communication. Si tu ne fais rien c'est la configuration par défaut de Wire qui est utilisée. Si tu crées par toi-meme une nouvelle instance de Wire avec les broches que tu veux alors ce sera celle-ci qui seront utilisée.


Concernant la librarie DIYables, le SPI est initialisé, dans le code de begin(), sans argument donc ce sont les pins par défaut qui sont utilisées.

A noter, Adafruit a une librarie pour cette afficheur et on peut fournir le périphérique SPI que l'on veut en argument.
Adafruit_GC9A01A::Adafruit_GC9A01A(SPIClass *spiClass, int8_t dc, int8_t cs, int8_t rst)

Le pire, c'est que je l'avais vu, mais oublié.

Pour la bibliothèque Adafruit_GC9A01A je vais regarder.

Merci.

Question subsidiaire :
Pour l'initialisation du SPI, peut-on donner la valeur -1 à la pin CS ?
Cela libère-t-il complètement la pin ?
Je me souviens avoir lu (ATMega328p) que si la pin CS est positionnée en entrée et qu'on y applique un niveau haut cela fait passer le SPI du micro de maître en esclave.

Sur ESP32, pour le SPI par exemple, les pins définies dans pins_arduino.h sont utilisée dans SPIClass::begin()

le prototype ne définit aucune valeur

et il ya toute une logique en fonction des cartes

pour définir les pins vraiment utilisées

donc si vous n'avez pas passé de pins à begin(), il utilise soit celles obligatoires pour votre chip, soit si elles sont variables celles du fichier pins_arduino.h

et à la fin du fichier (un peu comme pour Serial) ils définissent une variable globale SPI

qui définit le SPI principal par son N° de spi_bus


Ce qui veut dire que si les bibliothèques donnent la possibilité de passer les N° de pins au constructeur et qu'elle se chargent de les transmettre à SPI.begin(...) alors vous aurez bien vos pins spécifiques mais si la bibliothèque fait appel à begin() sans paramètres alors vous dépendez des pins définies dans pins_arduino.h

il y a cependant semble-t-il une subtilité : le début de begin() c'est

donc si vous avez appelé vous même dans votre code SPI.begin() avec vos pins, la classe spi aura été initialisée avec vos pins, _spi ne sera pas nul et donc si le begin de la bibliothèque est fait plus tard, il sera ignoré et c'est votre config qui est retenue.

De même pour I2C, on a dans le begin() un test qui regarde si on a déjà initialisé le bus et dans ce cas on ne le refait pas

donc idem vos pins devraient être favorisées.

➜ c'est ce que vous voyez avec votre I2C mais...

ça c'est plus louche... faudrait creuser vraiment ce qu'il se passe... petite trace dans le core ?

Ca me va. Il y a bien "un truc" qui permet de bloquer une double initialisation.
C'est rassurant.

Euh cela veut dire quoi : trace dans le core ?

Je vais recommencer mon test.
Je n'exclus jamais une ânerie de ma part.
Je regarderai aussi avec la bibliothèque indiquée par @fdufnews .

Merci à tous les deux.

Modifier le source du core pour introduire un message sur Serial par exemple dans la fonction begin() pour s’assurer qu’on passe par la …

Je vous informe que j'ai recommencé la manip en SPI, avec la même bibliothèque, (je suis têtu, je n'aime pas quand ça résiste).
Je suis reparti quasiment de zéro en vérifiant point par point.

Conclusion :

  1. Cela fonctionne bien en ajoutant la ligne
    SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, PIN_CS);
    avant d'initialiser le module SPI. :grinning_face:

  2. Cela fonctionne bien ......., mais après que j'ai rectifié les étourderies, désolé. :face_with_bags_under_eyes:

J'en ai appris un peu plus sur la gestion I2C et SPI sur micro Espressif.
Maintenant, je sais que l'initialisation préalable ne fonctionne pas par hasard mais par construction.
Si l'I2C ou le SPI sont initialisés avant d'initialiser des modules, il est possible d'imposer aux bibliothèques des réglages importants comme la fréquence d'horloge.

Commentaire personnel :
L'intelligence naturelle des membres de ce forum est largement supérieure à l'artificielle dont on nous rabat les oreilles :rofl:

Merci.

:clap::clap::clap: