firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

initial embedded-graphics support

+125 -91
+2 -1
Cargo.toml
··· 22 22 mcp9808 = "0.4" 23 23 usb-device = "0.3" 24 24 usbd-serial = "0.2" 25 - crc32fast = { version = "1.4", default-features = false } 25 + crc32fast = { version = "1.4", default-features = false } 26 + embedded-graphics = { version = "0.8.1", features = ["defmt"] }
+3 -2
fw16-epd-main/Cargo.toml
··· 5 5 6 6 [dependencies] 7 7 fw16-epd-bsp = { path = "../fw16-epd-bsp" } 8 - fw16-epd-program-interface = { path = "../fw16-epd-program-interface" } 8 + fw16-epd-program-interface = { path = "../fw16-epd-program-interface", features = ["embedded-graphics"] } 9 9 tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040"] } 10 10 cortex-m.workspace = true 11 11 cortex-m-rt.workspace = true ··· 19 19 mcp9808.workspace = true 20 20 usb-device.workspace = true 21 21 usbd-serial.workspace = true 22 - crc32fast.workspace = true 22 + crc32fast.workspace = true 23 + embedded-graphics.workspace = true
+40 -86
fw16-epd-main/src/main.rs
··· 11 11 use core::cell::{RefCell, RefMut}; 12 12 use critical_section::Mutex; 13 13 use defmt::{debug, error, info, trace}; 14 + use embedded_graphics::pixelcolor::BinaryColor; 15 + use embedded_graphics::prelude::*; 16 + use embedded_graphics::primitives::{Line, PrimitiveStyle, PrimitiveStyleBuilder}; 14 17 use embedded_hal::digital::PinState; 15 18 use embedded_hal::i2c::I2c; 16 19 use embedded_hal_bus::i2c::RefCellDevice; ··· 30 33 use fw16_epd_bsp::hal::multicore::{Multicore, Stack}; 31 34 use fw16_epd_bsp::pac::I2C0; 32 35 use fw16_epd_bsp::pac::interrupt; 36 + use fw16_epd_program_interface::eg::EpdDrawTarget; 37 + use fw16_epd_program_interface::ProgramFunctionTable; 33 38 use tp370pgh01::rp2040::{Rp2040PervasiveSpiDelays, IoPin}; 34 - use tp370pgh01::Tp370pgh01; 39 + use tp370pgh01::{Tp370pgh01, IMAGE_BYTES}; 35 40 use crate::programs::Programs; 36 41 37 42 static CORE1_STACK: Stack<8192> = Stack::new(); ··· 47 52 static mut GLOBAL_USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None; 48 53 static mut GLOBAL_USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None; 49 54 static mut GLOBAL_USB_SERIAL: Option<SerialPort<hal::usb::UsbBus>> = None; 55 + 56 + extern "C" fn write_image(image: &[u8; IMAGE_BYTES]) { 57 + critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image)); 58 + } 59 + 60 + extern "C" fn refresh() { 61 + DO_REFRESH.store(true, Ordering::Relaxed); 62 + FAST_REFRESH.store(false, Ordering::Relaxed); 63 + cortex_m::asm::sev(); 64 + } 65 + 66 + extern "C" fn refresh_fast() { 67 + DO_REFRESH.store(true, Ordering::Relaxed); 68 + FAST_REFRESH.store(true, Ordering::Relaxed); 69 + cortex_m::asm::sev(); 70 + } 50 71 51 72 #[entry] 52 73 fn main() -> ! { ··· 169 190 } 170 191 } 171 192 172 - fn plot(data: &mut RefMut<[u8; 12480]>, x: u16, y: u16) { 173 - let bit_index = (y as usize) * 240 + (x as usize); 174 - let i = bit_index / 8; 175 - let j = 1 << (bit_index % 8); 176 - 177 - let val = &mut data[i]; 178 - *val |= j; 179 - } 180 - 181 - fn plot_line_low(data: &mut RefMut<[u8; 12480]>, x0: i16, y0: i16, x1: i16, y1: i16) { 182 - let dx = x1 - x0; 183 - let mut dy = y1 - y0; 184 - let mut yi = 1; 185 - if dy < 0 { 186 - yi = -1; 187 - dy = -dy; 188 - } 189 - let mut d = (2 * dy) - dx; 190 - let mut y = y0; 191 - 192 - for x in x0..=x1 { 193 - plot(data, x as u16, y as u16); 194 - if d > 0 { 195 - y += yi; 196 - d += 2 * (dy - dx); 197 - } else { 198 - d += 2 * dy; 199 - } 200 - } 201 - } 202 - 203 - fn plot_line_high(data: &mut RefMut<[u8; 12480]>, x0: i16, y0: i16, x1: i16, y1: i16) { 204 - let mut dx = x1 - x0; 205 - let dy = y1 - y0; 206 - let mut xi = 1; 207 - if dx < 0 { 208 - xi = -1; 209 - dx = -dx; 210 - } 211 - let mut d = (2 * dx) - dy; 212 - let mut x = x0; 213 - 214 - for y in y0..=y1 { 215 - plot(data, x as u16, y as u16); 216 - if d > 0 { 217 - x += xi; 218 - d += 2 * (dx - dy); 219 - } else { 220 - d += 2 * dx; 221 - } 222 - } 223 - } 224 - 225 - fn plot_line(data: &mut RefMut<[u8; 12480]>, x0: u16, y0: u16, x1: u16, y1: u16) { 226 - if y1.abs_diff(y0) < x1.abs_diff(x0) { 227 - if x0 > x1 { 228 - plot_line_low(data, x1 as i16, y1 as i16, x0 as i16, y0 as i16); 229 - } else { 230 - plot_line_low(data, x0 as i16, y0 as i16, x1 as i16, y1 as i16); 231 - } 232 - } else { 233 - if y0 > y1 { 234 - plot_line_high(data, x1 as i16, y1 as i16, x0 as i16, y0 as i16); 235 - } else { 236 - plot_line_high(data, x0 as i16, y0 as i16, x1 as i16, y1 as i16); 237 - } 238 - } 239 - } 240 - 241 193 #[interrupt] 242 194 fn USBCTRL_IRQ() { 243 195 static mut INDEX: usize = 0; ··· 271 223 fn IO_IRQ_BANK0() { 272 224 static mut TOUCH_INT_PIN: Option<EpdTouchInt> = None; 273 225 static mut I2C: Option<I2C<I2C0, (I2CSda, I2CScl)>> = None; 274 - static mut PREV_POS: (u16, u16) = (0, 0); 226 + static mut PREV_POS: Point = Point::new(0, 0); 227 + static mut DRAW_TARGET: EpdDrawTarget = EpdDrawTarget::new(ProgramFunctionTable { 228 + write_image, 229 + refresh, 230 + refresh_fast, 231 + }); 275 232 276 233 trace!("IO_IRQ_BANK0"); 277 234 ··· 299 256 if int.interrupt_status(EdgeLow) { 300 257 let mut buf = [0u8; 9]; 301 258 i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap(); 302 - let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16; 303 - let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16; 259 + let x = (((buf[3] & 0x0f) as i32) << 8) | buf[4] as i32; 260 + let y = (((buf[5] & 0x0f) as i32) << 8) | buf[6] as i32; 261 + debug!("touch event at ({}, {})", x, y); 262 + let pos = Point::new(x, y); 304 263 305 264 let state = buf[3] >> 6; 306 265 307 266 if state == 1 && y > 400 { 308 - critical_section::with(|cs| { 309 - IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(&[0; (240 * 416) / 8]); 310 - }); 311 - FAST_REFRESH.store(false, Ordering::Relaxed); 312 - DO_REFRESH.store(true, Ordering::Relaxed); 267 + DRAW_TARGET.clear(BinaryColor::Off).unwrap(); 268 + DRAW_TARGET.refresh(); 313 269 } else if state == 1 && y < 20 { 314 270 hal::rom_data::reset_to_usb_boot(0, 0); 315 271 } else { 316 272 if state == 1 || state == 2 { 317 - let (x0, y0) = *PREV_POS; 318 - let (x1, y1) = (x, y); 319 - critical_section::with(|cs| { 320 - plot_line(&mut IMAGE_BUFFER.borrow_ref_mut(cs), x0, y0, x1, y1); 321 - }); 273 + Line::new(PREV_POS.clone(), pos) 274 + .into_styled(PrimitiveStyle::with_stroke(BinaryColor::On, 5)) 275 + .draw(DRAW_TARGET) 276 + .unwrap(); 277 + DRAW_TARGET.refresh_fast(); 322 278 } 323 - FAST_REFRESH.store(true, Ordering::Relaxed); 324 - DO_REFRESH.store(true, Ordering::Relaxed); 325 279 326 280 if state == 0 || state == 2 { 327 - *PREV_POS = (x, y); 281 + *PREV_POS = Point::new(x, y); 328 282 } 329 283 } 330 284 int.clear_interrupt(EdgeLow);
+2 -1
fw16-epd-program-interface/Cargo.toml
··· 4 4 edition = "2021" 5 5 6 6 [dependencies] 7 - tp370pgh01 = { path = "../tp370pgh01" } 7 + tp370pgh01 = { path = "../tp370pgh01" } 8 + embedded-graphics = { workspace = true, optional = true }
+71
fw16-epd-program-interface/src/eg.rs
··· 1 + use core::convert::Infallible; 2 + use embedded_graphics::prelude::*; 3 + use embedded_graphics::geometry::Dimensions; 4 + use embedded_graphics::Pixel; 5 + use embedded_graphics::pixelcolor::BinaryColor; 6 + use embedded_graphics::primitives::Rectangle; 7 + use tp370pgh01::{DIM_X, DIM_Y, IMAGE_BYTES}; 8 + use crate::ProgramFunctionTable; 9 + 10 + pub struct EpdDrawTarget { 11 + functions: ProgramFunctionTable, 12 + buf: [u8; IMAGE_BYTES], 13 + } 14 + 15 + impl Dimensions for EpdDrawTarget { 16 + fn bounding_box(&self) -> Rectangle { 17 + Rectangle::new(Point::new(0, 0), Size::new(DIM_X as u32, DIM_Y as u32)) 18 + } 19 + } 20 + 21 + impl DrawTarget for EpdDrawTarget { 22 + type Color = BinaryColor; 23 + type Error = Infallible; 24 + 25 + fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error> 26 + where 27 + I: IntoIterator<Item = Pixel<Self::Color>>, 28 + { 29 + for Pixel(point @ Point { x, y }, colour) in pixels { 30 + if !self.bounding_box().contains(point) { 31 + continue; 32 + } 33 + 34 + let bit_index = (y as usize) * 240 + (x as usize); 35 + let i = bit_index >> 3; 36 + let j = 1 << (bit_index & 0x07); 37 + 38 + match colour { 39 + BinaryColor::Off => self.buf[i] &= !j, 40 + BinaryColor::On => self.buf[i] |= j, 41 + } 42 + } 43 + 44 + Ok(()) 45 + } 46 + 47 + fn clear(&mut self, colour: Self::Color) -> Result<(), Self::Error> { 48 + match colour { 49 + BinaryColor::Off => self.buf.copy_from_slice(&[0; IMAGE_BYTES]), 50 + BinaryColor::On => self.buf.copy_from_slice(&[u8::MAX; IMAGE_BYTES]), 51 + } 52 + 53 + Ok(()) 54 + } 55 + } 56 + 57 + impl EpdDrawTarget { 58 + pub const fn new(functions: ProgramFunctionTable) -> Self { 59 + Self { functions, buf: [0; IMAGE_BYTES] } 60 + } 61 + 62 + pub fn refresh(&self) { 63 + (self.functions.write_image)(&self.buf); 64 + (self.functions.refresh)(); 65 + } 66 + 67 + pub fn refresh_fast(&self) { 68 + (self.functions.write_image)(&self.buf); 69 + (self.functions.refresh_fast)(); 70 + } 71 + }
+7 -1
fw16-epd-program-interface/src/lib.rs
··· 1 1 #![no_std] 2 2 3 + #[cfg(feature = "embedded-graphics")] 4 + pub mod eg; 5 + 3 6 pub use tp370pgh01::IMAGE_BYTES; 4 7 5 8 #[repr(C)] 9 + #[derive(Copy, Clone)] 6 10 pub struct ProgramFunctionTable { 7 - write_epd_image: extern "C" fn(&[u8; IMAGE_BYTES]), 11 + pub write_image: extern "C" fn(&[u8; IMAGE_BYTES]), 12 + pub refresh: extern "C" fn(), 13 + pub refresh_fast: extern "C" fn(), 8 14 }