metronome/rust/pm-kit/src/main.rs
Me Here 17d2aa134d pm-kit: diagnostic display pattern + flip_horizontal (fix mirror)
Replace clear() with same-path full-screen fill, add a 4-edge red border, four
distinct corner markers (TL green / TR yellow / BL cyan / BR magenta) and a TL
label, to pin down rotation/mirror/size from one flash. Apply flip_horizontal to
match the panel's MADCTL MX bit (CircuitPython uses 0x48).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 21:16:34 -05:00

137 lines
4.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! PM_K-1 firmware — Stage 3 bring-up.
//! Milestone 1 (done): blink GP25 → proved boot/flash.
//! Milestone 2 (this): init the ST7796 320×480 display over SPI0 and draw to it.
//! Pins (from the CircuitPython firmware): SCK=GP2, MOSI=GP3, CS=GP5, DC=GP6, RST=GP7;
//! BGR panel, colours inverted. LED on GP25 keeps blinking as a heartbeat.
#![no_std]
#![no_main]
use embedded_graphics::{
mono_font::{ascii::FONT_10X20, MonoTextStyle},
pixelcolor::Rgb565,
prelude::*,
primitives::{PrimitiveStyle, PrimitiveStyleBuilder, Rectangle},
text::Text,
};
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::OutputPin;
use embedded_hal_bus::spi::ExclusiveDevice;
use mipidsi::interface::SpiInterface;
use mipidsi::models::ST7796;
use mipidsi::options::{ColorInversion, ColorOrder, Orientation};
use mipidsi::Builder;
use panic_halt as _;
use rp235x_hal as hal;
use hal::fugit::RateExtU32;
use hal::Clock;
/// Image definition block — the RP2350 bootrom looks for this to boot the image.
#[link_section = ".start_block"]
#[used]
pub static IMAGE_DEF: hal::block::ImageDef = hal::block::ImageDef::secure_exe();
const XTAL_FREQ_HZ: u32 = 12_000_000;
const WIDTH: u16 = 320;
const HEIGHT: u16 = 480;
#[hal::entry]
fn main() -> ! {
let mut pac = hal::pac::Peripherals::take().unwrap();
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
let clocks = hal::clocks::init_clocks_and_plls(
XTAL_FREQ_HZ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let mut timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
let sio = hal::Sio::new(pac.SIO);
let pins = hal::gpio::Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);
let mut led = pins.gpio25.into_push_pull_output();
// --- ST7796 over SPI0 ---
let sclk = pins.gpio2.into_function::<hal::gpio::FunctionSpi>();
let mosi = pins.gpio3.into_function::<hal::gpio::FunctionSpi>();
let dc = pins.gpio6.into_push_pull_output();
let rst = pins.gpio7.into_push_pull_output();
let cs = pins.gpio5.into_push_pull_output();
let spi = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (mosi, sclk));
let spi = spi.init(
&mut pac.RESETS,
clocks.peripheral_clock.freq(),
16.MHz(),
embedded_hal::spi::MODE_0,
);
let spi_device = ExclusiveDevice::new_no_delay(spi, cs).unwrap();
let mut buffer = [0u8; 512];
let di = SpiInterface::new(spi_device, dc, &mut buffer);
let mut display = Builder::new(ST7796, di)
.reset_pin(rst)
.display_size(WIDTH, HEIGHT)
.color_order(ColorOrder::Bgr)
.invert_colors(ColorInversion::Inverted)
.orientation(Orientation::new().flip_horizontal()) // panel wants MX set (matches CircuitPython MADCTL 0x48)
.init(&mut timer)
.unwrap();
let w = WIDTH as i32;
let h = HEIGHT as i32;
let m = 36; // marker size
// Full-screen fill via the SAME draw path as the shapes (clear() left snow last time).
Rectangle::new(Point::zero(), Size::new(WIDTH as u32, HEIGHT as u32))
.into_styled(PrimitiveStyle::with_fill(Rgb565::new(0, 0, 12)))
.draw(&mut display)
.unwrap();
// Red 8px border on all four edges — if any edge is missing, the addressed area != panel.
Rectangle::new(Point::zero(), Size::new(WIDTH as u32, HEIGHT as u32))
.into_styled(
PrimitiveStyleBuilder::new()
.stroke_color(Rgb565::RED)
.stroke_width(8)
.build(),
)
.draw(&mut display)
.unwrap();
// Distinct corner markers so orientation/mirror is unambiguous.
let ms = Size::new(m as u32, m as u32);
for (x, y, c) in [
(0, 0, Rgb565::GREEN), // top-left
(w - m, 0, Rgb565::YELLOW), // top-right
(0, h - m, Rgb565::CYAN), // bottom-left
(w - m, h - m, Rgb565::MAGENTA), // bottom-right
] {
Rectangle::new(Point::new(x, y), ms)
.into_styled(PrimitiveStyle::with_fill(c))
.draw(&mut display)
.unwrap();
}
// Labels: "TL" near origin, big "PMK" centred.
let label = MonoTextStyle::new(&FONT_10X20, Rgb565::WHITE);
Text::new("TL", Point::new(44, 28), label).draw(&mut display).unwrap();
Text::new("PMK", Point::new(w / 2 - 30, h / 2), label).draw(&mut display).unwrap();
loop {
led.set_high().unwrap();
timer.delay_ms(250);
led.set_low().unwrap();
timer.delay_ms(250);
}
}
/// picotool metadata (visible via `picotool info`).
#[link_section = ".bi_entries"]
#[used]
pub static PICOTOOL_ENTRIES: [hal::binary_info::EntryAddr; 1] =
[hal::binary_info::rp_program_name!(c"pm-kit display")];