HelTecAutomation / Heltec_ESP32

Arduino library for Heltec ESP32 (or ESP32+LoRa) based boards
Other
580 stars 219 forks source link

use own Oled 0.96" on Wireless Stick Lite - 'class Heltec_ESP32' has no member named 'display' #74

Open tis-cs opened 2 years ago

tis-cs commented 2 years ago

Hi, I alway get an error by compiling the OLED_LoRa_Receiver Sketch on my Lite-Stick. Any suggestions to solve it?

`Arduino: 1.8.16 (Windows 10), Board: "Wireless Stick Lite, Disabled, 240MHz (WiFi/BT), 921600, None, REGION_EU868, None"

\\Mac\Home\Documents\Arduino\libraries\Heltec_ESP32_Dev-Boards\examples\LoRa\OLED_LoRa_Receiver\OLED_LoRa_Receiver.ino: In function 'void logo()':

OLED_LoRa_Receiver:29:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->clear();

OLED_LoRa_Receiver:30:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawXbm(0,5,logo_width,logo_height,logo_bits);

OLED_LoRa_Receiver:31:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->display();

\\Mac\Home\Documents\Arduino\libraries\Heltec_ESP32_Dev-Boards\examples\LoRa\OLED_LoRa_Receiver\OLED_LoRa_Receiver.ino: In function 'void LoRaData()':

OLED_LoRa_Receiver:35:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->clear();

OLED_LoRa_Receiver:36:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);

OLED_LoRa_Receiver:36:36: error: 'TEXT_ALIGN_LEFT' was not declared in this scope

   Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);

OLED_LoRa_Receiver:37:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->setFont(ArialMT_Plain_10);
OLED_LoRa_Receiver:37:27: error: 'ArialMT_Plain_10' was not declared in this scope

   Heltec.display->setFont(ArialMT_Plain_10);

OLED_LoRa_Receiver:38:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawString(0 , 15 , "Received "+ packSize + " bytes");

OLED_LoRa_Receiver:39:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawStringMaxWidth(0 , 26 , 128, packet);
OLED_LoRa_Receiver:40:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawString(0, 0, rssi);  
OLED_LoRa_Receiver:41:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->display();

\\Mac\Home\Documents\Arduino\libraries\Heltec_ESP32_Dev-Boards\examples\LoRa\OLED_LoRa_Receiver\OLED_LoRa_Receiver.ino: In function 'void setup()':

OLED_LoRa_Receiver:56:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->init();

OLED_LoRa_Receiver:57:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->flipScreenVertically();  

OLED_LoRa_Receiver:58:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->setFont(ArialMT_Plain_10);

OLED_LoRa_Receiver:58:27: error: 'ArialMT_Plain_10' was not declared in this scope

   Heltec.display->setFont(ArialMT_Plain_10);

OLED_LoRa_Receiver:61:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->clear();

OLED_LoRa_Receiver:63:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawString(0, 0, "Heltec.LoRa Initial success!");

OLED_LoRa_Receiver:64:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->drawString(0, 10, "Wait for incoming data...");

OLED_LoRa_Receiver:65:10: error: 'class Heltec_ESP32' has no member named 'display'

   Heltec.display->display();

exit status 1

'class Heltec_ESP32' has no member named 'display'

`

Thanks in advance

MURPHYENGINEERING commented 2 years ago
  1. Why can't I use Heltec.display with the Wireless Stick Lite?
  2. How do I enable my OLED?
  3. How do I find the I2C address?
  4. Why does my module say the address is 0x78 if it's actually 0x3C?

Hope that helps!


Why can't I use Heltec.display with the Wireless Stick Lite?

The display is declared on this line:

https://github.com/HelTecAutomation/Heltec_ESP32/blob/e17ad84ccf4964718a62ec1c17d891a096876b9f/src/heltec.h#L32

and enabled by this line:

https://github.com/HelTecAutomation/Heltec_ESP32/blob/e17ad84ccf4964718a62ec1c17d891a096876b9f/src/heltec.cpp#L12

This is only enabled when Wireless_Stick is defined, which is done in the board variant:

pins_arduino.h#L6: #define Wireless_Stick true

But you can't just enable this on the wireless stick lite because that board variant doesn't define SDA_OLED, SCL_OLED, RST_OLED in pins_arduino.h.

And if you look at the pinout for the wireless stick, OLED_RST is on 16; but on the wireless stick lite pin 16 is the chip select for the flash memory. Also, the OLED on the wireless stick is initialized as 64x32 pixels, but the 0.96" OLED is 128x64 pixels.

Solution:

You need to make sure that your OLED module uses the SSD1306 driver chip--it almost certainly does. You can reuse the driver from the Heltec library, but you need to set your own pins and the correct I2C address for the OLED module you have.

The 0.96" OLED is 128x64 pixels, which is the default argument in the constructor:

https://github.com/HelTecAutomation/Heltec_ESP32/blob/e17ad84ccf4964718a62ec1c17d891a096876b9f/src/oled/SSD1306Wire.h#L47

so you can just write

SSD1306Wire *display = new SSD1306Wire(i2c_address, sda_pin, scl_pin, rst_pin);

I2C slave address

The I2C address for the SSD1306 can be either 0x3C or 0x3D. You can find out which by guessing, or it's probably printed on your board somewhere, or it's probably on the product page. If it says 0x78 then you need to use 0x3C; if it says 0x7A then use 0x3D (explanation below).

You can also find the slave address by looking at the schematic for your board:

From the SSD1306 datasheet (p. 19):

8.1.5 MCU I2C Interface a) Slave address bit (SA0) SSD1306 has to recognize the slave address before transmitting or receiving any information by the I2C-bus. The device will respond to the slave address following by the slave address bit (“SA0” bit) and the read/write select bit (“R/W#” bit) with the following byte format, 0 1 1 1 1 0 SA0 R/W# “SA0” bit provides an extension bit for the slave address. Either “0111100” or “0111101”, can be selected as the slave address of SSD1306. D/C# pin acts as SA0 for slave address selection.

Looking at the Adafruit breakout boards for example:

On the STEMMA QT version (schematic) the slave address is set by pulling the SA0 pin to high, with a disconnected jumper to ground. So the address is 0b0111101 (0x3D), and soldering the jumper closed will change the address to 0x3C.

Screen Shot 2021-11-11 at 11 48 43 AM

Why does my board say 0x78 if the address is 0x3C?

Look at the line from the datasheet shown above: 0 1 1 1 1 0 SA0 R/W# When we send an address byte to the SSD1306, the first 7 bits are the slave address and the 8th bit is the read/write flag. 0x3C is the value of the 7 bit slave address, but if we shift that to the left by one bit to make room for the R/W bit, then that becomes 2 * 0x3C = 0x78.

You can see how this is implemented in the espressif/arduino-esp32 core:

esp32-hal-i2c.c#L158:

ret = i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, true);

Since the address is shifted by the I2C library, you need to initialize it with the 7 bit value. So if the board says 0x78 or 0x7A then the address you use is 0x3C or 0x3D.

tis-cs commented 2 years ago

@MURPHYENGINEERING Thanks a lot for your detailed answer but until now I didn't get it running...

Do I have just to replace L47 and set my own defined pins instead of "i2c_address etc. like SSD1306Wire *display = new SSD1306Wire(0X3C, 15, 4, 9); and comment out L48-55?

Because this doesn't work in my case.

Would it be possible that you will show me the whole SSD1306Wire.h?

Other question: would it also be possible to just add a new definition like #elif defined( Wireless_Stick_Lite ) display = new SSD1306Wire(0x3c, 15, 4, 9, GEOMETRY_128_64);

and add some || defined( Wireless_Stick_Lite ) in L49, L72, L82 and L95 in heltec.ccp?

Thanks in advance!

MURPHYENGINEERING commented 2 years ago

Hi @tis-cs, sorry it's still not working for you, I'm sure that's frustrating to still be stuck with it.

I'll need some more info; you can find my questions in the second topic here:


Would it be possible that you will show me the whole SSD1306Wire.h?

You can see the complete SSD1306 driver here.

How can I implement my own instance of SSD1306Wire?

I don't recommend putting your changes in the existing files (e.g. Heltec.h/cpp); if you ever update your libraries then your changes will be lost, and if you ever use another board then you might produce a confusing bug when the #defines change.

You can just add this to the top of your own source file:

#include "oled/SSD1306Wire.h"
SSD1306Wire *display = new SSD1306Wire(0X3C, 15, 4, 9);

If you need to use the display in multiple files then you can put that line in each one, or you can declare it in a header:

// display.h
#ifndef DISPLAY_H
#define DISPLAY_H

#ifdef Wireless_Stick_Lite

  #define OLED_I2C_ADDR 0x3C
  #define OLED_PIN_SDA  15
  #define OLED_PIN_SCL  4
  #define OLED_PIN_RST  9

#endif // Wireless_Stick_Lite

#include "oled/SSD1306Wire.h"
extern SSD1306Wire* display;

#endif // DISPLAY_H
// display.cpp
#include "display.h"

#ifdef Wireless_Stick_Lite

  SSD1306Wire* display = new SSD1306Wire(
    OLED_I2C_ADDR, 
    OLED_PIN_SDA, 
    OLED_PIN_SCL, 
    OLED_PIN_RST
  );

#else

  #include "Heltec.h"
  SSD1306Wire* display = Heltec.display;

#endif

and just #include "display.h" whenever you need to use it.

Why isn't it working for my OLED?

According to the pinout, the pins you chose should be okay to use. I looked through the Heltec library and they don't appear to be used anywhere. Two things to note:

I can't say anything else without seeing your code and what module you have/how it's wired up. See if you can provide a minimum working example (a complete program that does nothing except try to use the OLED, use gist.github.com) and a link to the module you have.

You can try something like this to see if anything is happening on the pins that you don't expect.