icon

Playing GIFs on the Fermion 1.51'' Transparent OLED Display

Hello Everyone, It's good to be back! This is going to be a short and beginner-friendly tutorial that lays the foundation of an upcoming interesting project!

 

A couple of months back, DFRobot sent me this Fermion 1.51" Transparent OLED Display which is going to be the star of this tutorial. Here, we are going to try running some GIFs on the display module.

Along the way, I am going to discuss a bit of the theory and all the steps involved in running a GIF on an OLED through an Arduino Uno. Before beginning, do watch this YouTube short to get a gist of the whole process, and let's start!

HARDWARE LIST
1 Arduino Uno
1 Fermion 1.51'' Transparent OLED

On the software side you'll need:

 

1) Your favorite GIF

 

2) Arduino IDE

 

3) U8g2lib library

 

4) Internet Access

 

And that's it! So now let's start!

 

Connect the Display to the Arduino

 

First, let's hook up the Arduino Uno to the display which comes with 2 main items: The Actual Transparent Display with a ribbon cable and a Module with some headers. The module acts as a bridge between the Display and the Arduino. It uses an SPI interface to communicate with the Arduino and then accordingly light the transparent pixels of our Display using a GDI interface.

 

So first let's solder the headers to our interface module and make the connections as follows:

 

Power Connections:

 

Display Module Vcc ---> Arduino 3.3V Pin

 

Display Module GND ---> Arduino GND Pin 

 

SPI Interface:

 

Display Module MOSI ---> Arduino Pin 11

 

Display Module SCLK ---> Arduino Pin 13

 

Display Module CS Pin ---> Arduino Pin 10 

 

Display Commands & Reset:

 

Display Module DC Pin ---> Arduino Pin 7

 

Display Module RST Pin ---> Arduino Pin 6 

 

After this is done, you can attach the loose end of the Display's ribbon cable to the connector on the module. Very gently pull out and flip up the black lock of the connector (a pair of tweezers might be best for this). Then push the cable in and close the lock in a similar way.

 

 

 

 

 

 

 

 

The Software and Some Theory

 

So now let's move on to the software part. If you want to skip the theory and get on with playing the GIFs, you can just go ahead and upload the attached code after installing the U8g2 Library.

 

And now...the explanations and the detailed process:

 

GIF stands for Graphics Interchange Format and it is a Bitmap image format that can be used for static as well as animated images. These types of images have a limited color palette (256 colors) but are very commonly used for their capability of storing animated images. Each pixel in a GIF is represented with an 8-bit value which refers to one of the 256 colors in the palette. For animated images, all the frames of the animation are stored and played back in a sequence. And this is what we have to do!

 

The U8g2 Library:

 

For the software side, we'll be using the U8g2lib library which is a graphics library for embedded devices that can be used with monochrome (single-colored) OLEDs and LCDs. The library comes with inbuilt functions for drawing common graphics like lines, circles, boxes, etc. as well as text with different fonts. So go ahead and install that library in your Arduino IDE from the Library Manager (Tools > Manage Libraries...) by searching U8g2 and clicking install. We'll be using the drawXBMP() function of the library to draw the bitmaps. For that, we need to convert the bitmaps to a character array which will be passed to the function along with the position of the top left corner, width, and height of the image.

 

Converting Images to Byte Arrays with image2cpp:

 

For the required conversion, we'll use the image2cpp project. This is an open-source project that converts images to byte arrays for monochrome OLED displays. While using it for this project, I found that the byte array output was not correctly rendered on the display. There was a noticeable shift in the pixels of the image which was due to the fact that image2cpp originally converted the image according to Adafruit's GLX library (with MSB on the left for each byte). However, for this, we are using the U8g2 library (which works with bitmap representations having LSB on the left for each byte) so you can use the patch-1 branch of this fork of image2cpp for the same.

 

 

 

 

 

For converting the frames of your GIF to byte arrays using image2cpp, you can follow these steps:

 

1) Extract all the frames of your GIF. You can use websites like ezgif to split the GIF into separate frames. Here make sure to use a less heavy GIF since we'll be storing the byte array of all the images in the Arduino's Program (Flash) Memory using PROGMEM

 

2) Clone the patch-1 branch of the linked fork or download the zip of the source code.Open the index.html in any browser of your choice. 

 

3) Once it opens, you should see the website interface. You'll see a Select Image option on the top where you can upload all the frames of your GIF. 

 

4) Configure the settings according to your needs. You can see the settings I used in the image attached. Keep referring to the preview to verify the result of all the settings. 

 

5) After you are satisfied with the preview, click the Generate Code button. Make sure the code output format is set to Arduino Code and enter a suitable prefix for the name of all the character arrays. 

 

6) Once all the byte arrays are generated, you can copy all the arrays and paste them into the Arduino sketch. Make sure to update the required variable names according to the prefix you used. 

 

Now you can go ahead and upload the program to your Arduino which will display all the frames in a sequence in the void loop() function. The delay() value in the loop function can be adjusted to change the FPS of the GIF.

 

 

CODE
#include <Arduino.h>
#include <U8g2lib.h>

#include <SPI.h>

/*
  U8g2lib Example Overview:
    Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption
    Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards.
    U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only.
    
  This is a page buffer example.    
*/

// Please UNCOMMENT one of the contructor lines below
// U8g2 Contructor List (Picture Loop Page Buffer)
// The complete list is available here: https://github.com/olikraus/u8g2/wiki/u8g2setupcpp
// Please update the pin numbers according to your setup. Use U8X8_PIN_NONE if the reset pin is not connected

#define OLED_DC  7
#define OLED_CS  10
#define OLED_RST 6
U8G2_SSD1309_128X64_NONAME2_1_4W_HW_SPI u8g2(/* rotation=*/U8G2_MIRROR, /* cs=*/ OLED_CS, /* dc=*/ OLED_DC,/* reset=*/OLED_RST);


void u8g2_prepare(void) {
  u8g2.setFont(u8g2_font_6x10_tf);  //Set the font to "u8g2_font_6x10_tf"
  u8g2.setFontRefHeightExtendedText();  //Ascent will be the largest ascent of "A", "1" or "(" of the current font. Descent will be the descent of "g" or "(" of the current font.
  u8g2.setDrawColor(1); //Ascent will be the largest ascent of "A", "1" or "(" of the current font. Descent will be the descent of "g" or "(" of the current font.
  u8g2.setFontPosTop();  /*When you use drawStr to display strings, the default criteria is to display the lower-left coordinates of the characters.
                        XXXX  */
  u8g2.setFontDirection(0); //Set the screen orientation: 0 -- for normal display
}

/* Paste the Byte Array from image2cpp here */


// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 18720)
const int rick_roll_animARRAY_LEN = 45;
const unsigned char* rick_roll_anim[45] = {
  rick_roll_frame_00_delay_0,
  rick_roll_frame_01_delay_0,
  rick_roll_frame_02_delay_0,
  rick_roll_frame_03_delay_0,
  rick_roll_frame_04_delay_0,
  rick_roll_frame_05_delay_0,
  rick_roll_frame_06_delay_0,
  rick_roll_frame_07_delay_0,
  rick_roll_frame_08_delay_0,
  rick_roll_frame_09_delay_0,
  rick_roll_frame_10_delay_0,
  rick_roll_frame_11_delay_0,
  rick_roll_frame_12_delay_0,
  rick_roll_frame_13_delay_0,
  rick_roll_frame_14_delay_0,
  rick_roll_frame_15_delay_0,
  rick_roll_frame_16_delay_0,
  rick_roll_frame_17_delay_0,
  rick_roll_frame_18_delay_0,
  rick_roll_frame_19_delay_0,
  rick_roll_frame_20_delay_0,
  rick_roll_frame_21_delay_0,
  rick_roll_frame_22_delay_0,
  rick_roll_frame_23_delay_0,
  rick_roll_frame_24_delay_0,
  rick_roll_frame_25_delay_0,
  rick_roll_frame_26_delay_0,
  rick_roll_frame_27_delay_0,
  rick_roll_frame_28_delay_0,
  rick_roll_frame_29_delay_0,
  rick_roll_frame_30_delay_0,
  rick_roll_frame_31_delay_0,
  rick_roll_frame_32_delay_0,
  rick_roll_frame_33_delay_0,
  rick_roll_frame_34_delay_0,
  rick_roll_frame_35_delay_0,
  rick_roll_frame_36_delay_0,
  rick_roll_frame_37_delay_0,
  rick_roll_frame_38_delay_0,
  rick_roll_frame_39_delay_0,
  rick_roll_frame_40_delay_0,
  rick_roll_frame_41_delay_0,
  rick_roll_frame_42_delay_0,
  rick_roll_frame_43_delay_0,
  rick_roll_frame_44_delay_0
};

/*
 * Animation
*/
void display_frame(char* frame_name) {
  u8g2.setBitmapMode(true /* transparent */);
  u8g2.drawXBMP(30, 0, 56, 56, frame_name);
}

void setup(void) {
  u8g2.begin(); //Initialize the function
}

uint8_t frame_num = 0;

void loop(void) {
  // picture loop  
  u8g2.firstPage();
  do {
    display_frame(rick_roll_anim[frame_num]);
  } while( u8g2.nextPage() );

  frame_num++;

  if (frame_num >= rick_roll_animARRAY_LEN){
    frame_num=0;
  }
  delay(80);
}
License
All Rights
Reserved
licensBg
0