Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
109 lines
2.9 KiB
Markdown
109 lines
2.9 KiB
Markdown
# SSD1306 driver
|
|
|
|
[](https://github.com/rust-embedded-community/ssd1306/actions/workflows/ci.yml)
|
|
[](https://crates.io/crates/ssd1306)
|
|
[](https://docs.rs/ssd1306)
|
|
|
|
[](examples/image_i2c.rs)
|
|
|
|
I2C and SPI (4 wire) driver for the SSD1306 OLED display.
|
|
|
|
## [Documentation](https://docs.rs/ssd1306)
|
|
|
|
## [Changelog](CHANGELOG.md)
|
|
|
|
## [Examples](examples)
|
|
|
|
This crate uses [`probe-run`](https://crates.io/crates/probe-run) to run the examples. Once set up,
|
|
it should be as simple as `cargo run --example <example name> --release`.
|
|
|
|
From [`examples/image_i2c.rs`](examples/image_i2c.rs):
|
|
|
|
```rust
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use cortex_m_rt::{entry, exception, ExceptionFrame};
|
|
use embedded_graphics::{
|
|
image::{Image, ImageRaw},
|
|
pixelcolor::BinaryColor,
|
|
prelude::*,
|
|
};
|
|
use panic_halt as _;
|
|
use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306};
|
|
use stm32f1xx_hal::{
|
|
i2c::{BlockingI2c, DutyCycle, Mode},
|
|
prelude::*,
|
|
stm32,
|
|
};
|
|
|
|
#[entry]
|
|
fn main() -> ! {
|
|
let dp = stm32::Peripherals::take().unwrap();
|
|
|
|
let mut flash = dp.FLASH.constrain();
|
|
let mut rcc = dp.RCC.constrain();
|
|
|
|
let clocks = rcc.cfgr.freeze(&mut flash.acr);
|
|
|
|
let mut afio = dp.AFIO.constrain(&mut rcc.apb2);
|
|
|
|
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
|
|
|
|
let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh);
|
|
let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);
|
|
|
|
let i2c = BlockingI2c::i2c1(
|
|
dp.I2C1,
|
|
(scl, sda),
|
|
&mut afio.mapr,
|
|
Mode::Fast {
|
|
frequency: 400_000.hz(),
|
|
duty_cycle: DutyCycle::Ratio2to1,
|
|
},
|
|
clocks,
|
|
&mut rcc.apb1,
|
|
1000,
|
|
10,
|
|
1000,
|
|
1000,
|
|
);
|
|
|
|
let interface = I2CDisplayInterface::new(i2c);
|
|
let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
|
|
.into_buffered_graphics_mode();
|
|
display.init().unwrap();
|
|
|
|
let raw: ImageRaw<BinaryColor> = ImageRaw::new(include_bytes!("./rust.raw"), 64);
|
|
|
|
let im = Image::new(&raw, Point::new(32, 0));
|
|
|
|
im.draw(&mut display).unwrap();
|
|
|
|
display.flush().unwrap();
|
|
|
|
loop {}
|
|
}
|
|
|
|
#[exception]
|
|
fn HardFault(ef: &ExceptionFrame) -> ! {
|
|
panic!("{:#?}", ef);
|
|
}
|
|
```
|
|
|
|
## License
|
|
|
|
Licensed under either of
|
|
|
|
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
http://www.apache.org/licenses/LICENSE-2.0)
|
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
|
|
at your option.
|
|
|
|
### Contribution
|
|
|
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
|
|
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
|
additional terms or conditions.
|