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>
137 lines
4.8 KiB
Rust
137 lines
4.8 KiB
Rust
//! 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")];
|