C/C++ Question SSD1331 Library for SPI 16bit color oled

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

I've wrapped my ESP8266FastSSD1331 C++ library for 0.96 inch 16bit color oled, this worked, I can draw, print text, play short videoclips from flash memory etc... from B4R.

This library is very fast, works 8-10 times faster than any other library I've tried, eg Adafruit, Ucgl etc... this because I wrote directly ESP8266 registers and don't used slow digitalWrite command to write on GPIOs.

As results, it is easy to use and very fast, show videoclips from Flash and SD from 24 to 30 FPS with ESP8266 working from 80Mhz to 160Mhz, so fluid video, on my tests I draw a rotating cube wirefreme at 160 FPS working @80Mhz and 280 FPS working @160Mhz, so there is a sort of retina persistence because a very high framerate and uman eyes only see just a small part of these, so I need to add a delay to slow down the speed.

Datasheet on the hand (this required me a lot of work) I've implemented almost all SSD1331 Hardware implementation, and other functions not supported by other libraries, eg. set the 8bit contrast separately for R, G and B channels, set 4 bit oled brightness, draw rectangles with hardware optimization, copy a portion of screen using hardware optimization, not pixel by pixel, but eg. just one command to draw a rectangle.

This library even contain follow classes:
Color565 - this class expose 30 color costants and RGB method that converts 24 bit color (8:8:8) to 16 bit color (5:6:5)
MeterBar - this is a class for horizontal and vertical progress bars
ImageClip - this is a class to draw custom controls animations based on consecutive bitmap images, (eg you can draw a lamp on or off, a servo motor animation etc...)

Almost all methods of wrapper works, but my Oled is declared in the rESP8266FastSSD1331 library as private using (new) operator, but MeterBars and ImageClip classes expected a pointer to Oled, and if I declare my oled istance as public I've compilation error. Can anyone help me to know how to do it?

this is my original library begin methods to initialize that classes, as you see is expected an istance of oled as first argument:
B4X:
void MeterBar::begin(ESP8266_FastSSD1331* tOled, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorClear, uint16_t colorFill, uint16_t colorBorder, uint8_t strokeWidth)

void ImageClip::begin(ESP8266_FastSSD1331* tOled, const String supportType, const String fileName, uint32_t startFrame, uint32_t endFrame, uint8_t x, uint8_t y, uint8_t w, uint8_t h)
I opened all B4R libraries to figure out how it works, but I cannot ...

I've attached rESP8266FastSSD1331 Library with one working example.

Please help me to figure how pass an istance of a class to other classes inside a same library, in my case I need to pass oled istance... If I solve this and other related I can release a full library on this forums, anyway here I posted all code, but you can see MeterBar and ImageClip classes and all components, but can't Initialize because I've commented a line that is wrong, all others methods of oled works.

Many thanks
 

Attachments

  • rESP8266FastSSD1331.zip
    152.7 KB · Views: 746
  • BouncingBall.zip
    1.6 KB · Views: 637
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Here a small demo video.... but pretty low quality because I've used a phone camera....
 

max123

Well-Known Member
Licensed User
Longtime User
The screen is smaller than 1 EURO and has 65536 colors as show on this my other old demo video that uses slow library
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Many thanks Erel,

I've changed my header code this way like rLiquidCrystal library:
B4X:
#pragma once

#include "B4RDefines.h"
#include "ESP8266_FastSSD1331.h"
#include "Fonts.h"

//~version: 1.18
namespace B4R {
    //~shortname: ESP8266FastSSD1331
    class B4RESP8266FastSSD1331 {
 
      private:
         uint8_t backend[sizeof(ESP8266_FastSSD1331)];
 
      public:                          
         //~hide
         ESP8266_FastSSD1331* oled;

Then in .cpp file I've changed Initialize functions to:
B4X:
void B4RESP8266FastSSD1331::Initialize(uint8_t CS, uint8_t DC, uint32_t Freq) {
   oled = new (backend) ESP8266FastSSD1331();
   oled->begin(CS, DC);
   SPI.setFrequency(Freq);
}
void B4RESP8266FastSSD1331::Initialize1(uint8_t CS, uint8_t DC, uint8_t RST, uint32_t Freq) {
   oled = new (backend) ESP8266FastSSD1331();
   oled->begin(CS, DC, RST);
   SPI.setFrequency(Freq);
}
void B4RESP8266FastSSD1331::Initialize2(uint8_t CS, uint8_t DC, uint8_t MOSI, uint8_t CLK, uint8_t RST) {
   oled = new (backend) ESP8266FastSSD1331();
   oled->begin(CS, DC, MOSI, CLK, RST);
}

But I have these compilation errors:
B4R version: 2.00
Parsing code. (0.00s)
Compiling code. (0.05s)
Building project (0.06s)
Compiling & deploying Ino project (NodeMCU 1.0 (ESP-12E Module) - COM6) Error
Loading configuration...
Sto inizializzando i pacchetti...
Sto preparando le schede...
Sto verificando e caricando...
C:\PROGRA~1\ANYWHE~1\B4R\PROGETTI\ESEMPI~1\ESP826~1\ROTATI~1\Objects\bin\sketch\rESP8266FastSSD1331.cpp: In member function 'void B4R::B4RESP8266FastSSD1331::Initialize(uint8_t, uint8_t, uint32_t)':
rESP8266FastSSD1331.cpp:8: error: expected type-specifier before 'ESP8266FastSSD1331'
oled = new (backend) ESP8266FastSSD1331();
^
rESP8266FastSSD1331.cpp:8: error: expected ';' before 'ESP8266FastSSD1331'
C:\PROGRA~1\ANYWHE~1\B4R\PROGETTI\ESEMPI~1\ESP826~1\ROTATI~1\Objects\bin\sketch\rESP8266FastSSD1331.cpp: In member function 'void B4R::B4RESP8266FastSSD1331::Initialize1(uint8_t, uint8_t, uint8_t, uint32_t)':
rESP8266FastSSD1331.cpp:13: error: expected type-specifier before 'ESP8266FastSSD1331'
oled = new (backend) ESP8266FastSSD1331();
^
rESP8266FastSSD1331.cpp:13: error: expected ';' before 'ESP8266FastSSD1331'
C:\PROGRA~1\ANYWHE~1\B4R\PROGETTI\ESEMPI~1\ESP826~1\ROTATI~1\Objects\bin\sketch\rESP8266FastSSD1331.cpp: In member function 'void B4R::B4RESP8266FastSSD1331::Initialize2(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)':
rESP8266FastSSD1331.cpp:18: error: expected type-specifier before 'ESP8266FastSSD1331'
oled = new (backend) ESP8266FastSSD1331();
^
rESP8266FastSSD1331.cpp:18: error: expected ';' before 'ESP8266FastSSD1331'
exit status 1
expected type-specifier before 'ESP8266FastSSD1331'

By default I use this command to declare a library:
B4X:
ESP8266_FastSSD1331 oled = ESP8266_FastSSD1331();
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
You saved my life boy.... ;)

Changed it an now compile OK, but now how I can pass "oled" reference to begin methods? These not worked:
B4X:
 void B4RMeterBar::Initialize(uint8_t X, uint8_t Y, uint8_t Width, uint8_t Height, uint16_t ClearColor, uint16_t FillColor, uint16_t BorderColor, uint8_t BorderWidth) {
     meterbar->begin(B4RESP8266FastSSD1331::_oled, X, Y, Width, Height, ClearColor, FillColor, BorderColor, BorderWidth);     
}
void B4RImageClip::Initialize(B4RString* SupportType, B4RString* FileName, uint32_t StartFrame, uint32_t EndFrame, uint8_t X, uint8_t Y, uint8_t Width, uint8_t Height) {
     imageclip->begin(B4RESP8266FastSSD1331::_oled, SupportType->data, FileName->data, StartFrame, EndFrame, X, Y, Width, Height);     
}
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Without use MeterBar or ImageClip classes the project now compiles, if I use these classes all compiles, I can declare, then I call Initializer method, it pass an Oled instance to my library, ESP8266FastSSD1331.cpp file (MeterBar::begin function) and then on this line ESP8266 crashes:
B4X:
_oled = tOled;

This is my changed function:
B4X:
   void B4RMeterBar::Initialize(B4RESP8266FastSSD1331* Oled, uint8_t X, uint8_t Y, uint8_t Width, uint8_t Height, uint16_t ClearColor, uint16_t FillColor, uint16_t BorderColor, uint8_t BorderWidth) {
     meterbar->begin(Oled->oled, X, Y, Width, Height, ClearColor, FillColor, BorderColor, BorderWidth);
}
but I think is not right, because normally I pass to library a reference of oled, eg &Oled. So as explained this is a begin method inside my library:
B4X:
void MeterBar::begin(ESP8266_FastSSD1331* tOled, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorClear, uint16_t colorFill, uint16_t colorBorder, uint8_t strokeWidth) {
  Serial.println(String("MeterBar::begin(OledPointer, " +  (String)x + ", " + (String)y  + ", " + (String)w + ", " + (String)h + ", " + (String)colorClear + ", " + (String)colorFill  + ", " + (String)colorBorder + ", " + (String)strokeWidth + ")"));

  Serial.println("ESP8266_FastSSD1331 : POINT 1 (before)");
  _oled = tOled;         ///////////// ESP CRASHES ON THIS LINE /////////////
  Serial.println("ESP8266_FastSSD1331 : POINT 2 (after)");

  _width = w;
  _height = h;
  _left = x;
  _top = y;
  _right = x + w;
  _bottom = y + h;
  _strokeWidth = strokeWidth;
  _value = 0;
  _colorClear = colorClear;
  _colorFill = colorFill;
  _colorBorder = colorBorder;
  _maxValue = 99;  // default
  _oled->fillRect(_left, _top, _width, _height, _colorClear);
  _oled->drawRect(_left, _top, _width, _height, _colorBorder);
}

So example this code draw a MeterBar (progress bar) and change it's value from 0 to 99 for 10 times, but do not work, stops when I initialize it:
B4X:
Sub Process_Globals
    Public Serial1 As Serial
    Private Oled As ESP8266FastSSD1331
    Private Colors As Color565
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log(" ") : Log(" ") : Log("AppStart") : Log(" ")
    Oled.Initialize(15, 10, 60000000)  ' Initializes the Oled with minimal configuration, we use Hardware CS Pin (HCS-GPIO15) but can be any free pin,
                                       ' and DC Pin (can be any free pin), then the library uses hardware HSPI for MOSI (GPIO13) and CLK (GPIO14).
                                       ' No RST pin used. (IMPORTANT: Connect oled RST pin to VCC).
                                       ' Finally sets HSPI Clock frequency by default 1000000 = 1Mhz

    Oled.Orientation = Oled.ORIENT_REVERSE_LANDSCAPE  ' Sets screen orientation, all four supported, but PORTRAIT orientations use software swap so it is a little slower than LANDSCAPE orientations
    Oled.setContrast(255, 255, 255)                   ' Sets separate contrast (0-255) for R, G and B channels
    Oled.SetMasterCurrent(15)                         ' Sets master current (0-15), by default 7, increase to max 15 for max brightness and brillant colors
                                                      ' (NOTE: Increase brightness can cause a bit shorter life of oled)

    Oled.SlidePageLeft(2, Colors.BLACK, Colors.BLUE, 8000)  ' Slide a page left  (This method do not slide screen content but show an animation, we don't need Oled.Cls method to clear screen)
    Oled.DrawText(6, 24, "MeterBar_Class", Oled.FONT_1206, Colors.BLUE)
    Delay(3000)

    Oled.SlidePageLeft(2, Colors.BLACK, Colors.BLUE, 8000)
    Log("MAIN : POINT 1")
    Dim mb As MeterBar
    mb.Initialize(Oled, 10, 10, 80, 20, Colors.BLACK, Colors.BLUE, Colors.WHITE, 1)  ' **** ESP CRASHES ON THIS LINE ****
    For times = 1 To 10
        Log("MAIN : POINT 2")
        For i = 0 To mb.MaxValue
            Log("Set Value: ", i)
            mb.Value = i
            Delay(100)
        Next
    Next
    Log("MAIN : POINT 3")
End Sub
And this is the log...
Initializing Oled...

SSD1331: Initializing Flash memory...
SSD1331: Flash OK!

Initialization required 48794 Microseconds.

MAIN : POINT 1
MeterBar::begin(OledPointer, 10, 10, 80, 20, 0, 31, 65535, 1)
ESP8266_FastSSD1331 : POINT 1 (before)
Exception (9):
epc1=0x40207e54 epc2=0x00000000 epc3=0x00000000 excvaddr=0xfeefeffe depc=0x00000000
ctx: cont
sp: 3fff0a60 end: 3fff0d60 offset: 01a0
>>>stack>>>
3fff0c00: 40106f70 3ffefc78 feefeffe 40207e4e
3fff0c10: 00000000 00000000 00000000 00000000
3fff0c20: 00000000 00000000 00000000 00000000
3fff0c30: 00000000 00000000 00000000 00000000
3fff0c40: 00000000 00000000 00000000 00000000
3fff0c50: 00000000 00000000 00000000 00000000
3fff0c60: 00000000 00000000 00000000 00000000
3fff0c70: 00000000 00000000 00000000 00000000
3fff0c80: 00000000 00000000 00000001 40206ef5
3fff0c90: 0000001f 0000ffff 00000001 3fff0c70
3fff0ca0: 3ffefb6c 00000050 00000014 00000000
3fff0cb0: 00000030 00000066 402363dc 00001f40
3fff0cc0: 3ffefb6c 00000000 3ffefb88 402084e8
3fff0cd0: 00000000 0000001f 0000ffff 00000001
3fff0ce0: 3ffefb6c 00000000 3ffefb88 402082fe
3fff0cf0: 00000000 0000001f 0000ffff 00000001
3fff0d00: 3ffe91b8 feefef01 feefeffe 3ffefd2c
3fff0d10: 3fffdad0 00000000 3ffefd24 401004d8
3fff0d20: feefeffe feefeffe feefeffe 3ffefd2c
3fff0d30: 3fffdad0 00000000 3ffefd24 40208528
3fff0d40: feefeffe feefeffe feefeffe 402093d0
3fff0d50: feefeffe feefeffe 3ffefd40 40100718
<<<stack<<<
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x4010f000, len 1264, room 16
tail 0
chksum 0x0f
csum 0x0f
~ld
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
I do not understand what strings you mean ... those in Serial.println I put them in the library just for debug, after I delete.

This class works in Arduino IDE enviroment.

_oled is declared in MeterBar class this way: ESP8266_FastSSD1331* _oled

this is a full MeterBar Class declaration:
B4X:
////////// METERBAR //////////
class MeterBar {

  public:
    MeterBar(void);
    void begin(ESP8266_FastSSD1331* tOled, uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t colorClear, uint16_t colorFill, uint16_t colorBorder, uint8_t strokeWidth);

    void setValue(uint16_t value);
    void setMaxValue(uint16_t maxValue);
    uint16_t value();
    uint16_t maxValue();

    uint8_t width();
    uint8_t height();
    uint8_t left();
    uint8_t top();
    uint8_t right();
    uint8_t bottom();
    uint8_t strokeWidth();

  private:
    ESP8266_FastSSD1331* _oled;
    uint8_t _left, _top, _right, _bottom, _width, _height, _strokeWidth;
    uint16_t _colorClear, _colorFill, _colorBorder, _value, _maxValue;
    uint8_t BarTop, BarHeight, oldBarHeight, BarWidth, oldBarWidth;
};

This works on C++ :
B4X:
meter.begin(&oled, 0, 0, oled.percentX(14), oled.percentY(100) - 1, BLACK, BLUE, WHITE, 2);
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Same for ImageClip class that require an oled reference too in the begin method:
B4X:
////////// IMAGECLIP //////////
class ImageClip {

  public:
    ImageClip(void);
    void begin(ESP8266_FastSSD1331* tOled, const String supportType, const String fileName, uint32_t startFrame, uint32_t endFrame, uint8_t x, uint8_t y, uint8_t w, uint8_t h);
    void setFrame(uint32_t frame);
    uint32_t frame();
    uint32_t frameCount();

    uint8_t width();
    uint8_t height();
    uint8_t left();
    uint8_t top();
    uint8_t right();
    uint8_t bottom();

  private:
    String _supportType;
    String _fileName;
    ESP8266_FastSSD1331* _oled;
    uint8_t _left, _top, _right, _bottom, _width, _height;
    uint32_t _currentFrame;
    uint32_t _frameCount;
    uint32_t _startFrame;
    uint32_t _endFrame;
};
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
I've attached the updated version of library.

Only this issue of reference to "oled" is missing and then one last thing regard a pointer to some byte array that show some symbols and then I think everything should work.

The thing regard a pointer is that in Fonts.h file I've defined 6 custom symbols, wifi signal icon, battery icon, bluetooth icon etc... these:
B4X:
const uint8_t c_chSignal816[16] = // mobile signal
{
  0xFE,0x02,0x92,0x0A,0x54,0x2A,0x38,0xAA,0x12,0xAA,0x12,0xAA,0x12,0xAA,0x12,0xAA
};

const uint8_t c_chMessage816[16] =  // message
{
  0x1F,0xF8,0x10,0x08,0x18,0x18,0x14,0x28,0x13,0xC8,0x10,0x08,0x10,0x08,0x1F,0xF8
};

const uint8_t c_chBattery816[16] = // battery
{
  0x0F,0xFE,0x30,0x02,0x26,0xDA,0x26,0xDA,0x26,0xDA,0x26,0xDA,0x30,0x02,0x0F,0xFE
};

const uint8_t c_chBluetooth88[8] = // bluetooth
{
  0x18,0x54,0x32,0x1C,0x1C,0x32,0x54,0x18
};

const uint8_t c_chGPRS88[8] = // GPRS
{
  0xC3,0x99,0x24,0x20,0x2C,0x24,0x99,0xC3
};

const uint8_t c_chAlarm88[8] = // alarm
{
  0xC3,0xBD,0x42,0x52,0x4E,0x42,0x3C,0xC3
};
And this is the function that draw symbols inside rESP8266FastSSD1331.cpp (call drawBitmapMono inside my original library)
B4X:
void B4RESP8266FastSSD1331::DrawBitmapMono(uint8_t X, uint8_t Y, ArrayByte* Bmp, uint8_t Width, uint8_t Height, uint16_t Color) {
  oled->drawBitmapMono(X, Y, Bmp, Width, Height, Color);
}
I need to pass a reference (Bmp) array of bytes to symbols, for now I declared with define this way, but sure is wrong way, used just to test defines:
B4X:
#define  /*ArrayByte*  BMP_SIGNAL_8x16;*/    B4RESP8266FastSSD1331_BMP_SIGNAL_8x16   (&c_chSignal816[0])
#define  /*ArrayByte*  BMP_MESSAGE_8x16;*/   B4RESP8266FastSSD1331_BMP_MESSAGE_8x16  (&c_chMessage816[0])
#define  /*ArrayByte*  BMP_BLUETOOTH_8x8;*/  B4RESP8266FastSSD1331_BMP_BLUETOOTH_8x8 (&c_chBluetooth88[0])
#define  /*ArrayByte*  BMP_GPRS_8x8;*/       B4RESP8266FastSSD1331_BMP_GPRS_8x8      (&c_chGPRS88[0])
#define  /*ArrayByte*  BMP_ALARM_8x8;*/      B4RESP8266FastSSD1331_BMP_ALARM_8x8     (&c_chAlarm88[0])
#define  /*ArrayByte*  BMP_BATTERY_8x16;*/   B4RESP8266FastSSD1331_BMP_BATTERY_8x16  (&c_chBattery816[0])
Normally I use this in C to show symbols and works as exptected:
B4X:
  oled.drawBitmapMono(0,  2, &c_chSignal816[0], 16, 8, WHITE);
oled.drawBitmapMono(19, 2, &c_chMessage816[0], 16, 8, YELLOW);
oled.drawBitmapMono(38, 2, &c_chBluetooth88[0], 8, 8, DARKGREY);
oled.drawBitmapMono(52, 2, &c_chGPRS88[0], 8, 8, DARKGREY);
oled.drawBitmapMono(66, 2, &c_chAlarm88[0], 8, 8, WHITE);
oled.drawBitmapMono(80, 2, &c_chBattery816[0], 16, 8, GREEN);

Many thanks Erel for you great support. ;)
 

Attachments

  • rESP8266FastSSD1331.zip
    153.1 KB · Views: 605
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
And here you can see a result of symbols (sorry for low quality video):

 

max123

Well-Known Member
Licensed User
Longtime User
Sure, I've attached last library update (no changes, only correct small bugs) and simple MeterBar class example.

If you want I've an ImageClip example too, but you need to upload images on ESP8266 Flash using Arduino FS Sketch File Upload plugin, or other tools, and maybe you don't have this oled to show a result.

Many thanks, I'm here to work about this library today too... ;)
 

Attachments

  • rESP8266FastSSD1331.zip
    153.4 KB · Views: 558
  • MeterBar_Class_Example.zip
    1.5 KB · Views: 571
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Bingo!

Used backend for any class and that worked on MeterBar class, now I test ImageClip class.

Now I need to know:

1) how to reference symbols as costants? The funcion expects a reference to byte array as explained on my #Post14:

2) Some functions expects a single character, I pass this way with Asc(), this works, but it is a right way?
B4X:
Oled.drawChar1632(8, 18,  Asc("2"), Colors.BLUE)
Oled.drawChar1632(24, 18, Asc("3"), Colors.BLUE)
Oled.drawChar1632(40, 18, Asc(":"), Colors.GRAY)
Oled.drawChar1632(56, 18, Asc("4"), Colors.BLUE)
Oled.drawChar1632(72, 18, Asc("8"), Colors.BLUE)

3) The library load bitmap images and image sequences from FS and SD, currently I check on .h and .cpp file if FS or SD is defined.
From my tests, is not possible to use FS and SD on same time because there is a conflict on libraries, double declaration of File class, so for this the library check it on header and cpp file. It is supposed to work on B4R too just including in the project rSD or rESP8266FileSystem libraries?

In header file:
B4X:
#if defined (__SD_H__)
   bool beginSD(uint8_t SD_CS = SD_CHIP_SELECT_PIN, uint32_t speed = SPI_HALF_SPEED);
#endif

In cpp file:
B4X:
// The library by default initializes FS file system
#if defined (FS_H)
  if (!SPIFFS.begin()) { // LOAD FILESYSTEM (always use this to "mount" the filesystem if <FS.h> included in the sketch)
    #ifdef SSD1331_DEBUG
       Serial.println("SSD1331: Failed to mount ESP8266 Flash file system!");
    #endif
    return;
  }
#endif

#if defined (__SD_H__)
   bmpFile.seek(pos);
#endif

#if defined (FS_H) || defined (__SD_H__)
   ........
#endif

and others like these...

Many thanks.
 
Last edited:
Top