How to fade in or fade out oled display SSD1306 Adafruit library

Didn´t find the code, so I had to write my own. I´m not a programmer so maybe there´s a better way to do it.

This is how I created a fade in and fadeout commands to Adafruit SSD1306 library.

It changes both SSD1306_SETCONTRAST and SSD1306_SETPRECHARGE to give a nice fade out.

I guess that´s all fadeout you can get with I2C.

Using SPI, I guess you can go further and turn off charge pump (Charge pump off (via writing 10h to 8Dh, to enable write 14h to same address)

I got the ideia from youtube:

Mine is I2C so I created and changed only contrast and precharge.

How to:

Adafruit_SSD1306.h

after "void display();", add:

void fadeout(); 
void fadein();

Adafruit_SSD1306.cpp

after "ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel
}"

void Adafruit_SSD1306::fadeout() {
    for (int dim=150; dim>=0; dim-=10) {
    ssd1306_command(0x81);
    ssd1306_command(dim); //max 157
    delay(50);
  }
  
  
  for (int dim2=34; dim2>=0; dim2-=17) {
  ssd1306_command(0xD9);
  ssd1306_command(dim2);  //max 34
  delay(100);
  }
}

void Adafruit_SSD1306::fadein() {
    for (int dim=0; dim<=160; dim+=10) {
    ssd1306_command(0x81);
    ssd1306_command(dim); //max 160
    delay(50);
  }
  
  
  for (int dim2=0; dim2<=34; dim2+=17) {
  ssd1306_command(0xD9);
  ssd1306_command(dim2);  //max 34
  delay(100);
  }
}

Hope it helps. Any improvments would be nice.

Thank you for this valuable contribution. I'm working with U8G2 library with an SSD1306 OLED module. Can we implement the same function with U8G2lib?

U8G2 has some contrast control functionality, can you please guide how to implement this?

u8g2.SetPrecharge(0x10);
u8g2.SetContrast(0 ... 255);

Thanks.

I can not provide a full solution, but maybe some hits.
Adafruit lib contains the ssd1306_command function. This is a little bit more complicated in u8g2 (because u8g2 also supports many other displays) so the second loop will probably look like this (not tested):

  for (int dim2=0; dim2<=34; dim2+=17) {
  u8x8_cad_StartTransfer(u8g2.GetU8x8());
  u8x8_cad_SendCmd( u8g2.GetU8x8(), 0xD9);
  u8x8_cad_SendArg( u8g2.GetU8x8(), dim2);  //max 34
  u8x8_cad_EndTransfer(u8g2.GetU8x8());
  delay(100);
  }

For the first loop you can use the set contrast command from u8g2.

Oliver

olikraus:
I can not provide a full solution, but maybe some hits.
Adafruit lib contains the ssd1306_command function. This is a little bit more complicated in u8g2 (because u8g2 also supports many other displays) so the second loop will probably look like this (not tested):

  for (int dim2=0; dim2<=34; dim2+=17) {

u8x8_cad_StartTransfer(u8g2.GetU8x8());
 u8x8_cad_SendCmd( u8g2.GetU8x8(), 0xD9);
 u8x8_cad_SendArg( u8g2.GetU8x8(), dim2);  //max 34
 u8x8_cad_EndTransfer(u8g2.GetU8x8());
 delay(100);
 }




For the first loop you can use the set contrast command from u8g2.

Oliver

Thank you Oliver for the suggestion. What is the purpose of GetU8c8() function? U8G2 is a brilliant library to work with. I also need to know what does setPrecharge do? I saw the suggested video by the OP and the implied limitations with I2C diaplays as their minimum contrast exhibit some constraints. I tried the following code with an I2C OLED module, and it seems like setContrast(0) hits the hardware limitation of the module as it was still quiet bright, not like the LED fade effect from absolute 0 to 255.

 for (int dim=0; dim<=255; dim+=10) {
    u8g2.SetContrast(dim);
     } 
    delay(50);

What is the purpose of GetU8c8() function?

U8g2 is a C library with a C++/Arduino wrapper. getU8x8() converts the C++/Arduino class into a pointer to the u8x8 C structure, which is required to call the low level functions.

I also need to know what does setPrecharge do?

There is no such function in u8g2. I do not know from where this got quoted. It is not from the original library.

like setContrast(0) hits the hardware limitation of the module as it was still quiet bright

Yes, this is true for some (all?) OLEDs. OP has used a trick here: The SSD1306 specific precharge register is used to do further brightness reduction. U8g2 and Adafruit libs do not provide access to this register because it is not portable and it may only work with some SSD1306 OLEDs.The trick was to do a fade down of the precharge values (there actualy two precharge periods and OP has reduced them both in parallel). This is from the initial code:

  for (int dim2=0; dim2<=34; dim2+=17) {
  ssd1306_command(0xD9);
  ssd1306_command(dim2);  //max 34
  delay(100);

Actually i can not tell you whether this will work or why this works. This is something you need to figure out from the SSD1306 data sheet. I can only tell you how to send the same commands+argumements to u8g2. I mean ssd1306_command is a Adafruit library command, so I just translated the same loop to U8g2 commands.

Oliver

Thanks Oliver, I'll try again and see if it works. In either case, I'll post a note here.

olikraus:

  for (int dim2=0; dim2<=34; dim2+=17) {

u8x8_cad_StartTransfer(u8g2.GetU8x8());
  u8x8_cad_SendCmd( u8g2.GetU8x8(), 0xD9);
  u8x8_cad_SendArg( u8g2.GetU8x8(), dim2);  //max 34
  u8x8_cad_EndTransfer(u8g2.GetU8x8());
  delay(100);
  }

Can I implement the code as it is? Since the compiler shows the following error:
'class U8G2_SSD1306_128X64_NONAME_F_HW_I2C' has no member named 'GetU8x8'.

I tried the same with U8X8 library and display constructor, the error persists. Can you please guide me to what I'm missing here?

Antrix:
Can I implement the code as it is? Since the compiler shows the following error:
'class U8G2_SSD1306_128X64_NONAME_F_HW_I2C' has no member named 'GetU8x8'.

I tried the same with U8X8 library and display constructor, the error persists. Can you please guide me to what I'm missing here?

My mistake, it is not "GetU8x8", but instead "getU8x8" (Arduino naming convention).

Oliver

olikraus:
My mistake, it is not "GetU8x8", but instead "getU8x8" (Arduino naming convention).

Oliver

Thank you for the update. I uploaded the code and it seems like there is further 40-50% reduction in brightness over setContrast(0);

   for (int dim=150; dim>=0; dim-=5) {
  u8x8_cad_StartTransfer(u8g2.getU8x8());
  u8x8_cad_SendCmd( u8g2.getU8x8(), 0x81);
  u8x8_cad_SendArg( u8g2.getU8x8(), dim);  //max 34
  u8x8_cad_EndTransfer(u8g2.getU8x8());
  delay(30);
   }
 
   for (int dim2=34; dim2>=0; dim2-=50) {
  u8x8_cad_StartTransfer(u8g2.getU8x8());
  u8x8_cad_SendCmd( u8g2.getU8x8(), 0xD9);
  u8x8_cad_SendArg( u8g2.getU8x8(), dim2);  //max 34
  u8x8_cad_EndTransfer(u8g2.getU8x8());
  delay(20);
  }

Thanks a lot Oliver for your kind help! I shall be using this code to save power in battery operated Arduino projects.

Hey there,

I´ve been struggeling to get my ssd1306 to dimm beyond what setConrast would allow. Now I´ve stumbled accross this piece of code, but son´t really know how to implement it.
You´ve stated that you uploaded the code. Please elaborate on where you put it.

I have tried in the main loop and get a nice pulsing brightness. At least it seems to go lower than what setContrast would allow.
I would like to know what dim1 and 2 are and what are their respective max/min values to be used.

interesting post,
where did you get the max value for contrast and precharge?

I found that the max value for contrast is 255, but what is the maximum value for precharge?

See the commands in the datasheet. Both are single bytes, but precharge has two phases combined into the byte.

MK1888:
See the commands in the datasheet. Both are single bytes, but precharge has two phases combined into the byte.

Not able to read that datasheet unfortunately.
Datasheet says this:
For 0xD9, page 40 just says "This command is used to set the duration of the pre-charge period. The interval is counted in number of DCLK, where RESET equals 2 DCLKs." and doesn't give a range

There is no range and no value, how am I supposed to set a value if I don't have a range?