Lightweight U8g2 version?

Hi,
I'm trying to use a single Arduino Uno board to drive 6 displays.
5 of them are 128x32 OLED I2C, and one is a 256x64 OLED SPI Display.

I've already working code for the first five display using Adafruit_GFX & Adafruit_SSD1306.

In a separate sketch I've the last display working with the U8g2 Library, but when merging code and libraries, I'll exceed the storage.... 102% ( damn! )

I was trying to use the same library for the bigger display, and I found this fork, that cold solve my problem and let me use the other display with the same base, but it's not working anymore:

Any idea if there is a U8g2 lighter version? I'm also open to any other options, but I would like to remain on Adafruit since I found the text font that I need for my projects!

Thanks

U8g2 is your only realistic choice of library.
It has excellent support of fonts and memory use.

Paste or attach your sketch. Choice of correct font makes a big difference e.g. number font vs regular or extended font.

David.

I need to replicate something like 14 segment display ( DIGIT14 ), like this: DSEG14.
With Adafruit I successfully get this kind of font working, that’s why I was looking to remain on that, but if I found something similar, I can switch the whole code.
My actual sketch also use an I2C multiplexer to use the 5 displays with different info, it’s possible to use in the same way the U8g2?

Attached it’s an example sketch on how i’m using multiple displays

EDIT: After playing a little bit with the U8g2 lib, I’m not really happy. The global variables increase a lot even using page mode instead full buffer, and adds a lot of unseeded “complication” on my code, and, most important, I can’t find a 14 Segments font, only available 7 bars that are able only to repoduce number, and it’s not what I need.

I also have problem with “hybrid” libs, there is some knows incompatibility to use Adafruit_GFX with Ug8 at the same time for two different displays?

Thanks

example_adafruit.ino (1.2 KB)

Looking for SSD1322 in the Library Manager U8g2lib is the only library.

Adafruit do not support SSD1322. And Adafruit's libraries always allocate a full buffer i.e. 2048 bytes for 256x64.
Nothing appears to support Grayscale on the SSD1322

You are not using separate objects for each screen. You switch the multiplexer. Clear the buffer and write fresh contents.

You can do something similar with U8g2 i.e. one 128x32 object and one 256x64 object.

D14SEG is your design choice. It is pretty ugly (for me).
Oliver does not seem to have an equivalent Font.

If you are only drawing text on the OLEDs there is no requirement for a buffer. Buffers are needed when you draw complex graphics e.g. crossing lines.

David.

p.s. online GFX Font creator is excellent.

Thanks for your feedback,
The final goal of the projects it's build Aircraft Panel replica, that's why I need a Digital 14 Bars font, it's not a really persona style choice :smiley:

btw...since with Adafruit GFX seems impossible to drive the large SSD1322 display, I'm trying to switch my code to UG8g2.

Any tips for constructor to save memory?
U8G2_SSD1322_NHD_256X64_1_4W_HW_SPI u8g2a(U8G2_R0, /* cs=/ 10, / dc=/ 9, / reset=/ 8);
U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2b(U8G2_R0, /
reset=/ U8X8_PIN_NONE, / clock=/ SCL, / data=*/ SDA);

I've warning for high memory usage and got unexpected screen behavior some times.

Also, I'm only going to write string on display, you say I don't need a buffer...so....which of following example are the "right" one according your suggestion? is the first one?

u8g2.firstPage();
do {
/* all graphics commands have to appear within the loop body. */
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(0,20,"Hello World!");
} while ( u8g2.nextPage() );

For Full buffer use the following function scheme must be used:
void loop(void) {
u8g2.clearBuffer();
// ... write something to the buffer
u8g2.sendBuffer();
delay(1000);
}

Ah-ha. If the original had "ugly" D14 font, you have no choice.

I will try it later. I have a 128x128 SSD1327 and a 128x32 SSD1306. So I can replicate your screen areas. Both of these are I2C.

Regarding screen draw. You use the firstPage() / nextPage() for buffered write.
The Uno has very little SRAM.

If memory is a problem, there are plenty of Uno format boards. And several Nano sized boards.

David.

Thanks again for your disposal to test on your devices, just little difference one of my display it's a SPI and not I2C.

btw......Can I use online GFX Font creator to make custom U8g2 fonts? it's not really good but it's have the DSEG14 Font, and if I remember well I also used for Adafruit GFX :wink:

Please try this sketch. Replace my constructor and draw() statements with the commented ones.

#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_1_4W_HW_SPI oled1(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
U8G2_SSD1327_MIDAS_128X128_1_HW_I2C oled2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C oled1(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1322_NHD_256X64_1_4W_HW_SPI oled2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

U8G2 *screen[] = { &oled1, &oled2, };      // access via pointer array

void setup(void)
{
    oled1.begin();
    oled2.begin();
    oled1.setFont(u8g2_font_ncenB14_tr);
    oled2.setFont(u8g2_font_fub14_tr);
}

void draw(U8G2 *s, int x1, int y1, char *msg1, int x2, int y2, char *msg2)
{
    s->firstPage();
    do {
        /* all graphics commands have to appear within the loop body. */
        s->drawStr(x1, y1, msg1);
        s->drawStr(x2, y2, msg2);
    } while ( s->nextPage() );
}

void loop(void)
{
    draw(screen[0], 0, 20, "SSD1306", 90, 30, "SPI");
    draw(screen[1], 20, 50, "SSD1327", 0, 80, "I2C interface");
//    draw(screen[0], 0, 20, "SSD1306", 90, 30, "I2C");
//    draw(screen[1], 20, 50, "SSD1322", 128, 60, "SPI interface");
    delay(1000);
}

My build says:

Using library U8g2 at version 2.24.3 in folder: C:\Users\David Prentice\Documents\Arduino\libraries\U8g2 
Using library SPI at version 1.0 in folder: C:\Program Files (x86)\Arduino-1.8.9\hardware\arduino\avr\libraries\SPI 
Using library Wire at version 1.0 in folder: C:\Program Files (x86)\Arduino-1.8.9\hardware\arduino\avr\libraries\Wire 
"C:\\Program Files (x86)\\Arduino-1.8.9\\hardware\\tools\\avr/bin/avr-size" -A "C:\\Users\\DAVIDP~1\\AppData\\Local\\Temp\\arduino_build_420137/Hello_u8g2_x2.ino.elf"
Sketch uses 13340 bytes (41%) of program storage space. Maximum is 32256 bytes.
Global variables use 1082 bytes (52%) of dynamic memory, leaving 966 bytes for local variables. Maximum is 2048 bytes.

Your build will use a bit more SRAM because the 1322 constructor has 256 byte buffer.

If you study Oliver’s Wiki, it probably shows you how to import a foreign font.
Otherwise someone might do it for you.

You still need to be careful with your SRAM usage.

David.

Thanks for sharing your code, it's really help me to adjust mine.

With your code I have 62% of SRAM occupied, with my full project I reach near 82%.

I Also found interesting think, using the multiplexer I need to cycle the begin() function for all screen. If I do only one time per screen, I'm not able to display anything on the screen after a booting from a completely power supply removing. Only work after "reset". If I cycle two time the same initialization function, works even after completely reboot.

I read a lot the Oliver's Wiki and I understand the workflow to include custom font, but I have some trouble since it's not compiling anymore using external fonts ( even not my fancy 14 bars but also the one provided in the example )

BTW...last question regarding U8g2, to save part of my code, I need a function that "write" new info on display without removing what is already displayed on it, like it's done on Adafruit GFX where I have to explicit clear display, it's possibile also on U8g2 ?

This is configured for your hardware. Just build and go.

#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_1_4W_HW_SPI oled1(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_SSD1327_MIDAS_128X128_1_HW_I2C oled2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C oled1(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1322_NHD_256X64_1_4W_HW_SPI oled2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

U8G2 *screen[] = { &oled1, &oled2, };      // access via pointer array

#define TCAADDR 0x70
void tcaselect(uint8_t i) {
    if (i > 7) return;
    Wire.beginTransmission(TCAADDR);
    Wire.write(1 << i);
    Wire.endTransmission();
}

void setup(void)
{
    for (int i = 0; i < 7; i++) {
        tcaselect(i);
        oled1.begin();  //init each hardware 128x32
    }
    oled2.begin(); //init single 256x64
    oled1.setFont(u8g2_font_ncenB14_tr); //single object
    oled2.setFont(u8g2_font_fub14_tr); //single object
}

void draw(U8G2 *s, int x1, int y1, char *msg1, int x2, int y2, char *msg2)
{
    s->firstPage();
    do {
        /* all graphics commands have to appear within the loop body. */
        s->drawStr(x1, y1, msg1);
        s->drawStr(x2, y2, msg2);
    } while ( s->nextPage() );
}

void loop(void)
{
    //draw(screen[0], 0, 20, "SSD1306", 90, 30, "SPI");
    //draw(screen[1], 20, 50, "SSD1327", 0, 80, "I2C interface");
    for (int i = 0; i < 7; i++) { //select each 128x32. write 0-6
        char buf[2];
        buf[0] = '0' + i;
        buf[1] = '\0';
        tcaselect(i);
        draw(screen[0], 0, 20, "SSD1306", 90, 30, buf);
        delay(1000);
    }
    draw(screen[1], 20, 50, "SSD1322", 128, 60, "SPI interface");
}

Regarding “old contents”. Remember data for each multiplexed 128x32. Redraw each time.

You can’t afford a pixel buffer for each 128x32.
But you can remember small char arrays. Or integer array that you convert to a single char array for printing.

It is always easier to show how to code something if you say what your typical outputs might be.

David.

Yeah, thanks for suggestion!
I’m saving all data to print out into two different array, and I’m printing the combined data on change instead only the new data coming from simulator :wink:

Playing with font converter, I also manage to “redraw” some characters to fit exactly the simulator, it’s amazing.

Thanks for your help!

Actually I wrote and tested the whole program with U8G2, using 59% of flash memory and 82% of dynamic memory. It’s seems stable, but maybe I’ve to replace it with U8X8 to save memory? Can help to reduce footprint on dynamic memory?

I need to print only “string”, some characters like @ and °, but I don’t have to draw line,circle or any other graphical elements. It’s a good Idea switch or is worth it?

Quite honestly, I would expect you to manage fine with the limited SRAM.
Just be careful with array types and sizes that are stored in SRAM.
Any const text strings can be stored in PROGMEM.

"Temporary" arrays can be on the stack. This lets you use the same memory for different functions.
It is not free. It will not appear in the build report.

From a brief glance at internal · olikraus/u8g2 Wiki · GitHub
you can convert any TTF font into the BDF format with a Unix utility.

I would develop the program first with regular fonts. e.g. to test all your multiplexed screens.

When fully debugged, you (or a reader) can create the necessary D14 font. (specify the exact size and style required)

David.

59% of flash memory and 82% of dynamic memory it's the full program, including all screens, switching with multiplexer, and my custom font D14 :wink:

I write it with U8G2 instead U8X8, and I was wondering if I need to change, or I can be "prod" of what I've done. So far I done some test and seems the 82% of SRAM occupied is not causing problems.

82% SRAM means 368 bytes free for the stack.

Only you know your own code style.

Typical projects never get much deeper than 8 functions on the stack.
And typical functions only store a few auto variables.
So 368 bytes is fairly safe.

A common trick is: You write a magic pattern on the available memory. Then inspect how deep the stack encroaches during a program run.

C Compilers like Codevision perform a static code analysis on every build.
This calculates for the deepest nest of calls and calculates the exact amount of local storage.
It can't cope with variadic or recursive code. (but it will find any recursion)

There are third party tools for GCC to do the same thing.

Quite honestly, a rule of thumb or a magic pattern is good enough.

How did you make your D14 font?
Can you post/attach it?

David.

david_prentice:
How did you make your D14 font?
Can you post/attach it?

I've finally found on FAQ of the U8G2 the way to make your own custom fonts.
The way is use Fony to create the .bdf, and then use bdfconv to crete the .c files.

Last tip, using Arduino IDE, I was facing problem compiling with custom fonts, solved using #include U8g2.h directly in top of the .c file generated by the conversion tool.

Starting font could be any font that you have installed on your computer, since I have played a lot I already have tons of digi fonts on my pc ahhahahaha :smiley:

Please attach your working D14 font.

I do not intend to learn Fony, bdfconv, ...

I would be interested in a step by step example for U8g2.
I generally use Adafruit FreeFonts. And can either create them myself or use the online tool from #3.

David.