Heltec display trouble

i cannot get heltec esp32 v3.2 to display anything with an outside sketch. Mesh works ok. Is there a sketch to show how to get the display to work

If you’re using the Arduino IDE:

File > Examples > HeltecExample > FactoryTest > WiFi_LoRa_32_V3_FactoryTest

An important thing to note is that the v3.2 uses inverted logic on the backlight (through Vext) compared to the normal v3 and v3.1.

does anyone have a working sketch that will show the display works on heltec lora32 v3 v3.2. I cannot get anything to work. the display works fine when i flash Meshtastic

No point asking for the same thing again until you tell us why @UniquePete’s suggestion doesn’t work …

after some time i have been working with Grok to solve the problem of haveing the heltec lora 32 v3.2 to write to display without meshtastic. I have a bmp280 sensor outputing to display the temp and pressure in F and "hg. The display is on one i2c bus and the sensor on the other. we will be adding a 0-3.3v anamometer using adc on the sensor bus. Amazing having the resource that Chat and Grok can supply but you still need to help them once and a while. Heres the sketch
#include <Wire.h>

#include “HT_SSD1306Wire.h”

#include <Adafruit_BMP280.h>

#ifdef WIRELESS_STICK_V3

static SSD1306Wire display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_64_32, RST_OLED);

#else

static SSD1306Wire display(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED);

#endif

Adafruit_BMP280 bmp(&Wire1);

unsigned long updateCounter = 0; // Counter for updates

const float tempOffset = -4.5; // Adjust to align with 75°F (23.9°C)

const float altitude = 1000.0; // Adjust to your altitude in meters

void VextON(void) {

pinMode(Vext, OUTPUT);

digitalWrite(Vext, LOW);

}

void setup() {

Serial.begin(115200);

Serial.println(“Starting BMP280 Continuous Display…”);

VextON();

delay(100);

// Initialize OLED (uses Wire on default pins: SDA_OLED=4, SCL_OLED=15)

display.init();

display.clear();

display.display();

display.setContrast(255);

Serial.println(“OLED initialized”);

// Initialize second I2C bus for BMP280 (pins 41 SDA, 42 SCL)

Wire1.begin(41, 42);

Serial.println(“Wire1 initialized on pins 41, 42”);

// Initialize BMP280

if (!bmp.begin(0x76)) {

Serial.println("BMP280 Failed");

display.clear();

display.setTextAlignment(TEXT_ALIGN_CENTER);

display.setFont(ArialMT_Plain_10);

display.drawString(display.getWidth()/2, display.getHeight()/2-10/2, "BMP280 Failed");

display.display();

while (1);

}

Serial.println(“BMP280 OK”);

}

void loop() {

updateCounter++; // Increment counter

// Read BMP280 data

float tempC = bmp.readTemperature() + tempOffset; // Apply offset

float tempF = tempC * 9.0 / 5.0 + 32.0; // Convert to °F

float pressure = bmp.readPressure() / 100.0F; // hPa

// Convert to sea-level pressure (hPa)

float seaLevelPressure = pressure / pow(1.0 - 0.0000225577 * altitude, 5.255);

float pressureInHg = seaLevelPressure / 33.8639; // Convert to inHg

// Display data

display.clear();

display.setTextAlignment(TEXT_ALIGN_LEFT);

display.setFont(ArialMT_Plain_10);

String tempStr = “T: " + String(tempF, 1) + " F”;

String pressStr = “P: " + String(pressureInHg, 2) + " inHg”;

String countStr = "C: " + String(updateCounter);

#ifdef WIRELESS_STICK_V3

display.drawString(0, 0, tempStr);

display.drawString(0, 12, pressStr);

display.drawString(0, 24, countStr);

#else

display.drawString(0, 10, tempStr);

display.drawString(0, 30, pressStr);

display.drawString(0, 50, countStr);

#endif

display.display();

// Serial output

Serial.print("Update ");

Serial.print(updateCounter);

Serial.print(": ");

Serial.print(tempStr);

Serial.print(", ");

Serial.print(pressStr);

Serial.println();

delay(2000); // Update every 2 seconds

}

You can use MeshCom 4.0 with the WEbFlasger https://esptool.oevsv.at

Heltec LoRa V3 using Arduino IDE 2.3.5 ESP32 core 3.2.0 display BMP280 results on OLED

// Heltec LoRa V3 OLED and BMP280 test

/* Interfacing Arduino with BMP280 temperature and pressure sensor.
 * Temperature and pressure values are displayed on 16x2 LCD.
 * This is a free software with NO WARRANTY.
 * https://simple-circuit.com/
 */

// BMP280 setup

#include <Wire.h>             // include Wire library, required for I2C devices
#include <Adafruit_Sensor.h>  // include Adafruit sensor library
#include <Adafruit_BMP280.h>  // include adafruit library for BMP280 sensor

// define device I2C address: 0x76 or 0x77 (0x77 is library default address)
#define BMP280_I2C_ADDRESS 0x76

Adafruit_BMP280 bmp280;

// OLED setup
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display1 width, in pixels
#define SCREEN_HEIGHT 64  // OLED display1 height, in pixels

// Declaration for an SSD1306 display1 connected to I2C (SDA, SCL pins)
#define SCREEN_ADDRESS 0x3C  //0x3D ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
// use Wire1 for OLED display as BMP280 is using Wire and would conflict (only one works)
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire1, RST_OLED);

void setup() {
  Serial.begin(115200);

  Serial.println(F("Heltec LoRa V3 OLED and BMP280"));
  if (!bmp280.begin(BMP280_I2C_ADDRESS)) {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1)
      ;
  }
  Serial.println("Found BMP280 sensor!");

  // OLED setup
  // setup OLED display
  Wire1.begin(SDA_OLED, SCL_OLED);
  // SSD1306_SWITCHCAPVCC = generate display1 voltage from 3.3V internally
  if (!display1.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;  // Don't proceed, loop forever
  }
  Serial.println(F("SSD1306 allocation OK"));
  // Show initial display1 buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  //display1.display();
  delay(2000);  // Pause for 2 seconds
  display1.clearDisplay();
  display1.setTextSize(2);               // Normal 1:1 pixel scale
  display1.setTextColor(SSD1306_WHITE);  // Draw white text
  display1.setCursor(0, 0);              // Start at top-left corner
  display1.println(F("   Heltec V3\n    BMP280"));
  display1.display();
  delay(2000);
}

void loop() {
  // BMP280 get temperature, pressure and altitude from library
  float temperature = bmp280.readTemperature();    // get temperature
  float pressure = bmp280.readPressure();          // get pressure
  float altitude_ = bmp280.readAltitude(1013.25);  // get altitude (this should be adjusted to your local forecast)
  // print data on the serial monitor software
  // 1: print temperature
  Serial.print("Temperature = ");
  Serial.print(temperature);
  Serial.println(" °C");
  // 2: print pressure
  Serial.print("Pressure    = ");
  Serial.print(pressure / 100);
  Serial.println(" hPa");
  // 3: print altitude
  Serial.print("Approx Altitude = ");
  Serial.print(altitude_);
  Serial.println(" m");

// display results on OLED
  Serial.println();         // start a new line
  display1.clearDisplay();  // Dsiplay information
  display1.setTextSize(1);
  display1.setCursor(0, 0);
  display1.println("Heltec BMP280\n");
  //display1.setCursor(0, 20);
  display1.printf("Temperature %.2f\n\n", temperature);
  //  display1.setCursor(0, 40);
  display1.printf("Pressure %.2f\n\n", pressure);
  display1.display();
  delay(2000);  // wait 2 seconds
}

Serial monitor output
Heltec LoRa V3 OLED and BMP280
Found BMP280 sensor!
SSD1306 allocation OK
Temperature = 22.49 °C
Pressure = 1013.84 hPa
Approx Altitude = -4.91 m

Temperature = 23.89 °C
Pressure    = 1013.82 hPa
Approx Altitude = -4.71 m

Temperature = 25.53 °C
Pressure    = 1013.67 hPa
Approx Altitude = -3.53 m

Temperature = 26.24 °C
Pressure    = 1013.62 hPa
Approx Altitude = -3.04 m

Temperature = 26.61 °C
Pressure    = 1013.55 hPa
Approx Altitude = -2.49 m

Temperature = 26.88 °C
Pressure    = 1013.54 hPa
Approx Altitude = -2.42 m

Temperature = 26.26 °C
Pressure    = 1013.66 hPa
Approx Altitude = -3.42 m

Temperature = 25.78 °C
Pressure    = 1013.71 hPa
Approx Altitude = -3.84 m

image

Hi C,
Old post, but I just bumped into it.
I’ve been trying to get my latest Heltec boards to work, they’re 3.2 version, and your code works, thanks.
C

Hi,
In case anyone is still reading this:
I spent a long time trying to get 3.1 codes to work with 3.2 heltecs, and di get them to work but because this needs two sets of libraries, it isn’t viable.
I also got the 3.2 to work with no screen library, and this code also worked with 3.1.
Anyway, I returned the 3.2s and re ordered a couple of 3.1, for simpicity.
C

They are revisions of the board, not different models, by now, years on, the chances of anyone having older stock is vanishingly close to zero.

I have mixture of v2, v3.1 & v3.2’s in the lab, yes there are differences but also, yes I can use them with consideration of any subtle but important differences.

Perhaps you could succinctly provide the minimum code that causes issue between 3.1 and 3.2.

Hi N,
Perhaps you could succinctly provide the minimum code that causes issue between 3.1 and 3.2.

I’m no programmer, and this is why I am using AI to code for me.
I had programs working ok on sets of V3 3.1 modules, then suddenly the screen didn’t work, because I bought 3.2, I searched for answers and did lots of tests, adding more libraries till the screen worked, then it didn’t and so on. So I can’t really answer you question. All I can say is, I guess that each code chooses the screen settings from its array of libraries, and may result in screen or no screen.
My simple answer is, for me to empty all libraries, choose one board (3.1) and one library, that works and stay with that.
c.

Seems you’re screwed on two levels:

  • You won’t be able to get 3.1 versions boards
  • You don’t seem able to ask AI for some test code, run it on both boards, share it and tell us what happened

Good luck

Hi N,
Once I receive the return payment from the 3.2s I’ll buy the 3.1s in my basket.

I can ask the AI, but for what point? I’m only going to use the existing working codes that need fewer libraries when using only one type of board.
C

Hi again N,
I asked AI to write code with no screen library, here:
C
: // Heltec WiFi LoRa 32 V3.1 / V3.2 OLED pins
#define OLED_SDA 17
#define OLED_SCL 18
#define OLED_RST 21
#define VEXT_PIN 10
#define OLED_ADDR 0x3C

// — Minimal I2C bit-bang (no Wire.h) —
void i2c_delay() { delayMicroseconds(5); }

void i2c_start() {
pinMode(OLED_SDA, OUTPUT);
digitalWrite(OLED_SDA, HIGH);
digitalWrite(OLED_SCL, HIGH);
i2c_delay();
digitalWrite(OLED_SDA, LOW);
i2c_delay();
digitalWrite(OLED_SCL, LOW);
}

void i2c_stop() {
digitalWrite(OLED_SDA, LOW);
digitalWrite(OLED_SCL, HIGH);
i2c_delay();
digitalWrite(OLED_SDA, HIGH);
i2c_delay();
}

void i2c_write_byte(uint8_t b) {
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(OLED_SDA, (b & 0x80) ? HIGH : LOW);
digitalWrite(OLED_SCL, HIGH);
i2c_delay();
digitalWrite(OLED_SCL, LOW);
b <<= 1;
}
pinMode(OLED_SDA, INPUT_PULLUP); // ACK ignored
digitalWrite(OLED_SCL, HIGH);
i2c_delay();
digitalWrite(OLED_SCL, LOW);
pinMode(OLED_SDA, OUTPUT);
}

void oled_cmd(uint8_t c) {
i2c_start();
i2c_write_byte(OLED_ADDR << 1);
i2c_write_byte(0x00);
i2c_write_byte©;
i2c_stop();
}

void oled_data(uint8_t d) {
i2c_start();
i2c_write_byte(OLED_ADDR << 1);
i2c_write_byte(0x40);
i2c_write_byte(d);
i2c_stop();
}

// — Minimal 5x7 font (A–Z + space) —
const uint8_t font5x7[][5] = {
{0,0,0,0,0}, // space
{0x7E,0x11,0x11,0x11,0x7E}, // A
{0x7F,0x49,0x49,0x49,0x36}, // B
{0x3E,0x41,0x41,0x41,0x22}, // C
{0x7F,0x41,0x41,0x22,0x1C}, // D
{0x7F,0x49,0x49,0x49,0x41}, // E
{0x7F,0x09,0x09,0x09,0x01}, // F
{0x3E,0x41,0x49,0x49,0x7A}, // G
{0x7F,0x08,0x08,0x08,0x7F}, // H
{0x00,0x41,0x7F,0x41,0x00}, // I
{0x20,0x40,0x41,0x3F,0x01}, // J
{0x7F,0x08,0x14,0x22,0x41}, // K
{0x7F,0x40,0x40,0x40,0x40}, // L
{0x7F,0x02,0x04,0x02,0x7F}, // M
{0x7F,0x04,0x08,0x10,0x7F}, // N
{0x3E,0x41,0x41,0x41,0x3E}, // O
{0x7F,0x09,0x09,0x09,0x06}, // P
{0x3E,0x41,0x51,0x21,0x5E}, // Q
{0x7F,0x09,0x19,0x29,0x46}, // R
{0x46,0x49,0x49,0x49,0x31}, // S
{0x01,0x01,0x7F,0x01,0x01}, // T
{0x3F,0x40,0x40,0x40,0x3F}, // U
{0x1F,0x20,0x40,0x20,0x1F}, // V
{0x7F,0x20,0x18,0x20,0x7F}, // W
{0x63,0x14,0x08,0x14,0x63}, // X
{0x07,0x08,0x70,0x08,0x07}, // Y
{0x61,0x51,0x49,0x45,0x43} // Z
};

void draw_char(char c) {
if (c == ’ ') {
for (int i = 0; i < 6; i++) oled_data(0x00);
return;
}
if (c >= ‘A’ && c <= ‘Z’) {
const uint8_t* p = font5x7[c - ‘A’ + 1];
for (int i = 0; i < 5; i++) oled_data(p[i]);
oled_data(0x00);
}
}

void draw_text(const char* s) {
oled_cmd(0xB0 | 0); // page 0
oled_cmd(0x00);
oled_cmd(0x10);
while (*s) draw_char(*s++);
}

void oled_clear() {
for (uint8_t page = 0; page < 8; page++) {
oled_cmd(0xB0 | page);
oled_cmd(0x00);
oled_cmd(0x10);
for (uint8_t col = 0; col < 128; col++) oled_data(0x00);
}
}

// — Common unlock + safety preamble —
void oled_unlock_and_reset() {
// Hard reset pulse
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(50);
digitalWrite(OLED_RST, HIGH);
delay(50);

// Unlock + DC-DC ON (Heltec / clone-safe)
oled_cmd(0xAE); // display off
oled_cmd(0xFD); oled_cmd(0x12); // unlock command set
oled_cmd(0xAD); oled_cmd(0x8B); // DC-DC on
delay(20);
}

// — V3.1 profile (bright, known-good) —
void oled_init_v31(uint8_t contrast) {
oled_unlock_and_reset();

oled_cmd(0xD5); oled_cmd(0x80);
oled_cmd(0xA8); oled_cmd(0x3F);
oled_cmd(0xD3); oled_cmd(0x00);
oled_cmd(0x40);
oled_cmd(0x8D); oled_cmd(0x14);
oled_cmd(0x20); oled_cmd(0x00);
oled_cmd(0xA1);
oled_cmd(0xC8);
oled_cmd(0xDA); oled_cmd(0x12);
oled_cmd(0x81); oled_cmd(contrast); // e.g. 0xFF
oled_cmd(0xD9); oled_cmd(0xF1);
oled_cmd(0xDB); oled_cmd(0x40);
oled_cmd(0xA4);
oled_cmd(0xA6);
oled_cmd(0xAF);
}

// — V3.2 profile (safe, starts from dull baseline) —
void oled_init_v32(uint8_t contrast) {
oled_unlock_and_reset();

oled_cmd(0xD5); oled_cmd(0x80);
oled_cmd(0xA8); oled_cmd(0x3F);
oled_cmd(0xD3); oled_cmd(0x00);
oled_cmd(0x40);
oled_cmd(0x8D); oled_cmd(0x14);
oled_cmd(0x20); oled_cmd(0x00);
oled_cmd(0xA1); // keep mapping same as working dull config
oled_cmd(0xC8);
oled_cmd(0xDA); oled_cmd(0x12);
oled_cmd(0x81); oled_cmd(contrast); // start from 0xCF, try upwards
oled_cmd(0xD9); oled_cmd(0x22); // working dull pre-charge
oled_cmd(0xDB); oled_cmd(0x40);
oled_cmd(0xA4);
oled_cmd(0xA6);
oled_cmd(0xAF);
}

void setup() {
// Power OLED
pinMode(VEXT_PIN, OUTPUT);
digitalWrite(VEXT_PIN, HIGH);
delay(100);

// Prepare I2C pins
pinMode(OLED_SDA, OUTPUT);
pinMode(OLED_SCL, OUTPUT);
digitalWrite(OLED_SDA, HIGH);
digitalWrite(OLED_SCL, HIGH);

bool isV32 = true; // <-- set per board
uint8_t contrast = 0xCF; // V3.2: start from known-working dull value

if (isV32) {
oled_init_v32(contrast);
} else {
oled_init_v31(0xFF);
}

oled_clear();
if (isV32) {
draw_text(“HELTEC V3.2 SAFE”);
} else {
draw_text(“HELTEC V3.1 SAFE”);
}
}

void loop() {
}

Which basket allows you to buy something that’s not been made for years?

Which bit of the evolution of hardware revisions over time don’t you understand?

WHY??? Why would you not just use a good known library - what were you thinking when you asked for a bit-banged I2C library - this is totally irrelevant to the matter at hand. How the I2C is implemented isn’t relevant.

All we need is an example of what works for v3.1 and what happens when you try it on a v3.2 board.

If you want assistance, do not add needless complexity or bright ideas to the situation. Just tell us what code you have - you imply you have some code that works - why can’t you just share it?

Hi N,
Which bit of the evolution of hardware revisions over time don’t you understand?
All of it, I’m not clever with all of this. You are obviously at a much higher level than me.

Anyway, I’ve solved my problem, so I’ll leave it here, and thanks for trying.
C

Heltec found issues with the hardware design of v3.1 so they made manufacturing changes and came up with v3.2

At which point, they stopped making v3.1’s and only made v3.2’s

This was years back, so the likelihood of you being able to buy v3.1’s is vanishingly small.

Many online vendors are lazy and don’t update their imagery.

Is that clearer?

But as you say you are sorted, I guess you must have code that works on both.

Hi N,
Heltec found issues with the hardware design of v3.1 so they made manufacturing changes and came up with v3.2
Perhaps this is why I’ve had problems?

I buy them from aliexpress. I see that V3.1 is shown at the first image, then at checkout 3.1 has gone, but the chips etc are in the same place, so I’ve messaged the vendors for clarity.

I only have code that works reliably with V3.1 modules. With V3.2 the screen is intermittent.

C.

Maybe but unlikely - we don’t know why they changed stuff but I do know that I have v2, v3.1 and v3.2 lying around the place and use them as I need.

Even if you can’t get AI to remove the extras, if it was shared, someone that can program cast an eye over it for debugging.