Drawing a Multi-Byte Image in Embedded Rust using embedded-graphics
Now let’s write the code to display a wider image on our OLED screen. The main changes from the previous example are the image data and the width value. This time, we’ll display a resistor symbol in the IEC-60617 style.
Project base
We will copy the byte-oled project and work on top of that.
git clone https://github.com/ImplFerris/pico2-embassy-projects
cp -r pico2-embassy-projects/blocking/byte-oled ~/YOUR_PROJECT_FOLDER/oled-rawimg
or you can simply create a fresh project from the template and follow the same steps we used earlier.
Image Data
Here’s the byte array for the resistor symbol. Notice how each row needs multiple bytes because the image is 31 pixels wide.
#![allow(unused)]
fn main() {
// 31x7 pixel
#[rustfmt::skip]
const IMG_DATA: &[u8] = &[
// 1st row
0b00000001,0b11111111,0b11111111,0b00000000,
// 2nd row
0b00000001,0b11111111,0b11111111,0b00000000,
//3rd row
0b00000001,0b10000000,0b00000011,0b00000000,
//4th row
0b11111111,0b10000000,0b00000011,0b11111110,
//5th row
0b00000001,0b10000000,0b00000011,0b00000000,
//6th row
0b00000001,0b11111111,0b11111111,0b00000000,
//7th row
0b00000001,0b11111111,0b11111111,0b00000000,
];
}
Creating and Positioning the Image
We need to set the width to 31 pixels. We’ll draw the image at position (x=35, y=35). There’s no special reason for these coordinates. I just wanted to show you that you can place images anywhere on the screen, not just at point zero. Feel free to try different position values and see what happens.
#![allow(unused)]
fn main() {
let raw_image = ImageRaw::<BinaryColor>::new(IMG_DATA, 31);
let image = Image::new(&raw_image, Point::new(35, 35));
}
Clone the existing project
You can also clone (or refer) project I created and navigate to the oled-rawimg folder.
git clone https://github.com/ImplFerris/pico2-embassy-projects
cd pico2-embassy-projects/blocking/oled-rawimg
The full code
#![no_std]
#![no_main]
use embassy_executor::Spawner;
use embassy_rp as hal;
use embassy_rp::block::ImageDef;
use embassy_time::Timer;
//Panic Handler
use panic_probe as _;
// Defmt Logging
use defmt_rtt as _;
// I2C
use embassy_rp::i2c::{self, Config};
// OLED
use ssd1306::{I2CDisplayInterface, Ssd1306, prelude::*};
// Embedded Graphics
use embedded_graphics::{
image::{Image, ImageRaw},
pixelcolor::BinaryColor,
prelude::Point,
prelude::*,
};
/// Tell the Boot ROM about our application
#[unsafe(link_section = ".start_block")]
#[used]
pub static IMAGE_DEF: ImageDef = hal::block::ImageDef::secure_exe();
// 31x7 pixel
#[rustfmt::skip]
const IMG_DATA: &[u8] = &[
// 1st row
0b00000001,0b11111111,0b11111111,0b00000000,
// 2nd row
0b00000001,0b11111111,0b11111111,0b00000000,
//3rd row
0b00000001,0b10000000,0b00000011,0b00000000,
//4th row
0b11111111,0b10000000,0b00000011,0b11111110,
//5th row
0b00000001,0b10000000,0b00000011,0b00000000,
//6th row
0b00000001,0b11111111,0b11111111,0b00000000,
//7th row
0b00000001,0b11111111,0b11111111,0b00000000,
];
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let sda = p.PIN_18;
let scl = p.PIN_19;
let mut i2c_config = Config::default();
i2c_config.frequency = 400_000; //400kHz
let i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, i2c_config);
let interface = I2CDisplayInterface::new(i2c);
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
.into_buffered_graphics_mode();
display.init().expect("failed to initialize the display");
let raw_image = ImageRaw::<BinaryColor>::new(IMG_DATA, 31);
let image = Image::new(&raw_image, Point::new(35, 35));
image
.draw(&mut display)
.expect("failed to draw text to display");
display.flush().expect("failed to flush data to display");
loop {
Timer::after_millis(100).await;
}
}
// Program metadata for `picotool info`.
// This isn't needed, but it's recomended to have these minimal entries.
#[unsafe(link_section = ".bi_entries")]
#[used]
pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
embassy_rp::binary_info::rp_program_name!(c"oled-rawimg"),
embassy_rp::binary_info::rp_program_description!(c"Multi Byte Image on OLED"),
embassy_rp::binary_info::rp_cargo_version!(),
embassy_rp::binary_info::rp_program_build_attribute!(),
];
// End of file