SH1106 OLED 128x64 I2C et Nano Pg de test OK Pg final bloque à Begin

Bonjour à tous
DESCRIPTION:je me suis développé une application (Arduino Nano et électronique) pour commander des chauffages électriques (6 ordres) sur 2 zones:
1/un interrupteur permet de choisir marche normal="PRESENT" ou bien régulation global (1 zone puis l'autre) avec température lue qui régule à une température réglée par potentiomètre. L'ensemble fonctionne bien avec un afficheur LCD I2C 1620.
J'ai ensuite décidé de remplacer cet afficheur par un afficheur OLED 128x64 I2C:
PROBLEME: j'ai d'abord écrit un programme de test et mise au point d’affichage sur le même montage: Ca MARCHE;
Lorsque je transfert ce programme dans le programme original le programme bloque à l'instruction "affich.begin(0x3C, true); " Je ne trouve pas l'erreur!
JE PRÉCISE QUE LA COMPILATION NE DONNE AUCUN MESSAGE D'ERREUR et que le transfert se passe bien pour les 2 programme sur la même électronique (même NANO même électronique)
Programme de test qui marche"TSt_affich_128_64_sketch_dec22a"


//#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
/* Uncomment the initialize the I2C address , uncomment only one, If you get a totally blank screen try the other*/
//#define i2c_Address 0x3c  //initialize with the I2C addr 0x3C Typically eBay OLED's
//#define i2c_Address 0x3d //initialize with the I2C addr 0x3D Typically Adafruit OLED's

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define OLED_RESET -1     //   QT-PY / XIAO
Adafruit_SH1106G affich = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

/*
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
*/
String Cms_d;
float Tam = 200;
float Tci = 123;
bool Zs;

void init_display() {
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.

  delay(250);                 // wait for the OLED to power up
  affich.begin(0x3C, true);  // Address 0x3C default
                            //affich.setContrast (0); // dim display

  affich.display();
  delay(2000);

  // Clear the buffer.
  affich.clearDisplay();
  // put your setup code here, to run once:
  // text display tests
  affich.setTextSize(1);
  affich.setTextColor(SH110X_WHITE);
}
void montre()
{

}
///////////////////////////////
void setup() {

  Serial.begin(11500);

  init_display();
  affich.setCursor(0, 0);
  
  /*
  affich.println("Failure is always an option");
  affich.setTextColor(SH110X_BLACK, SH110X_WHITE);  // 'inverted' text
  affich.println(3.141592);
  affich.setTextSize(2);
  affich.setTextColor(SH110X_WHITE);
  affich.print("0x");
  affich.println(0xDEADBEEF, HEX);
  affich.display();
  delay(2000);
  affich.clearDisplay();
  */
}

void loop()
 {
  char buf_Tam[6];
  char buf_Tci[6];
  float Tam_d;
  float Tci_d;
  if (Cms_d == "ABSENT") 
  {
    Cms_d = "PRESENT";
  } 
  else 
  {
    Cms_d = "ABSENT";
  }
  if (Zs==0){Zs=1;} else {Zs=0;}
  affich.setTextSize(2);
  affich.setCursor(0, 0);
  affich.println(Cms_d);
  ////
  affich.print(" Tamb=");
  dtostrf(Tam/10,4,1,buf_Tam);
  affich.println(buf_Tam);//affich.println("°");
  affich.setTextSize(1);
  //affich.println();
  affich.setCursor(0,36);
  affich.println("Consigne    Active");
  affich.setCursor(0,48);
  affich.setTextSize(2);
  dtostrf(Tci/10,4,1,buf_Tci);
  affich.print(buf_Tci);affich.print(" Zone");affich.println(Zs,BIN);
  affich.display();
  delay(1000);
  affich.clearDisplay();
}

Programme final "CanZ1Z2_Nano_Oled_dec22b" qui bloque ligne " affich.begin(0x3C, true);"


//pg commande chauffage Cancale
#include <avr/wdt.h>  // watchDog timer
// librairie afficheur I2C
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define OLED_RESET -1     //   QT-PY / XIAO
Adafruit_SH1106G affich = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

const float K=1.08;  //0.931; // 1024.0/1100.0
// définitions des pins E/S
#define PIN_Z1 8
#define PIN_Z2 9
#define PIN_Cmd 7
#define PIN_Ta A0
#define PIN_Tc A2
// variable Temperature
int Tam; // T ambiante moyeene en dixième de degré
int Tci; // valeur de consigne calculée en dixème de degré
 int Tc0=129; // T consigne min 120/K
 int Tc1=135; // T consigne + hysterésie de 5 dixième
//variable des zones et commande
bool Zs; // Z1=true et Z2 = false
bool Cmd; // true = present et false = absent

// variables de durée (temps en millisecondes)
unsigned long Dmi; // durée en cours
unsigned long Dm0; // origine du temps en cours
const unsigned long D_Z1=1000;//300000; // durée max Zone 1
const unsigned long D_Z2 = 2000;//600000; // durée max Zone 2
const int tempo=2000;
//contante d'affichage

void init_affich()
{
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  Serial.println(F("debut init_affich ligne 49"));
  delay(250);                 // wait for the OLED to power up
  affich.begin(0x3C, true);   // Address 0x3C default
  //affich.setContrast (0); // dim display
  affich.display();
  delay(2000);
  
  Serial.println(F("init Oled ligne 56"));


  // Clear the buffer.
  affich.clearDisplay();
  affich.setTextSize(1);
  affich.setTextColor(SH110X_WHITE);
  Serial.println(F("init_affich DONE"));
  affich.display();
}

////////////////////////
/*
void init_lcd()
{
  lcd.init();
  lcd.backlight();
  delay(250);
}
*/


/////////////////////////////set_up
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print(F("Serial initialisé avec File= "));
  Serial.println(__FILE__); 
  // fonction I/O des pins
  pinMode(PIN_Z1,OUTPUT);
  pinMode(PIN_Z2,OUTPUT);
  pinMode(PIN_Cmd,INPUT);
  pinMode(PIN_Ta,INPUT);
  // analogic reference 1V
  analogReference(INTERNAL);
  Tam=analogRead(PIN_Ta);
  Tc0=analogRead(PIN_Tc);
  Serial.println("Ta initial="+Tam);
  Zs=true; // Z1 d'abord
  Serial.println(F("on va sur aret Zs"));
  Arret_Zs(); // arret des 2 zones
  Dm0=millis();  // initialisation du compteur de duréé
  Dmi=0; // iniotialisation de la durée
  Tci=Tc0; // initialisation de la Temperature de consigne au min
  init_affich();

}
////////////////////////////////
  void Marche_Zs()
  {
    digitalWrite(PIN_Z1,LOW);
    digitalWrite(PIN_Z2,LOW);  
    Serial.println("SP Marche_Zs");  
  }
//////////////////////////////// 
  void Arret_Zs() //mise à l'arret des 2 zones
  {
    digitalWrite(PIN_Z1,HIGH);
    digitalWrite(PIN_Z2,HIGH);
    Serial.println("SP arret_Zs");
  }
/////////////////////////////
void Commute_Zs(bool Zi)
{
  if(Zi==true)
  {
    digitalWrite(PIN_Z1,HIGH);
    digitalWrite(PIN_Z2,LOW);
  }
  else
  {
    digitalWrite(PIN_Z1,LOW);
    digitalWrite(PIN_Z2,HIGH);    
  }
  Serial.println("SP Commute_Zs");
}
/////////////////////////////
  void lit_Ta() // lecture temperature en dixieme de degré  et moyenne
  {
    int Ta=analogRead(PIN_Ta);
    Tam=(Tam*7+Ta)/8;
    Serial.println("Tam="+ String(Tam)+"==> Ta="+String(Tam*K/10));
  }
///////////////////////////
  void lit_Tc()
  {
	int Tc=analogRead(PIN_Tc);
	Tc0=(Tc0*7+Tc)/8;
  Tc1=Tc0+6;
	Serial.println("Tc0="+ String(Tc0)+" ==> T0="+String(Tc0*K/10));
  }
////////////////////////
  void lit_Cmd()  // lit l'interrupteur de commande
  {
    Cmd=digitalRead(PIN_Cmd);
    Serial.println("SP lit_cmd="+String(Cmd));
  }
//////////////////////
  void lit_Dmi()
  {
    Dmi=millis()-Dm0;
    if (Dmi>=D_Z2)
    {
      Dm0=millis();
      Dmi=0;
    }
  }
  
//////////////////////
void ecr_lcd()
{
  Serial.println(F("  début ecr_lcd ligne 160"));
  char buf_Tam[6];
  char buf_Tci[6];

  float Tam_d=Tam*K/10;
  dtostrf(Tam_d,4,1,buf_Tam);
 
  float Tci_d=Tci*K/10;

  dtostrf(Tci_d,4,1,buf_Tci);
    Serial.println("Tci_d="+String(Tci_d)+"==>"+buf_Tci);
  String Cmd_S;
  if(Cmd==true)
  { Cmd_S="PRESENT";}
  else {Cmd_S="ABSENT ";}

  affich.clearDisplay();
  affich.setTextSize(2);
  affich.setCursor(0, 0);
  affich.println(Cmd_S);
  affich.print(" Tamb=");
  affich.println(buf_Tam);
  affich.setTextSize(1);
  affich.setCursor(0,36);
  affich.println("Consigne    Active");
  affich.setCursor(0,48);
  affich.setTextSize(2);
  affich.print(buf_Tci);affich.print(" Zone");affich.println(Zs,BIN);
  affich.display();
  delay(1000);
}

///////////////////////////////loop
void loop() {
  wdt_enable(WDTO_4S);
    lit_Cmd();
	  lit_Tc();
    lit_Ta();
    lit_Dmi();
    //on decide quelle zone est active
    if(Dmi<=D_Z1)
    {
      Zs=true;
    }
    if ((Dmi>D_Z1) && (Dmi <=D_Z2))
    {
      Zs=false;
    }
    if(Cmd==true)  // cas present
    {
        //Marche_Zs(); // pas de signal sur z1 zet z2
        Commute_Zs(Zs); // on commande alternativement les 2 zones
    }
    if(Cmd==false) // cas absent
    {
        if(Tam>Tci)  // Temperature moyenne au desssus de la consigne
        {
          Arret_Zs();
          Tci=Tc0; //on revient à la consigne mini
        }
        if (Tam<Tci)  // il faut chauffer
        {
          Tci=Tc1;
          Commute_Zs(Zs);
        }
    }
Serial.println("Fin loop Tci="+String(Tci)+" ==> Ti="+String(Tci*K/10));
//affiche à écrir
ecr_lcd();
//

delay(tempo);
wdt_reset();
}

Peut-être un problème de mémoire.
La librairie graphique bloque quand même 1k de RAM pour créer le buffer d'écran à quoi il faut ajouter quelques variables de travail. Cette allocation est faite dynamiquement à l'initialisation de l'afficheur et n’apparaît donc pas dans le compte-rendu de compilation.
Dans le compte-rendu de compilation combien y-a-t-il de RAM libre?

pour le programme de test de l'afficheur:
Le croquis utilise 15546 octets (50%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 649 octets (31%) de mémoire dynamique, ce qui laisse 1399 octets pour les variables locales. Le maximum est de 2048 octets.
"C:\Users\jppur\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\jppur\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -patmega328p -carduino "-PCOM3" -b57600 -D "-Uflash:w:C:\Users\jppur\AppData\Local\Temp\arduino\sketches\765E434C890D1921EE321AC8AD58A335/TSt_affich_128_64_sketch_dec22a.ino.hex:i"

Pour le programme complet:
Le croquis utilise 18652 octets (60%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 870 octets (42%) de mémoire dynamique, ce qui laisse 1178 octets pour les variables locales. Le maximum est de 2048 octets.
"C:\Users\jppur\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/bin/avrdude" "-CC:\Users\jppur\AppData\Local\Arduino15\packages\arduino\tools\avrdude\6.3.0-arduino17/etc/avrdude.conf" -v -patmega328p -carduino "-PCOM3" -b57600 -D "-Uflash:w:C:\Users\jppur\AppData\Local\Temp\arduino\sketches\A616ECABFD27C0EFC8729E5A4A575E9B/CanZ1Z2_Nano_Oled_dec22b.ino.hex:i"

C'est un afficheur AZDelivery qui fonctionne bien avec le premier programme de test de l'affichage (mise au point) mais pas avec le suivant quand je l'intègre dans le programme complet: il bloque à dans le SP "init_affich"à la ligne

affich.begin(0x3C, true); Je le repère en regardant les sortie imprimé usb.

https://www.az-delivery.de/fr/products/1-3zoll-i2c-oled-display

j'ai bien vérifié l'adresse avec un programme scanner I2C et c'est la même dans les 2 programmes.

L'Ebook d'AZ Delivery annonce SH1106 et ça marche dans le programme de test de l'affichage!

Et je pense avoir bien fait pareil. En fait je ne sais pas quelle bibliothèque simple à utiliser pour écrire du texte seulement (pas de graphique)

Cordialement

Sur les 1178 octets de libre, la librairie graphique va allouer 128 * 64 / 8 soit 1024 octets pour le buffer d'écran plus quelques dizaines d'octets pour son usage propre. Donc il n'y a plus de mémoire disponible pour un fonctionnement correct.

Tu pourrais te rabattre sur la librairie U8g2. Cette librairie est disponible dans le gestionnaire de librairie de l'IDE.
Elle a des modes de fonctionnement utilisant un buffer graphique réduit. Cela ralenti le tracé car il est effectué en plusieurs passes.
Elle a aussi un mode purement texte (U8X8) dans lequel il n'y a pas du tout de buffer graphique et qui permet donc de ne consommer que très peu de ressources.

Avant de l'utiliser, il est bon de lire le wiki qui détaille bien les modes de fonctionnement et leurs contraintes.

Merci beaucoup, pour le débogage..

Je vais essayer d'utiliser la librairie U8x8, cela va me prendre quelques temps pour refaire l'application.

En attendant merci pour ta réponse et son lien que je vais regarder.

Bonne fêtes de Noël et de fin d'année.

Cordialement

Merci de votre réponse
J'ai eu quelques soucis domestiques qui m'ont retardé dans la suite de mon application.
J'ai programmer avec la librairie U8x8 ; j'ai eu quelques difficultés car les commandes ne sont pas les mêmes: le programme de test de l'affichage fonctionne fonctionne! Si ça peut aider certain voilà le fichier:
test_Oled128x64_B8x8_sketch_dec24a.ino (1,6 Ko)

Ensuite lorsque je l'ai incorporé dans le programme principale sur une carte arduino nano V3 clone chinois: j'ai tué la carte! Az-Delivery m'en a renvoyé une neuve mais là j'ai supprimé le watchdog et tout marche bien!....
CanZ1Z2_Nano_Oled_jan01a.ino (5,4 Ko)

il me reste encore à faire le dessin du CI avec KiCad puis le réaliser et enfin de le cabler... puis le mettre en boite et l'installer à la campagne ce sera bien utile!

Deux pistes :

  1. Si je regarde ce code d'exemple à la ligne 68, j'ai l'impression que les paramètres passés à affich.begin(0x3C, true); ne sont pas ceux auxquels s'attend la librairie : display.begin(SH1106_SWITCHCAPVCC, 0x3C);.

  2. Il manque peut-être un Wire.begin() avant le affich.begin().

Cordialement,

Nicolas