Probleme d'interferences avec mon analyseur de spectre

bonjour tout le monde,

j’ai un soucis d’interferences avec mon montage a base d’arduino nano (oldbootloader) et de tft GMT020-02-7P….

quand je branche les entrées de signaux audio et que le nano se trouve à proximité du Bluetooth de l’ampli sa flash le code que j’ai uploadé au bout de quelques seconde et l’ecran se fige, idem quand le câble du générateur de fréquences et a proximitée immédiate.

y a t’il un filtrage (composants) ou un blindage type (cage de faraday a mettre en place) pour regler se problème, ou , carrement changer d’arduino pour passer sur esp32 (que je ne possède malheureusement pas)

le code ci dessousa été bricolé avec l’IA Copilot vu que je suis nul en codage !!!

un grand merci à tous pour les réponces que vous pouriez m’apporter

#include <Adafruit_GFX.h>

#include <Adafruit_ST7789.h>

#include <SPI.h>




#define TFT_CS   10

#define TFT_DC    8

#define TFT_RST   9




Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);




// MSGEQ7 pins

#define STROBE 4

#define RESET  5

#define LEFT_IN  A0

#define RIGHT_IN A1




// Colonnes dynamiques

const int colWidth = 3;

const int colSpace = 2;

const int numCols = 64;        // calculé pour 320 px

const int baseX = 7;           // centré automatiquement




int leftBands[numCols];

int rightBands[numCols];

int peakL[numCols] = {0};

int peakR[numCols] = {0};




// Layout vertical

const int topY = 10;

const int topHeight = 110;




const int bottomY = 130;

const int bottomHeight = 110;




const int segmentHeight = 5;

const int segmentGap = 2;




unsigned long lastFlicker = 0;




// ---------------------------

//  PALETTE 26 COULEURS VIVES

// ---------------------------

uint16_t colColor[numCols];




uint16_t makeColor(int i) {

  float t = (float)i / numCols;

  int R = sin(t * 6.28 + 0) * 127 + 128;

  int G = sin(t * 6.28 + 2.09) * 127 + 128;

  int B = sin(t * 6.28 + 4.18) * 127 + 128;

  return tft.color565(R, G, B);

}




// ---------------------------

//  SCINTILLEMENT LED RÉALISTE

// ---------------------------

uint16_t flickerColor(uint16_t baseColor) {

  uint8_t r = (baseColor >> 11) & 0x1F;

  uint8_t g = (baseColor >> 5) & 0x3F;

  uint8_t b = baseColor & 0x1F;




  float factor = 0.95 + (random(0, 10) / 100.0);




  r = constrain((int)(r * factor), 0, 31);

  g = constrain((int)(g * factor), 0, 63);

  b = constrain((int)(b * factor), 0, 31);




  return (r << 11) | (g << 5) | b;

}




// ---------------------------

//  SEGMENT LED + NÉON

// ---------------------------

void drawSegment(int x, int y, int h, uint16_t color) {

  uint16_t finalColor = color;




  if (millis() - lastFlicker > 80) {

    finalColor = flickerColor(color);

  }




  tft.fillRect(x, y, colWidth, h, finalColor);




  uint16_t glow = tft.color565(255, 255, 255);

  tft.drawFastHLine(x, y, colWidth, glow);

  tft.drawFastHLine(x, y + h - 1, colWidth, glow);

}




// ---------------------------

//  COLONNE UNIQUE (haut ou bas)

// ---------------------------

void drawColumn(int x, int value, int peak, int startY, int maxH, uint16_t color, bool mirror) {

  int h = map(value, 0, 1023, 0, maxH);




  tft.fillRect(x, startY, colWidth, maxH, ST77XX_BLACK);




  int segments = h / (segmentHeight + segmentGap);




  for (int i = 0; i < segments; i++) {

    int pos = i * (segmentHeight + segmentGap);




    int y = mirror

      ? (startY + pos)

      : (startY + maxH - pos - segmentHeight);




    drawSegment(x, y, segmentHeight, color);

  }




  if (!mirror) {

    int peakY = maxH - map(peak, 0, 1023, 0, maxH);

    tft.fillRect(x, startY + peakY, colWidth, 3, ST77XX_WHITE);

  }

}




// ---------------------------

//  LECTURE MSGEQ7 (64 bandes)

// ---------------------------

void readMSGEQ7() {

  digitalWrite(RESET, HIGH);

  delayMicroseconds(1);

  digitalWrite(RESET, LOW);




  for (int i = 0; i < numCols; i++) {

    digitalWrite(STROBE, LOW);

    delayMicroseconds(25);




    leftBands[i]  = analogRead(LEFT_IN);

    rightBands[i] = analogRead(RIGHT_IN);




    digitalWrite(STROBE, HIGH);

    delayMicroseconds(25);

  }

}




// ---------------------------

//  SETUP

// ---------------------------

void setup() {

  tft.init(240, 320);

  tft.setRotation(1);

  tft.fillScreen(ST77XX_BLACK);




  pinMode(STROBE, OUTPUT);

  pinMode(RESET, OUTPUT);

  digitalWrite(RESET, LOW);

  digitalWrite(STROBE, HIGH);




  randomSeed(analogRead(A3));




  for (int i = 0; i < numCols; i++) {

    colColor[i] = makeColor(i);

  }

}




// ---------------------------

//  LOOP

// ---------------------------

void loop() {

  readMSGEQ7();




  for (int i = 0; i < numCols; i++) {




    if (leftBands[i] > peakL[i]) peakL[i] = leftBands[i];

    else peakL[i] -= 8;




    if (rightBands[i] > peakR[i]) peakR[i] = rightBands[i];

    else peakR[i] -= 8;




    int x = baseX + i * (colWidth + colSpace);




    drawColumn(x, leftBands[i], peakL[i], topY, topHeight, colColor[i], false);

    drawColumn(x, rightBands[i], peakR[i], bottomY, bottomHeight, colColor[i], true);

  }




  if (millis() - lastFlicker > 80) {

    lastFlicker = millis();

  }

}

On a inventé les blindages pour se protéger des perturbation électromagnétiques.

On peut aussi commencer par éloigner les composants qui rayonnent.

Oh là quand j'entends parlé d'IA comme solution magique je part le plus loin possible.

3 € à 4 € sur aliexpess, livrable en moins de 10 jours.
Mode "Choice" : livraison gratuite si montant total de la commande (peut être constituée d'achat sur différents sites marchands) atteint 10 €.

j'ai demandé à une IA ce qu'elle en pensait :

———

Je vais analyser ce code pour un visualiseur de spectre audio avec MSGEQ7 + écran ST7789.

Bugs identifiés

:red_circle: Bug critique — MSGEQ7 : 7 bandes, pas 64

Le MSGEQ7 ne fournit que 7 bandes fréquentielles, pas 64. La boucle readMSGEQ7() lit 64 fois, mais après 7 impulsions STROBE le chip se répète en boucle depuis le début.

// ❌ Incorrect
const int numCols = 64;

// ✅ Correct
const int numCols = 7;

Et le layout doit être recalculé en conséquence (colWidth, colSpace, baseX).


:red_circle: Bug critique — Peak négatif (underflow sur int)

peakL[i] -= 8; // peut descendre sous 0 → valeur négative

peakL et peakR sont des int, donc ils peuvent devenir négatifs et provoquer un affichage aberrant.

// ✅ Corriger avec constrain
peakL[i] = max(0, peakL[i] - 8);
peakR[i] = max(0, peakR[i] - 8);

:orange_circle: Bug logique — Miroir inversé mais peak uniquement en haut

La colonne du bas utilise mirror = true, mais le peak indicator n'est dessiné que si !mirror, donc le canal droit (bas) n'a jamais de peak affiché, contrairement à ce que l'effet miroir suggère visuellement.


:orange_circle: Bug logique — flickerColor appelée seulement si condition vraie, mais pas dans la branche else

if (millis() - lastFlicker > 80) {
    finalColor = flickerColor(color);
}
// sinon finalColor == color, pas de scintillement

Le scintillement n'est actif que toutes les 80 ms, mais l'intent semble être d'appliquer une variation subtile en continu. À clarifier selon l'effet voulu.


:yellow_circle: Avertissement — randomSeed(analogRead(A3)) sur Nano

Sur Arduino Nano, A3 peut ne pas être flottant si connecté au circuit. Utiliser A6 ou A7 (pins analogiques non connectées) est plus fiable pour un seed aléatoire.


:yellow_circle: Avertissement — baseX et numCols non cohérents

Avec numCols = 64, colWidth = 3, colSpace = 2 :

64 × (3 + 2) = 320 px → ça tient pile

Le commentaire dit "centré automatiquement" mais baseX = 7 n'est pas calculé dynamiquement. Si on change numCols, il faudra recalculer manuellement. Mieux vaut :

const int baseX = (320 - numCols * (colWidth + colSpace)) / 2;

Résumé

Sévérité Problème
:red_circle: Critique numCols = 64 incompatible avec MSGEQ7 (7 bandes)
:red_circle: Critique Peak peut devenir négatif
:orange_circle: Logique Peak non affiché sur le canal miroir
:orange_circle: Logique Scintillement inactif entre les fenêtres de 80 ms
:yellow_circle: Warning randomSeed sur pin potentiellement connectée
:yellow_circle: Warning baseX non calculé dynamiquement

Le bug le plus bloquant est le nombre de bandes — le spectre ne s'affichera jamais correctement avec 64 lectures sur un MSGEQ7.

C'est un problème d'interférence, d'affichage ou de soft?
Lorsque le système n'est pas à proximité du Bluetooth fonctionne t'il correctement?

Merci J-M-l pour ton retours je vais corriger tout cela !

Je ne pensais vraiment pas qu’il y avait autant de probleme avec se code, pour le MSGEQ7 incompablible avec 64 bande il y a un detail qui m’a mis la puce a l’oreille car quand j’ai augmenté de 7 vers les 64 je voyais le signal du generateur de frequence comme si c’etait son propre écran et oui je viens de regarder il y a bien une répétition toutes les 7 bandes.

Je suis novice en programmations j’ai trouvé 2 nano que j’avais commandé il y a tellement longtemps que je n’ai meme plus l’année en tête, j’avais abandonné l'idée de me lancer sur arduino mais que je vois les progrès qui ont été fait depuis les anciens nano je me suis dit pourquoi pas réessayer et persévérer.

Les interferences effacent complètement le code que je mets dans le nano quand il est a proximité du Bluetooth et le générateur de fréquence me donne un affichage du spectre complètement chaotique mais quand tout est eloigné sa fonctionne sur 7 bandes répété plusieur fois comme l’indique J-ML

j’ai commandé une Carte de développement WiFi Bluetooth ESP32-WROOM-32, écran couleur LCD intégré de 1.9 pouce soit disant 240x320px mais vu les ESP-S3 avec écran qui ont une résolution de 170x320px je pense ne pas avoir fait le bon choix + un lot d'ESp32 tout simple et un capteur de temperature/humidité pour voir ce que j'arrive a faire avec les écran 1.53" et 2" que je posséde

Bonsoir ou bonjour la communauté

J'ai fait quelques petites recherches sur different site de ventes et j'ai trotexte en grasuvé se commentaire assez long veuillez m'excuser par avance pour le temps de lecture

J'ai plusieurs projets en cours avec différentes cartes électroniques, pour développer de petits gadgets et me débrouiller avec les cartes les plus utilisées du moment, dont les plus petits de la famille hériteront à l'avenir, pour apprendre à programmer. Dans ce cas, il me manquait une carte ESP32 et j'ai essayé celle-ci, de la marque Diymore, qui possède une connexion d'alimentation USB-C. Il comprend un convertisseur USB vers série (CH340) et un module ESP-WROOM-32 avec écran LCD couleur intégré de 1,96 pouces. Il s'agit d'une carte de développement avec une puce Tensilica L106 avec une consommation minimale de processeur de 32 bits et une fréquence de 80 MHz à 160 MHz, qui possède une connectivité de type C, UART, SPI, SDIO, I2C, PWM, I2S, IR, ADC, DAC, Wi-Fi et Bluetooth. Il possède une antenne PCB ESP-32S (2400-2500 MHz). Supporte les communications sans fil 802.11 b/g/n/e/i. Une mémoire LPDDR2 est incluse. Un avantage considérable est que nous disposons déjà d'un très joli écran couleur intégré qui nous permet d'afficher des données ou des images en haute définition. Le module ESP32 dispose de plusieurs modes de programmation et dispose également d'une connectivité BT ou Wi-Fi sur une fréquence de 2,4 GHz pour gérer par programmation une pile complète de protocoles réseau. Je pense que c'est idéal pour le prototypage ou même pour les débutants. C'est parfait pour commencer, car tout est intégré, assemblé et vous n'avez pratiquement pas besoin de quoi que ce soit pour fonctionner. Il possède une mémoire flash SPI intégrée (4 Mo/32 768 192 octets), suffisante pour le système d'exploitation et les données que vous pouvez gérer. Il dispose d'une interface de chargement de batterie au lithium de 3,7 V pour un fonctionnement sans fil. Il permet une connexion directe à Internet via un routeur doté d'une connectivité Wi-Fi et la connexion de téléphones portables via Bluetooth. Très complet et tient dans la paume de votre main.

Est-ce que c'est recommandé ?
OUI. Si vous connaissez Arduino ou si vous souhaitez les acquérir, mais sans dépenser beaucoup d'argent et sans perdre beaucoup de temps à installer l'équipement. Une autre chose est que la documentation en ligne spécifique n'est pas disponible et que celle sur le Web est assez basique. Quelques images pour télécharger OpenArduino et depuis Expressid.
NON. En raison de sa gamme de prix, vous pouvez vous procurer un appareil similaire basé sur l'ESP32 auprès d'autres fabricants qui incluent une documentation adéquate pour ne pas perdre trop de temps au démarrage.

Expérience utilisateur :
il est livré dans un sac en plastique rembourré (avec bulles) hermétiquement fermé avec une bonne protection. Il comprend des liens pour télécharger les manuels au format pdf dans différentes langues, y compris l'espagnol, mais il convient de noter qu'il ne fonctionne PAS depuis l'Espagne. Un site Web apparaît avec le message 404 Not Found. Le manuel de la puce (pas la carte) est accessible en recherchant sur Internet l'identifiant FCC du fabricant (2BCLP-ESP-32S), qui correspond à la technologie Shenzhen Siinst. L'URL pour télécharger les manuels des puces est la suivante :
FCC ID 2BCLP-ESP-32S . La série ESP32-WROOM comprend des modules Wi-Fi et Bluetooth combinés basés sur le système sur puce (SoC) ESP32. Le module ESP32-WROOM est parfait pour le prototypage rapide et la mise en œuvre de solutions IoT. Sa conception prête à l'emploi le rend idéal pour les appareils domestiques intelligents, les appareils électroniques grand public, les capteurs sans fil, les appareils connectés, les communications et pour manipuler les langues et l'électronique.

Note technique :
La plate-forme ESP32 permet le développement d'applications dans différents langages de programmation, frameworks, bibliothèques et ressources. Les plus courants sont : Arduino (C/C++), ESP-IDF (Espressif IoT Development Framework), Simba Embedded Programming Platform (Python), RTOS (comme Zephyr Project, Mongoose OS, NuttX RTOS), MicroPython, LUA, Javascript (Espruino, Duktape, Mongoose JS) ou Basic. En travaillant dans l'environnement Arduino, nous pouvons utiliser un langage de programmation bien connu et utiliser un IDE simple, en plus d'utiliser toutes les informations sur les projets et les bibliothèques disponibles sur Internet.

Conseils d'utilisation :

  • Je recommande d'installer l'IDE Arduino (arduino.cc) pour fonctionner avec ces cartes.
  • Il comprend un convertisseur CH340 utilisé sur la carte de développement pour charger du code à l'aide de l'IDE Arduino. Il nécessite l'installation des pilotes CH340 (convertisseur USB vers série), bien qu'il doive être installé automatiquement sur la plupart des systèmes d'exploitation.
  • La série ESP32-WROOM comprend plusieurs modèles, de l'ESP32-WROOM-32 de base au 32D, 32U et 32E, chacun offrant des configurations d'antenne et des options de mémoire différentes. Vérifiez vos besoins pour sélectionner ce dont vous avez besoin.
  • Une source de documentation pour ces types de plaques est expressif.com.

Suggestions d'amélioration :

  • Mettez à jour les liens de téléchargement de la documentation du forum.

Points forts :

  • Le module ESP32-WROOM rationalise le processus de développement grâce à des antennes intégrées, des certifications réglementaires et une mémoire étendue. Il est idéal pour les prototypes utilisant LoRaWAN.
  • Ils offrent toutes les fonctionnalités d'un module ESP32 traditionnel, y compris le BT, le Wi-Fi et un écran pour afficher les données en haute définition.
  • Supporte plusieurs interfaces, UART, SPI, SDIO, I2C, PWM, I2S, IR, ADC, DAC.
  • Comprend un écran LCD couleur de 1,9 pouces.
  • Les modules ESP32-WROOM sont certifiés pour leur conformité réglementaire, ce qui réduit les délais et les coûts de certification. Cela en fait le choix idéal pour les développeurs qui souhaitent commercialiser rapidement leurs produits. Ils comprennent une antenne PCB ou un connecteur IPEX pour une antenne externe.
  • Sécurité : cryptage matériel, démarrage sécurisé, cryptage flash.

Points faibles :

  • Il est recommandé d'avoir des connaissances préalables ou d'avoir envie d'apprendre.

vous confirmez ?

Il aurait été plus simple de mettre un lien vers le site marchand plutôt que ce copié/collé relativement indigeste qui contient des erreurs et des contradictions.
Et je ne vois pas trop ce que tu veux que l'on confirme dans la mesure ou on ne sait pas de quel matériel tu parles.

Je pense que tu te prends trop la tête pour pas grand chose.

Les puces ESP32 sont toujours fabriquées mais sont fortement concurencées par les générations ESP32-Cx, ESP32-SX, ESP32-HX, ESP32-PX.

Les deux ”en vogue” actuellement sont les ESP32-C3 et ESP32-S3.
On trouve des réalisations sur des cartes de grandes surface où tous les gpios sont accessibles, on trouve des réalisations de petites surface où moins (c’est relatif) de gpios sont accessibles.

On trouve des réalisations où la puce est dans un boitier blindé (meilleure immunité au bruit) et d’autres sans blindage, mais qui fonctionne toujours.

En résumé : inutile de se prendre la tête avec des analyses commerciales (achetez moi, je suis la meilleure carte) ou d’auto proclamés expert.

Les plus important est que tu évalues tes besoins.
Trouver la carte qui y réponds se fera ensuite.

Soyons clair le Bluetooth n'efface rien mais ton circuit est perturbé

Je pencherais plutôt pour un mauvais câblage.. On a tous bricolé sur une table avec le PC et/ou le téléphone à proximité (qui crache WiFi et Bluetooth) sans aucune perturbation.
Je serais d'ailleurs curieux de voir une photo d'ensemble du montage.

C'est tellement une évidence, que c'est un bon rappel. Une énumération vante ce qu'il y a pas ce qui pourrait manquer pour faire aboutir le projet. La phrase principale passe inaperçue . Vérifiez vos besoins pour sélectionner ce dont vous avez besoin.

Espressif fournit un comparatif pour aider à ce choix

Suite à ce que dit @fdufnews pour la partie hardware pourquoi ne pas utiliser une bibliothèque spécifique au MSGEQ7 pour la partie software faute de lire la datasheet du composant?

Amazon.fr :Commentaires en ligne: diymore Carte de développement pour ESP32 avec écran LCD 1.96inch 2.4 GHz WLAN WiFi Bluetooth BLE MCU CH340 Chip pour ESP32 32 Nodemcu USB C

Page inaccessible sans compte Amazon.

Je reviens au début.
Qu'est-ce qui permet d'accuser des interférences ?
Absolument rien.

La carte Nano et son microcontrôleur Atmega328p n'a aucun problème identifié, c'est vraiment une carte béton de chez béton.

Il faut bien poser le problème.
Désolé mais à 99 % c'est de la faute de l'opérateur.
Il faut bien se dire que quand cela ne fonctionne pas c'est nous qui sommes responsables, moi comme toi.

Seuls ceux qui commencent par se dire : qu'est-ce que j'ai fait comme erreur, peuvent progresser.
Les autres font de la fuite en avant et se vautrent, l'IA n'est d'aucun secours.

Qu'est-ce qui fonctionne ?
A partir de quand cela ne fonctionne plus ?
Et bien évidement il faut décrire le matériel et les connexions dans tous les cas.

Il y a bien mieux que l'IA.
Quand tu utilises un composant qui nécessite une bibliothèque il faut commencer par faire les exemples de code qui sont fournis avec sa bibliothèque.
Tant que tu n'arrives pas à faire fonctionner ces exemples il est inutile d'aller plus loin.
Ces exemples ont été vérifiés des milliers de fois.

En l’occurrence, ici, ce n'est pas vraiment le cas. Le composant dispose de 2 fils de commande.

  • un reset. qui initialise un séquence de lecture
  • un strobe, qui permet de passer d'un pas au suivant.
  1. On fait un reset, une impulsion positive
  2. On génère un strobe pour aiguiller un filtre vers la sortie et on répète 7 fois.

la datasheet ici

A noter:

  • Sur la sortie analogique, on lit le niveau crête pour une bande de fréquence.
  • A chaque fois qu'on lit une sortie de filtre on décrémente son contenu d'environ 10% ce qui permet d'avoir un effet d'amortissement suite à un pic de niveau. La fréquence de lecture influe donc directement sur le rendu.
  • on n'a pas besoin de faire un reset, sauf à l'initialisation bien sûr, si on contrôle bien les impulsions de strobe le compteur rebouclant sur 0 lorsqu'il arrive au dernier filtre.

Encore est-il que même si le composant est simple, faute d'avoir lu la datasheet il vaut mieux utiliser une bibliothèque.

Faire une fonction de lecture d'un composant sans lire la datasheet relève de Nostradamus. Dans une bibliothèque la fonction lecture sera au moins conforme à celle ci.

Bien on va reprendre depuis le début, maintenant que l'on a un lien vers la datasheet.
Ce lien aurait du être fourni par le demandeur, il me semble que c'est demandé dans le message d'accueil.

Quelques remarques .

Dans le code je vois les mémoires leftBands et rightBands : c'est donc qu'il n'y a pas qu'un MSGEQ7 mais deux !
Dans ce cas est-ce que les deux "Strobe" et les deux "Reset" sont connectés ensemble ?

A priori je ne vois pas d'inconvénient a ce qu'ils le soient, mais il faut le dire et vérifier que la mise en parallèle n'apporte pas des soucis non prévus.

Je suis curieux de savoir ce que donne : delayMicroseconds(1); sachant qu'en fonction des réglages "mode Arduino" du timer 0, le pas de delayMicroseconds est de 4 µs.
1 cela donne 0 µs ou 4 µs ?
Attention ce n'est valable qu'avec un micro avr comme l'atmega328p, pour d'autres micro je n'ai pas l'information.

J'aborde la suite pour faire de l'information sur les temps d’exécution des fonctions digitalWrite/Read.
Je ne dis pas que c'est la cause des problèmes, je dis que cette information est très rarement donnée et qu'il est essentiel de la connaître quand on pilote un composant où le respect des timings est important.

Sur un atmega328p (carte nano), digitalWrite est une fonction qui prend (environ) 60 cycles horloge, soit avec une horloge à 16 MHz : 62,5 ns * 60 = 4 µs.
La "lenteur" est due à une double cause : le micro lui même et le code qui a été écrit.
Mettre un gpio à 1 puis immédiatement le mettre à 0 prend 8 µs.
Le temps minimal du plateau du signal est de 4 µs.

Ce n'est pas en choisissant un micro qui a une fréquence horloge de 240 MHz comme l'ESP32-S3 que l'on gagnera dans un rapport des fréquences horloge 240/16 = 15.
Non, dans les micro 32 bits, l'horloge principale peut être à 240 MHz, mais celle qui pilote les gpios peut n'être que de 80 ou 40 MHz.

Uniquement pour les micro AVR, comme l'atmega328p de la nano, il existe la fonction digitalWriteFast qui ne prend que deux cycles horloge à 16 MHz.

Pour les ESP32 on peut aussi aller plus vite qu'avec digitalWrite en écrivant directement dans les registres :

Les temps minimaux de la datasheet du MSGEQ7 sont-il respectés ?


Ce sont des temps minimaux; il est possible de les augmenter.
Je pense plus particulièrement au temps "trs" et "to"

  • trs est le temps minimal entre le retour à 0_Logique (LOW) de Reset et le retour à 0_Logique (LOW) de STROBE.
  • to est le temps minimal pour la mesure soit disponible sur la sortie.

ATTENTION AUSSI aux particularités des mesures analogiques.
Il n'y a qu'un SEUL ADC dans un microcontrôleur.

Cet unique ADC est précédé par un multiplexeur analogique. Dès qu'il y a une modification sur le multiplexeur, comme commuter d'une entrée Ax à une entrée Ay il faut systématiquement rejeter la première mesure.
La raison est qu'une mesure analogique prend plus de temps que le multiplexeur met à commuter de Ax à Ay.
S'il y a commutation, la première mesure qui suit la commutation peut être commencée sur Ax et terminée sur Ay.
Elle doit être systématiquement considérée comme fausse.

Un bon appareil de mesure, simple d'emploi, pas cher, pour mesurer des temps est l'analyseur logique clone de Saleae que l'on trouve à 5 ou 6 € sur aliexpress.

Remarque de méthodologie :
Pourquoi faire directement un programme qui incorpore la gestion d'un écran SPI ?
Il est possible de faire de simples sorties rudimentaires dans le moniteur série.

Seulement si les sorties sont bonnes, on passe à l'incorporation d'un écran.
Plus il y a d'actions qui sont effectuées, plus il y a des motifs pour se tromper.
Moins il y a d'actions, plus vite on trouve la cause d'un non fonctionnement.

Sur AVR le code est optimisé pour attendre le bon temps entre 3 et 16383 microsecondes. Cf la doc)

Si vous regardez le code source delayMicroseconds sur AVR n’utilise pas micros() mais repose sur des boucles calibrées en assembleur dépendant directement de la fréquence CPU.

Cela à toujours été la méthode Atmel qui n'utilise que des opérations dont il connait parfaitement le résultat puisque c'est Atmel qui conçoit le microcontroleur.
Il fut un temps où j'avais un lien sur mon PC sur l'avrLibC, ou je trouvais mes informations, je ne l'ai plus.

Ce point du pas de 4 µs a été souvent évoqué sur ce forum, certes il y a plusieurs années.
Je ne met pas en cause ce que tu dis, mais cela voudrait dire que le code a été changé.

Mais quand même, si on va sur le site Arduino :
https://docs.arduino.cc/language-reference/en/functions/time/delayMicroseconds/

on peut lire :

Notes and Warnings

This function works very accurately between 3 and 16383 microseconds. We cannot assure that

delayMicroseconds

will perform precisely for smaller delay times. Larger delay times may result in a very brief delay.

Donc nouveau code ou pas, delaymicrosecond pour des délai inférieure à 3 µs est fortement déconseillé.
Dans le code il y a un delaymicrosecond(1);

Concernant la question de départ c'est de l'ordre du troisième chiffre après la virgule alors que l'on n'est pas sûr des unités.

J'aimerais bien que l'OP nous fasse un tableau qui indique les valeurs attribués à chacun des temps du timing qui permet d'avoir des résultats fiables.
Qu'il fasse un test avec une seule voie (s'il y en a réellement deux, c'est flou) et en virant la cosmétique en virant l'écran afin que l'on comprenne un peu mieux ce qu'il se passe.