Using the DVID screen

2019 March 25

I recently bought the Damn Vulnerable IoT Device. I started playing with it and I wanted to see if I could produce an animated logo for the DVID hardware. In this post I show how to use the DVID screen to display pictures

Arduino IDE and libraries

IDE

First things first, we will need the Arduino IDE installed. When this is done we will need to select the proper programmer in Tools > Programmer. Since we use a USBAsp to program the Atmega328p, we select USBAsp.

Libraries

Now we will need to install the Adafruit libraries. To do so, we navigate in Tools > Manage libraries. Then we search for adafruit SSD1306 and install Adafruit SSD1306. We then search adafruit GFX and install Adafruit GFX Library.

We now have everything needed to start playing with the screen.

Example sketch

Adafruit provides examples of how to use their library.

We have the choice between four scripts :

  • ssd1306_128x32_i2c
  • ssd1306_128x32_spi
  • ssd1306_128x64_i2c
  • ssd1306_128x64_spi

The OLED screen used by DVID has the following characteristics :

  • Resolution: 128*64
  • Control chip: SSH1106
  • Display area: 29.42 x 14.7mm
  • Driving voltage: 3.3-5V
  • Operating temperature: -40 ℃ to 70 ℃
  • Interface type: IIC/I2C interface

According to our screen characteristics, we use the script ssd1306_128x64_i2c. We copy it in our arduino IDE, and start a compilation (Sketch > Verify/Compile).

Then we upload the sketch to the board with Sketch > Upload using programmer.

And ... tada ! Nothing happens.

Why is that ?

I2C address

After some research we find that the problem lies in this line :

 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Address 0x3D for 128x64

This bit of code leads us to believe that the parameter 0x3D is linked to the resolution of the screen, but it is not. Actually if we replace 0x3D by 0x3C as suggested in the blog post linked above, our example will work perfectly (in my case, at least).

If we look at the source code of the Adafruit library we see that the prototype for the begin function is :

boolean Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, boolean reset,
boolean periphBegin)

The documentation specifies that

@param addr I2C address of corresponding SSD1306 display (or pass 0 to use default of 0x3C for 128x32 display, 0x3D for all others). SPI displays (hardware or software) do not use addresses, but this argument is still required (pass 0 or any value really, it will simply be ignored). Default if unspecified is 0.

So 0x3D is supposed to be the I2C address of the SSD1306 display. The issue is the 0x3D does not seem to be the address of our display.

So how do we find the I2C ? Some quick DDG search gives us the tool I2cScanner.

So we just have to copy the script into our Arduino IDE and upload it with the USBAsp programmer.

Then we use a serial connection to connect to the board and we will get the information we are looking for :

cu -l /dev/ttyUSB0 -s 9600
Connected.
Scanning...
I2C device found at address 0x3C  !
done

Now if we replace the 0x3D address by the one displayed we will have a working demo.

About I2C

We've been talking about I2C but what is it exactly ?

The Inter-integrated Circuit (I2C) Protocol is a protocol intended to allow multiple "slave" digital integrated circuits ("chips") to communicate with one or more "master" chips. Like the Serial Peripheral Interface (SPI), it is only intended for short distance communications within a single device. Like Asynchronous Serial Interfaces (such as RS-232 or UARTs), it only requires two signal wires to exchange information.

A full introduction can be found on sparkfun.com.

Drawing a bitmap

Now that we've seen how to make the example sketch work, let's do one of our own. In this sketch we will attempt to draw a logo from a bitmap.

First we create a logo in Gimp. To do this we create a new project for a 128x64 pixels image and we do some pixel art with a hardbrush pencil with a size of 1 pixel.

Once this is done we export the logo as a *.xbm file. We then rename the file as *.c and open it in an editor. We retrieve the array and paste it in our sketch. We just have to modify the type to static const uint8_t PROGMEM then we can use it in our code.

To use it we just have to call drawXBitmap and give it our bitmap to display it.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSans9pt7b.h>


#define DVID_logo_width 128
#define DVID_logo_height 64

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);



static const uint8_t PROGMEM DVID_logo_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x1c, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x02, 0x00, 0x01, 0x80, 0x03, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xf2, 0x1f,
   0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x08, 0x12, 0x10, 0x00, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, 0xf0, 0xff, 0x17, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00,
   0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x08, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x07,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0xff, 0x3f, 0x00,
   0xf8, 0x00, 0x00, 0x3e, 0x78, 0x80, 0xff, 0x0f, 0x00, 0xc0, 0x7f, 0x04,
   0x00, 0xff, 0xff, 0x00, 0xf8, 0x00, 0x00, 0x3e, 0x78, 0x80, 0xff, 0x3f,
   0x00, 0x40, 0x40, 0x04, 0x00, 0xff, 0xff, 0x03, 0xf8, 0x01, 0x00, 0x3f,
   0x78, 0x80, 0xff, 0xff, 0x00, 0x40, 0x40, 0x04, 0x00, 0xff, 0xff, 0x07,
   0xf8, 0x01, 0x00, 0x1f, 0x78, 0x80, 0x07, 0xf8, 0x01, 0x40, 0x40, 0x04,
   0x00, 0x0f, 0xf0, 0x0f, 0xf0, 0x01, 0x00, 0x1f, 0x78, 0x80, 0x07, 0xe0,
   0x03, 0x40, 0x40, 0x04, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x03, 0x80, 0x0f,
   0x78, 0x80, 0x07, 0xc0, 0x07, 0x40, 0x40, 0x04, 0x00, 0x0f, 0x80, 0x1f,
   0xe0, 0x03, 0x80, 0x0f, 0x78, 0x80, 0x07, 0x80, 0x07, 0x40, 0x40, 0x04,
   0x00, 0x0f, 0x00, 0x3f, 0xe0, 0x03, 0x80, 0x0f, 0x78, 0x80, 0x07, 0x00,
   0x0f, 0x40, 0x40, 0x04, 0x00, 0x0f, 0x00, 0x3e, 0xe0, 0x07, 0xc0, 0x07,
   0x78, 0x80, 0x07, 0x00, 0x0e, 0x40, 0xe0, 0x04, 0x00, 0x0f, 0x00, 0x3e,
   0xc0, 0x07, 0xc0, 0x07, 0x78, 0x80, 0x07, 0x00, 0x1e, 0x40, 0xa0, 0x04,
   0x00, 0x0f, 0x00, 0x7c, 0xc0, 0x07, 0xc0, 0x07, 0x78, 0x80, 0x07, 0x00,
   0x1c, 0x40, 0xe0, 0x04, 0x00, 0x0f, 0x00, 0x7c, 0xc0, 0x0f, 0xe0, 0x03,
   0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x7c,
   0x80, 0x0f, 0xe0, 0x03, 0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x00, 0x04,
   0x00, 0x0f, 0x00, 0x7c, 0x80, 0x0f, 0xe0, 0x01, 0x78, 0x80, 0x07, 0x00,
   0x1c, 0x40, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x7c, 0x80, 0x1f, 0xf0, 0x01,
   0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x7c,
   0x00, 0x1f, 0xf0, 0x01, 0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x00, 0x04,
   0x00, 0x0f, 0x00, 0x7c, 0x00, 0x1f, 0xf0, 0x00, 0x78, 0x80, 0x07, 0x00,
   0x1c, 0x40, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x7c, 0x00, 0x3e, 0xf8, 0x00,
   0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x7c,
   0x00, 0x3e, 0xf8, 0x00, 0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x38, 0x04,
   0x00, 0x0f, 0x00, 0x7c, 0x00, 0x3e, 0x78, 0x00, 0x78, 0x80, 0x07, 0x00,
   0x1c, 0x40, 0x2e, 0x0e, 0x00, 0x0f, 0x00, 0x7c, 0x00, 0x7c, 0x7c, 0x00,
   0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x3a, 0x0a, 0x00, 0x0f, 0x00, 0x7c,
   0x00, 0x7c, 0x7c, 0x00, 0x78, 0x80, 0x07, 0x00, 0x1c, 0x40, 0x02, 0x0e,
   0x00, 0x0f, 0x00, 0x7e, 0x00, 0x7c, 0x3c, 0x00, 0x78, 0x80, 0x07, 0x00,
   0x1c, 0x40, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x3e, 0x00, 0xf8, 0x3e, 0x00,
   0x78, 0x80, 0x07, 0x00, 0x1e, 0x40, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x3f,
   0x00, 0xf8, 0x1f, 0x00, 0x78, 0x80, 0x07, 0x00, 0x0e, 0x40, 0x02, 0x00,
   0x00, 0x0f, 0x80, 0x1f, 0x00, 0xf0, 0x1f, 0x00, 0x78, 0x80, 0x07, 0x80,
   0x0f, 0x40, 0x02, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0x00, 0xf0, 0x1f, 0x00,
   0x78, 0x80, 0x07, 0x80, 0x03, 0x40, 0x02, 0x00, 0x00, 0x0f, 0xf0, 0x0f,
   0x00, 0xf0, 0x0f, 0x00, 0x78, 0x80, 0x07, 0xe0, 0x03, 0x40, 0xe2, 0x00,
   0x00, 0xff, 0xff, 0x07, 0x00, 0xe0, 0x0f, 0x00, 0x78, 0x80, 0x07, 0xf8,
   0x00, 0x40, 0xa2, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0xe0, 0x0f, 0x00,
   0x78, 0x80, 0xff, 0xff, 0x00, 0x40, 0xe2, 0x00, 0x00, 0xff, 0xff, 0x00,
   0x00, 0xc0, 0x07, 0x00, 0x78, 0x80, 0xff, 0x3f, 0x00, 0x40, 0x42, 0x00,
   0x00, 0xff, 0x3f, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x78, 0x80, 0xff, 0x0f,
   0x00, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x42, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x40, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x20, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
   0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x20, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff,
   0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x5f, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00 };

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

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


void loop() {}

And it works !