QMK OLED images

QMK has good OLED support out of the box. My favorite keyboard Corne has by default some informational text going on the displays if you just enable the feature and do nothing else. On the right side you can see a beautiful Corne logo and that peak my curiosity to see how do you put images into those displays.

Create images

The most common display used for this keyboard is 128x32 pixels.

So that’s what we use, jump into photoshop or use an oline equivalent like Photopea and create an image with those dimensions with a black background:

Note I’ve used width 32px and height 128px because I’m going to do an example image that is vertical (this will make sense in a bit).

Then you can go crazy with text, or all the pixel art you can imagine with that amount of pixels.

Keep in mind the OLED display can only handle on/off pixels so go full white or black, gray won’t show well.

I’ll go with this to start:

Save it as a JPG or PNG, then let’s convert that to code.

Convert pixels to code

Now go to the utility Image 2 CPP.

Pick the image file you just created and change the following settings:

  • Background: ‘Black’
  • Code Output Format: ‘Plain bytes’
  • Draw Mode: ‘Vertical - 1 bit per pixel’

Hit ‘Generate code’ and copy that output, in my case:

// 'hello_world_corne_final', 32x128px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0x00, 0x00, 
0xc0, 0xf0, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0xc0, 0xf0, 0xf8, 0xfc, 0xe8, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xc0, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x01, 0x0f, 0x1f, 0x3f, 0x7f, 0x7e, 0x7f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0x7f, 0x7f, 
0x3f, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0xf0, 0xf0, 0x70, 0x78, 0x1c, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x80, 0xf0, 0x70, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0x06, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe, 0xff, 0x0f, 0x3f, 0xfc, 0xff, 0x1f, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x03, 0x03, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x0c, 0x0c, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x60, 0x60, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0c, 0x0c, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff, 0xdf, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00

Add it to your firmware

Now let’s add it to your firmware, I assume you already have the QMK environment and a base keymap to work with.

Make sure that OLED support is enabled, inside your rules.mk file you should have:

OLED_ENABLE = yes

Then add a conditional block to handle the OLED display if it is enabled:

#ifdef OLED_ENABLE
// your code will be here
#endif

Let’s set the right orientation first, since we want to have this vertically, we set the rotation degrees:

oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    return OLED_ROTATION_270;  
    return rotation;
}

Next we write he method that actually shows stuff.

bool oled_task_user(){
    // This stores the image content
    static const char hello_world_img [] PROGMEM = {
        // your image 2 cpp content
    };
    // this displays the image
    oled_write_raw_P(hello_world_img, sizeof(hello_world_img));
    
    return false;
}

And that’s it! after that just flash your firmware and the image will show correctly.

This is just the tip of the iceberg, check out the complete API for more info. The combination of several images and a timer can be used to display animations and such. Another good use could be to indicate activated layers with conditionals.

Share: Twitter Facebook

Comments