LED matrix demo
This commit is contained in:
parent
40ce8dba2c
commit
0bab1d52a5
3 changed files with 127 additions and 14 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -766,6 +766,7 @@ dependencies = [
|
|||
"heapless",
|
||||
"mipidsi",
|
||||
"panic-probe",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1083,6 +1084,9 @@ name = "rgb"
|
|||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp-pac"
|
||||
|
|
|
|||
|
|
@ -47,3 +47,4 @@ mipidsi = "0.9.0"
|
|||
embedded-hal-bus = "0.3.0"
|
||||
embassy-futures = "0.1.2"
|
||||
heapless = "0.8.0"
|
||||
rgb = "0.8.52"
|
||||
|
|
|
|||
|
|
@ -1,36 +1,61 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::convert::Infallible;
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::select::select_array;
|
||||
use embassy_rp::bind_interrupts;
|
||||
use embassy_rp::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_rp::peripherals::PIO0;
|
||||
use embassy_rp::pio::Pio;
|
||||
use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program};
|
||||
use embassy_rp::pwm::{self, Pwm};
|
||||
use embassy_rp::rom_data::reset_to_usb_boot;
|
||||
use embassy_time::Delay;
|
||||
use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
|
||||
use embedded_hal_bus::spi::ExclusiveDevice;
|
||||
use heapless::String;
|
||||
use mipidsi::interface::SpiInterface;
|
||||
use mipidsi::models::ST7789;
|
||||
use mipidsi::options::Orientation;
|
||||
use rgb::RGB8;
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
use embassy_rp::spi;
|
||||
use embassy_rp::spi::{Blocking, Spi};
|
||||
use embassy_rp::spi::{self, Blocking, Spi};
|
||||
use embedded_graphics::image::{Image, ImageRawLE};
|
||||
use embedded_graphics::mono_font::MonoTextStyle;
|
||||
use embedded_graphics::mono_font::ascii::FONT_10X20;
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics::text::Text;
|
||||
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
PIO0_IRQ_0 => embassy_rp::pio::InterruptHandler<PIO0>;
|
||||
});
|
||||
|
||||
const DISPLAY_FREQ: u32 = 64_000_000;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) -> ! {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
|
||||
// Setup buttons
|
||||
let _btn_a = Input::new(p.PIN_12, Pull::Up);
|
||||
let _btn_b = Input::new(p.PIN_13, Pull::Up);
|
||||
// let _btn_x = Input::new(p.PIN_14, Pull::Up);
|
||||
let btn_y = Input::new(p.PIN_15, Pull::Up);
|
||||
|
||||
let mut btn_f1 = Input::new(p.PIN_11, Pull::Up);
|
||||
let mut btn_f2 = Input::new(p.PIN_14, Pull::Up);
|
||||
let mut btn_f3 = Input::new(p.PIN_9, Pull::Up);
|
||||
let mut btn_f4 = Input::new(p.PIN_3, Pull::Up);
|
||||
|
||||
spawner.spawn(dfu_button(btn_y)).ok();
|
||||
|
||||
// display SPI
|
||||
|
||||
let mut display_buffer = [0u8; 512];
|
||||
|
|
@ -87,16 +112,33 @@ async fn main(spawner: Spawner) -> ! {
|
|||
b_pwm.set_config(&b_config);
|
||||
};
|
||||
|
||||
// Setup buttons
|
||||
let _btn_a = Input::new(p.PIN_12, Pull::Up);
|
||||
let _btn_b = Input::new(p.PIN_13, Pull::Up);
|
||||
// let _btn_x = Input::new(p.PIN_14, Pull::Up);
|
||||
let btn_y = Input::new(p.PIN_15, Pull::Up);
|
||||
let mut led_pio = Pio::new(p.PIO0, Irqs);
|
||||
let led_program = PioWs2812Program::new(&mut led_pio.common);
|
||||
|
||||
let mut btn_f1 = Input::new(p.PIN_11, Pull::Up);
|
||||
let mut btn_f2 = Input::new(p.PIN_14, Pull::Up);
|
||||
let mut btn_f3 = Input::new(p.PIN_9, Pull::Up);
|
||||
let mut btn_f4 = Input::new(p.PIN_3, Pull::Up);
|
||||
let mut led_surface = LedMatrix::new(
|
||||
Serpentine {
|
||||
size: Size::new(40, 8),
|
||||
},
|
||||
PioWs2812::new(
|
||||
&mut led_pio.common,
|
||||
led_pio.sm0,
|
||||
p.DMA_CH0,
|
||||
p.PIN_10,
|
||||
&led_program,
|
||||
),
|
||||
);
|
||||
led_surface.clear(Rgb888::BLACK).ok();
|
||||
Rectangle::new(Point::zero(), led_surface.size())
|
||||
.into_styled(
|
||||
PrimitiveStyleBuilder::new()
|
||||
.stroke_color(Rgb888::RED)
|
||||
.stroke_width(1)
|
||||
.fill_color(Rgb888::CSS_DARK_BLUE)
|
||||
.build(),
|
||||
)
|
||||
.draw(&mut led_surface)
|
||||
.ok();
|
||||
led_surface.sync().await;
|
||||
|
||||
let mut render = |f_keys: [bool; 4]| {
|
||||
display.clear(Rgb565::BLACK).ok();
|
||||
|
|
@ -115,8 +157,6 @@ async fn main(spawner: Spawner) -> ! {
|
|||
|
||||
let mut last_state = None;
|
||||
|
||||
spawner.spawn(dfu_button(btn_y)).ok();
|
||||
|
||||
loop {
|
||||
let state = [
|
||||
btn_f1.is_low(),
|
||||
|
|
@ -144,3 +184,71 @@ async fn dfu_button(mut btn_y: Input<'static>) {
|
|||
btn_y.wait_for_falling_edge().await;
|
||||
reset_to_usb_boot(0, 0);
|
||||
}
|
||||
|
||||
struct Serpentine {
|
||||
size: Size,
|
||||
}
|
||||
|
||||
impl Serpentine {
|
||||
fn map(&self, mut p: Point) -> Option<usize> {
|
||||
if p.x < 0 || p.x as u32 >= self.size.width || p.y < 0 || p.y as u32 >= self.size.height {
|
||||
return None;
|
||||
}
|
||||
|
||||
if p.y % 2 == 0 {
|
||||
p.x = self.size.width as i32 - 1 - p.x;
|
||||
}
|
||||
|
||||
Some(p.y as usize * self.size.width as usize + p.x as usize)
|
||||
}
|
||||
}
|
||||
|
||||
struct LedMatrix<'d> {
|
||||
buffer: [RGB8; 320],
|
||||
layout: Serpentine,
|
||||
pio: PioWs2812<'d, PIO0, 0, 320>,
|
||||
}
|
||||
|
||||
impl<'d> LedMatrix<'d> {
|
||||
fn new(layout: Serpentine, pio: PioWs2812<'d, PIO0, 0, 320>) -> Self {
|
||||
Self {
|
||||
buffer: [RGB8::default(); 320],
|
||||
layout,
|
||||
pio,
|
||||
}
|
||||
}
|
||||
|
||||
async fn sync(&mut self) {
|
||||
self.pio.write(&self.buffer).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> DrawTarget for LedMatrix<'d> {
|
||||
type Color = Rgb888;
|
||||
|
||||
type Error = Infallible;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = Pixel<Self::Color>>,
|
||||
{
|
||||
for Pixel(point, color) in pixels {
|
||||
if let Some(x) = self.layout.map(point).and_then(|i| self.buffer.get_mut(i)) {
|
||||
// Map to 0-64 for brightness limiting
|
||||
*x = RGB8::new(
|
||||
color.r().div_ceil(4),
|
||||
color.g().div_ceil(4),
|
||||
color.b().div_ceil(4),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> OriginDimensions for LedMatrix<'d> {
|
||||
fn size(&self) -> Size {
|
||||
self.layout.size
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue