mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-24 05:01:31 +11:00
Add an example for using the SSD1306 I2C display driver crate with the Raspberry Pi Pico
This commit is contained in:
parent
0cb171ffc8
commit
2f418bbf8f
|
@ -31,6 +31,8 @@ heapless = "0.7.9"
|
||||||
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
|
embedded-sdmmc = { git = "https://github.com/rust-embedded-community/embedded-sdmmc-rs.git" }
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
ws2812-pio = { git = "https://github.com/ithinuel/ws2812-pio-rs", rev = "4f0d81e594ea9934f9c4c38ed9824ad0cce4ebb5" }
|
||||||
|
ssd1306 = "0.7.0"
|
||||||
|
embedded-graphics = "0.7.1"
|
||||||
|
|
||||||
defmt = "0.2.0"
|
defmt = "0.2.0"
|
||||||
defmt-rtt = "0.2.0"
|
defmt-rtt = "0.2.0"
|
||||||
|
|
185
boards/rp-pico/examples/pico_i2c_oled_display_ssd1306.rs
Normal file
185
boards/rp-pico/examples/pico_i2c_oled_display_ssd1306.rs
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
//! # Pico (monochome) OLED Display with SSD1306 Driver Example
|
||||||
|
//!
|
||||||
|
//! See the `Cargo.toml` file for Copyright and licence details.
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
// The macro for our start-up function
|
||||||
|
use cortex_m_rt::entry;
|
||||||
|
|
||||||
|
// Time handling traits:
|
||||||
|
use embedded_time::duration::*;
|
||||||
|
use embedded_time::rate::Extensions;
|
||||||
|
|
||||||
|
// CountDown timer for the counter on the display:
|
||||||
|
use embedded_hal::timer::CountDown;
|
||||||
|
|
||||||
|
// Ensure we halt the program on panic (if we don't mention this crate it won't
|
||||||
|
// be linked)
|
||||||
|
use panic_halt as _;
|
||||||
|
|
||||||
|
// A shorter alias for the Peripheral Access Crate, which provides low-level
|
||||||
|
// register access
|
||||||
|
use rp_pico::hal::pac;
|
||||||
|
|
||||||
|
// A shorter alias for the Hardware Abstraction Layer, which provides
|
||||||
|
// higher-level drivers.
|
||||||
|
use rp_pico::hal;
|
||||||
|
|
||||||
|
// For in the graphics drawing utilities like the font
|
||||||
|
// and the drawing routines:
|
||||||
|
use embedded_graphics::{
|
||||||
|
mono_font::{ascii::FONT_9X18_BOLD, MonoTextStyleBuilder},
|
||||||
|
pixelcolor::BinaryColor,
|
||||||
|
prelude::*,
|
||||||
|
text::{Baseline, Text},
|
||||||
|
};
|
||||||
|
|
||||||
|
// The display driver:
|
||||||
|
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
||||||
|
|
||||||
|
/// Entry point to our bare-metal application.
|
||||||
|
///
|
||||||
|
/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
|
||||||
|
/// as soon as all global variables are initialised.
|
||||||
|
///
|
||||||
|
/// The function configures the RP2040 peripherals,
|
||||||
|
/// gets a handle on the I2C peripheral,
|
||||||
|
/// initializes the SSD1306 driver, initializes the text builder
|
||||||
|
/// and then draws some text on the display.
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
// Grab our singleton objects
|
||||||
|
let mut pac = pac::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
// Set up the watchdog driver - needed by the clock setup code
|
||||||
|
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
|
||||||
|
|
||||||
|
// Configure the clocks
|
||||||
|
//
|
||||||
|
// The default is to generate a 125 MHz system clock
|
||||||
|
let clocks =
|
||||||
|
hal::clocks::init_clocks_and_plls(
|
||||||
|
rp_pico::XOSC_CRYSTAL_FREQ,
|
||||||
|
pac.XOSC,
|
||||||
|
pac.CLOCKS,
|
||||||
|
pac.PLL_SYS,
|
||||||
|
pac.PLL_USB,
|
||||||
|
&mut pac.RESETS,
|
||||||
|
&mut watchdog)
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// The single-cycle I/O block controls our GPIO pins
|
||||||
|
let sio = hal::Sio::new(pac.SIO);
|
||||||
|
|
||||||
|
// Set the pins up according to their function on this particular board
|
||||||
|
let pins = rp_pico::Pins::new(
|
||||||
|
pac.IO_BANK0,
|
||||||
|
pac.PADS_BANK0,
|
||||||
|
sio.gpio_bank0,
|
||||||
|
&mut pac.RESETS,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Configure two pins as being I²C, not GPIO
|
||||||
|
let sda_pin = pins.gpio16.into_mode::<hal::gpio::FunctionI2C>();
|
||||||
|
let scl_pin = pins.gpio17.into_mode::<hal::gpio::FunctionI2C>();
|
||||||
|
|
||||||
|
// Create the I²C drive, using the two pre-configured pins. This will fail
|
||||||
|
// at compile time if the pins are in the wrong mode, or if this I²C
|
||||||
|
// peripheral isn't available on these pins!
|
||||||
|
let i2c = hal::I2C::i2c0(
|
||||||
|
pac.I2C0,
|
||||||
|
sda_pin,
|
||||||
|
scl_pin,
|
||||||
|
400.kHz(),
|
||||||
|
&mut pac.RESETS,
|
||||||
|
clocks.peripheral_clock,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create the I²C display interface:
|
||||||
|
let interface = I2CDisplayInterface::new(i2c);
|
||||||
|
|
||||||
|
// Create a driver instance and initialize:
|
||||||
|
let mut display =
|
||||||
|
Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
||||||
|
.into_buffered_graphics_mode();
|
||||||
|
display.init().unwrap();
|
||||||
|
|
||||||
|
// Create a text style for drawing the font:
|
||||||
|
let text_style = MonoTextStyleBuilder::new()
|
||||||
|
.font(&FONT_9X18_BOLD)
|
||||||
|
.text_color(BinaryColor::On)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
|
||||||
|
let mut delay = timer.count_down();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
let mut buf = FmtBuf::new();
|
||||||
|
loop {
|
||||||
|
buf.reset();
|
||||||
|
// Format some text into a static buffer:
|
||||||
|
core::fmt::write(&mut buf, format_args!("counter: {}", count)).unwrap();
|
||||||
|
count += 1;
|
||||||
|
|
||||||
|
// Empty the display:
|
||||||
|
display.clear();
|
||||||
|
|
||||||
|
// Draw 3 lines of text:
|
||||||
|
Text::with_baseline("Hello world!", Point::zero(), text_style, Baseline::Top)
|
||||||
|
.draw(&mut display)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Text::with_baseline("Hello Rust!", Point::new(0, 16), text_style, Baseline::Top)
|
||||||
|
.draw(&mut display)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Text::with_baseline(buf.as_str(), Point::new(0, 32), text_style, Baseline::Top)
|
||||||
|
.draw(&mut display)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
display.flush().unwrap();
|
||||||
|
|
||||||
|
// Wait a bit:
|
||||||
|
delay.start(500.milliseconds());
|
||||||
|
let _ = nb::block!(delay.wait());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a very simple buffer to pre format a short line of text.
|
||||||
|
struct FmtBuf {
|
||||||
|
buf: [u8; 64],
|
||||||
|
ptr: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FmtBuf {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
buf: [0; 64],
|
||||||
|
ptr: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.ptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_str(&self) -> &str {
|
||||||
|
core::str::from_utf8(&self.buf[0..self.ptr]).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::fmt::Write for FmtBuf {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
let len = s.len();
|
||||||
|
self.buf[self.ptr..(self.ptr + len)].copy_from_slice(s.as_bytes());
|
||||||
|
self.ptr += len;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// End of file
|
Loading…
Reference in a new issue