Problem using Teensy 4.0 with 2.42" Oled and u8g2 or Adafruit Library

Status
Not open for further replies.

guzu

Well-known member
Hello.

I am trying to use an 2.42" Oled display with a Teensy 4.0 and the u8g2 Library.
No matter how I try, I cannot make the Oled to work properly. When I use the u8g2 Library, I get the following result: The Oled displays what I code, but it permanently displays some horizontal lines. The lines do not disappear no matter what I try.
Here is an image: (I know that the text is upside down and I have solved that issue.)
IMG_0717.jpg

And I tried to reduce the code to the smallest possible to try to find out what is wrong:

Code:
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif



//U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 27, /* dc=*/ 34, /* reset=*/ 24);	
U8G2_SSD1309_128X64_NONAME0_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 27, /* dc=*/ 34, /* reset=*/ 24);  

void setup(void) {
  u8g2.begin();
}

void loop(void) {
}

I still get only the horizontal lines on the Oled:
IMG_0731.jpg

When I try to use the Adafruit 1306 Library, I get the following result:
IMG_0733.jpg

I use the hardware SPI on the Teensy and I have the following Oled display:
IMG_0718.jpg

When I use the display on an Arduino, it works properly. I even tried using another display just like this one with the Teensy to make sure is not the display and it has the same issue.
Could anyone tell me what I should do to get the Oled to work properly?

Thank you very much in advance for your time.
 
Last edited:
Just a quick question are you sure you are suppose to be using a SSD1306 library? The back of the display says its a SSD1309. It looks like this one I found on amazon: https://www.amazon.com/Diymore-Digital-Display-SSD1309-Electronic/dp/B07XRFFPCT?th=1. Also what mode are you running SPI or I2C. Looks like you have it set up for SPI.

You are not showing how you have it connected to the Teensy 4.0.

Just a guess but looking at the u8g2 library its not compatible with the Teensy 4.0, in other words it has not been ported over. If you are using a SSD1306 library it may not be 100% compatible with the SSD1309. You could try using the Sparkfun SSD1309 library: https://github.com/sparkfun/HyperDisplay_SSD1309_ArduinoLibrary/tree/master/src.
 
Just a quick question are you sure you are suppose to be using a SSD1306 library? The back of the display says its a SSD1309. It looks like this one I found on amazon: https://www.amazon.com/Diymore-Digital-Display-SSD1309-Electronic/dp/B07XRFFPCT?th=1. Also what mode are you running SPI or I2C. Looks like you have it set up for SPI.

You are not showing how you have it connected to the Teensy 4.0.

Just a guess but looking at the u8g2 library its not compatible with the Teensy 4.0, in other words it has not been ported over. If you are using a SSD1306 library it may not be 100% compatible with the SSD1309. You could try using the Sparkfun SSD1309 library: https://github.com/sparkfun/HyperDisplay_SSD1309_ArduinoLibrary/tree/master/src.

Thank you for the reply.
The u8g2 Library has a constructor for SSD1309 oleds. But it gives the same result.
I use the SPI setup.
VCC - 3.3V
GND - GND
SCL - 13 (SCK)
SDA - 11 (MOSI)
RES - 24
DC - 34
CS - 27

Do you have any ideea if the library will be ported to the Teensy 4.0? Is there any oled library that is already portedfor Teensy 4.0? I read on the forums that other users used the u8g2 library with no problem on older teensy boards.(like the 3.2 and 3.5)

Thank you very much.
 
As for things like when... Often depends on who is the owner of the library, also depends on someone needing it. And then hopefully the person needing it, figures out what is needed and contacts the owner of the library....

As for this specific library, hard to say, the only mention I noticed in the beta for T4 was the posting: https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=210723&viewfull=1#post210723


As for other libraries, again as mentioned, it looks like Sparkfun has something? Also it might be interesting to see if one can figure out what the differences are from the 1306, to see how hard it might be to for example adapt the Adafruit library or the Sumotoy (https://github.com/sumotoy/OLED_SSD1306) but warning Sumotoy has not been active for several years now.
 
I'm curious. Try underclocking the teensy @ 150 and 396. Does the issue persist? You might also check into using littlevgl lib.
This link pertains to T3.6 but may be relevant to yr issue: https://github.com/olikraus/u8g2/issues/336

I tried to underclock the Teensy all the way to 24MHz. (Using the Arduino IDE > Tools > CPU Speed option.) The horizontal lines are still there.

@KurtE The mention regarding u8g2 Library working is related to the Oled working on I2C, not SPI. I am interested in using SPI. If there is no way that I can get it to work on SPI, I will try I2C.

Is there any Oled library that is known to work with the Teensy 4.0 and an Oled on SPI?

Thanks.
 
VCC - 3.3V
GND - GND
SCL - 13 (SCK)
SDA - 11 (MOSI)
RES - 24
DC - 34
CS - 27
Pins 34, 24, and 27 on the T4.0 are on the underside of the T4. 34 is on one of the 1mm pads are you really using the pins on the underside of the board. Suggest that you Rst = 8, DC = 9 and CS = 10 as a quick test. Recommend you try this pin connection

Second, @KurtE and I both mentioned:
it supports both I2C and SPI - have you tried this library yet.
 
Pins 34, 24, and 27 on the T4.0 are on the underside of the T4. 34 is on one of the 1mm pads are you really using the pins on the underside of the board. Suggest that you Rst = 8, DC = 9 and CS = 10 as a quick test. Recommend you try this pin connection

Second, @KurtE and I both mentioned:
it supports both I2C and SPI - have you tried this library yet.

I tried to test the Oled using the other pins and it had the same issue with the u8g2 Library. However, it seems that the Sparkfun SSD1309 library IS WORKING JUST FINE. :D
Thank you very much. Now I just have to learn to use the Sparkfun Library.

Anyway, if anyone knows how I can use the u8g2 Library successfully I would really appreciate it as I have the code written already.
 
Sorry, not sure what I can do here...

I don't have an SSD1309, and I did verify that SSD1306 with SPI at least for drawing the logo example appears to work on T4. At least the 128x64 one I dug out of my parts box.

As for SSD1309 don't have one so can not verify they work properly.

If it were me, might suggest trying out on a different MicroCOntroller to see if it works there.
 
So after many discussions and tests, it seems that this is a problem with the HW SPI code for the Teensy 4.0.
If I use the exact same pins (SCK 13, MOSI 11, etc) with the SW SPI constructor to drive the oled, everything works fine (just slower due to the software SPI).

You can follow the tests I made with the help of the developer of the u8g2 library here.

Could anyone help me figure why the HW SPI is not working properly with the SSD1306 Oled connected to HW SPI?
I have also posted a possible Issue on the GitHub SPI library for the Teensy.

Thank you very much for all your input.
 
If I or anyone else where wanted to work on this problem, which display should we buy? The only one I've seen so far is this from Sparkfun, which has I2C interface, not SPI.

https://www.sparkfun.com/products/15173


This is the display I bought.
Here you can find another link to the same display sold by another vendor.
Here is a link to some documentation.

Thank you for looking into this.

One question regarding the SPI. Could I use the same pins for SW SPI (to drive the oled) and HW SPI to drive other modules (NRF24L01+)? SCK 13, MOSI 11?
 
I tried to test the Oled using the other pins and it had the same issue with the u8g2 Library. However, it seems that the Sparkfun SSD1309 library IS WORKING JUST FINE. :D

Is there any reason to believe the u8g2 problem is with Teensy's SPI library, or other code provided by Teensyduino?
 
I just ordered one from Amazon... Maybe here tomorrow...

I suspect it may be more of an issue of which MODE does the display use?
SPI_MODE0, SPI_MODE1... 3 ?

The only caveat here than is sometimes needing to do a dummy SPI transfer to change the actual pins for the different mode...
 
One of the things I saw in issue you posted to the U8G2 library is that they suggested changing the SPI Clock and Mode for the display. Not sure what you changed them too but looking at the SSD1309 that you said works has the following settings:
Code:
#define UG2856KLBAG01_SPI_FREQ_MAX 	8000000	// once tested up to 10 MHz
#define UG2856KLBAG01_SPI_MODE 		SPI_MODE3
for the clock and mode. Note: the SPI Clock is not the same as the CPU clock. So if you set it to 24mhz it wouldn't work. Try these settings with the U8G2 library.

EDIT: Ordered one as well.
 
Quick update. olikraus wrote to change SPI:

Code:
SPI Modes are 0 to 3 and can be modified by changing the u8g2 code:
Here
https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_ssd1309.c#L146
and here:
https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_ssd1309.c#L245

The change would be from what is there now:
Code:
/* spi_mode = */ 0,
to
Code:
/* spi_mode = */ [COLOR="#FF0000"]3[/COLOR],
. Give it a try and see what happens
 
Quick update. olikraus wrote to change SPI:

The change would be from what is there now:
Code:
/* spi_mode = */ 0,
to
Code:
/* spi_mode = */ [COLOR="#FF0000"]3[/COLOR],
. Give it a try and see what happens

I changed the code as you mentioned and IT WORKS! I changed the spi_mode = 3. Thank you very much.
What did it change? Just to know what is been eating my days :)

I am sorry that is was such a simple solution and I did not know how to implement it.
I will close the issue on the SPI library.

Thank you very very much for the information.
 
Quick FYI - The Adafruit_ssd1306 library works as well, if you edit the constructor sources and change SPI_MODE0 to SPI_MODE3.
 
Another update. I just put in a Pull Request to Adafruit_SSD1306 library that makese the spiSettings member variable protected instead of private.

This allowed me to then create a sub-class of the SSD1305 object which sets this to SPI_MODE3, which is working on my machine. The PR has been merged.

My test version for this looks like:
Code:
/**************************************************************************
 This is an example for our Monochrome OLEDs based on SSD1306 drivers

 Pick one up today in the adafruit shop!
 ------> http://www.adafruit.com/category/63_98

 This example is for a 128x64 pixel display using SPI to communicate
 4 or 5 pins are required to interface.

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source
 hardware by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries,
 with contributions from the open source community.
 BSD license, check license.txt for more information
 All text above, and the splash screen below must be
 included in any redistribution.
 **************************************************************************/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

class Adafruit_SSD1309_SPI : public Adafruit_SSD1306 {
 public:
  Adafruit_SSD1309_SPI(uint8_t w, uint8_t h, SPIClass *spi,
    int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate=8000000UL) :
    Adafruit_SSD1306(w, h, spi, dc_pin, rst_pin, cs_pin, bitrate) {
#ifdef SPI_HAS_TRANSACTION
  spiSettings = SPISettings(bitrate, MSBFIRST, SPI_MODE3);
#endif
      
    }
}; 

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
/*
// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
*/
///* Comment out above, uncomment this block to use hardware SPI
#define OLED_DC     6
#define OLED_CS     7
#define OLED_RESET  8
Adafruit_SSD1309_SPI display(SCREEN_WIDTH, SCREEN_HEIGHT,
  &SPI, OLED_DC, OLED_RESET, OLED_CS);
//*/

#define NUMFLAKES     10 // Number of snowflakes in the animation example

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

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

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }


  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}
 
Status
Not open for further replies.
Back
Top