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
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.
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.
Adafruit provides examples of how to use their library.
We have the choice between four scripts :
The OLED screen used by DVID has the following characteristics :
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 ?
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.
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.
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 !