OLED Display for the s905x-cc

I am having a hard time finding a .96" oled display for my Potato. It seem that most only work with RPI. Is there a generic display I can be using that will work with the Libre board? Is there a workaround that someone has discovered in being able to use an oled display?

Most of them are I2C so you just have to enable the I2C overlay and send the appropriate data. Recommend you learn about how the I2C bus works.

2 Likes

I spent some time going through standing up a SH1106 OLED display on Le potato and with python LUMA code on GPIO pins 1(vcc),6(gnd),27(sda) and 28(sck). Unlike Renegade which has an overlay ready to go for OLED on channel 1 checking with i2cdetect -l (rk3x-i2c) address 3C, my le potato setup did not have anything like that.

Static hostname: lepotato
Icon name: computer
Machine ID: …
Boot ID: …
Operating System: Armbian 25.5.2 bookworm
Kernel: Linux 6.12.32-current-meson64
Architecture: arm64

So i write an overlay and compiled it with dts and then put that overlay in the right place (until i learned the gotchas).

this is the overlay I used: i2c-b.dts

/*

  • Copyright (c) 2017 BayLibre, SAS.
  • Author: Neil Armstrong narmstrong@baylibre.com
  • SPDX-License-Identifier: (GPL-2.0+ OR MIT)
    */

/*

  • Overlay aimed to enable I2C_B on Header 7J1 :
  • Pins 27 (SDA), 28 (SCL)
    */

/dts-v1/;
/plugin/;

/ {
compatible = β€œlibretech,aml-s905x-cc”, β€œamlogic,s905x”, β€œamlogic,meson-gxl”;

    fragment@0 {
            target-path = "/aliases";

            __overlay__ {
                    i2c0 = "/soc/cbus@c1100000/i2c@87c0";
            };
    };

    fragment@1 {
            target = <&i2c_b_pins>;

            __overlay__ {
                    cfg {
                            pins = "GPIODV_26", "GPIODV_27";
                            bias-pull-up;
                    };
            };
    };

    fragment@2 {
            target = <&i2c_B>;

            __overlay__ {
                    status = "okay";
                    pinctrl-0 = <&i2c_b_pins>;
                    pinctrl-names = "default";
            };
    };

};

  1. use: pins = β€œGPIODV_26”, β€œGPIODV_27”; NOT the numbers in the pinout (27,28)

  2. the target in fragment B is target = <&i2c_B>; not target = <&i2c_B>;

  3. I checked my /boot/armbianEnv.txt and noticed that there is an overlay prefix (overlay_prefix=meson)

  4. make sure you have a line overlays=i2cB

(NOT overlays=i2cb) in armbianEnv.txt.

so had to run through edits! => vi i2c-b.dts

Compiled it => dtc -@ -I dts -O dtb -o meson-i2cB.dtbo i2c-b.dts

next step was to copy that to a working location

for me that is /boot/dtb/amlogic/overlay/

sudo cp meson-i2cB.dtbo /boot/dtb/amlogic/overlay/

note the prefix β€œmeson-”is added and the file type is dtbo and for me it works here: /boot/dtb/amlogic/overlay/

The last curveball is when I ran i2cdetect -l it is:

i2c-0 i2c Meson I2C adapter I2C adapter
i2c-1 i2c DesignWare HDMI I2C adapter

So the new i2c port is 0! this is what is needed in your code not 1 as i thought it would be like for Renegade’s.

Check for the correct address:

sudo i2cdetect -y 0 <= NOT 1!!!

sudo] password for goldenway:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – – – – – – – –
10: – – – – – – – – – – – – – – – –
20: – – – – – – – – – – – – – – – –
30: – – – – – – – – – – – – 3c – – –
40: – – – – – – – – – – – – – – – –
50: – – – – – – – – – – – – – – – –
60: – – – – – – – – – – – – – – – –
70: – – – – – – – –

I see address is 3c

Looked good

test it…ran python script below

from luma.core.interface.serial import i2c
from luma.oled.device import sh1106
from PIL import Image, ImageDraw
import time

time.sleep(0.5)
serial = i2c(port=0, address=0x3C) #bus 1 address from i2cdetect
device = sh1106(serial)

image = Image.new(β€œ1”, (128, 64))
draw = ImageDraw.Draw(image)
draw.text((10, 20), β€œLe Potato OLED”, fill=255)
draw.text((10, 40), β€œI2C OK”, fill=255)
device.display(image)

sure enough I see the OLED flash that and turn off

so then I put all my code in a while loop with a delay

while True:

instantiate the Image and ImageDraw classes

draw things…

device.display(image)

time.sleep(update_interval)

Done :oncoming_fist: Hope this day of IoT fun helps! :wink:

There’s no overlay in libretech-wiring-tool? It has a bunch of displays including some tiny OLED ones.

Maybe but in Armbian 25.5.2 bookworm I think my image/os required dts not ldto :man_gesturing_ok: had issues with that you get a NO VENDOR error or something as i recall? So i just bounced it. I am still learning about Armbian OS/ their kernels and i2c devices and SPI devices…edisonian style. I don’t like the non ARM64 chips other than renegade so far - they use too much power and get too hot. So I went the Armbian path for those. Got any insights? Why use LDTO?

Here’s an AI summary

Linux Device Tree File Types

File Type Purpose Human-readable? Usage / Notes
.dts – Device Tree Source Defines hardware: CPU, memory, peripherals in a hierarchical text format :white_check_mark: Yes Compiled into .dtb; main editable source for Linux kernel
.dtbo – Device Tree Overlay Modifies or extends a base .dtb without changing it :white_check_mark: Yes Optional; applied at boot or runtime to enable extra hardware
.dtb – Device Tree Blob Binary representation of .dts / .dtbo :cross_mark: No Loaded by bootloader; kernel reads it to understand hardware
.ldto – Loader DTO (toolchain-specific) Sometimes used as a loader-specific hardware description or intermediate binary :cross_mark: Usually Not standard in Linux; used in proprietary bootloaders, FPGA, or MCU toolchains

Key Points

  • .dts = source β†’ human-readable β†’ kernel compilation.

  • .dtb = compiled β†’ used at boot.

  • .dtbo = overlay β†’ optional modifications.

  • .ldto = uncommon; specific to certain loaders or toolchains, not part of standard Linux workflow.

:light_bulb: Linux focus: You usually only need .dts β†’ compile to .dtb (and optionally .dtbo). .ldto is rarely relevant unless you are working with a proprietary bootloader or FPGA toolchain.

:peace_symbol: