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.

fw16-epd-main: initial work on program format

+173 -5
+1
.idea/epd_firmware.iml
··· 9 9 <sourceFolder url="file://$MODULE_DIR$/pervasive-spi/src" isTestSource="false" /> 10 10 <sourceFolder url="file://$MODULE_DIR$/tp370pgh01/src" isTestSource="false" /> 11 11 <sourceFolder url="file://$MODULE_DIR$/fw16-epd-main/src" isTestSource="false" /> 12 + <sourceFolder url="file://$MODULE_DIR$/fw16-epd-program-interface/src" isTestSource="false" /> 12 13 <excludeFolder url="file://$MODULE_DIR$/fw16_epd_bsp/target" /> 13 14 <excludeFolder url="file://$MODULE_DIR$/target" /> 14 15 <excludeFolder url="file://$MODULE_DIR$/fw16-epd-bsp/target" />
+3 -2
Cargo.toml
··· 3 3 4 4 members = [ 5 5 "fw16-epd-bsp", 6 - "fw16-epd-main", 6 + "fw16-epd-main", "fw16-epd-program-interface", 7 7 "pervasive-spi", 8 8 "tp370pgh01", 9 9 ] ··· 21 21 portable-atomic = { version = "1.10", features = ["critical-section"] } 22 22 mcp9808 = "0.4" 23 23 usb-device = "0.3" 24 - usbd-serial = "0.2" 24 + usbd-serial = "0.2" 25 + crc32fast = { version = "1.4", default-features = false }
+5
fw16-epd-main/.gdbinit
··· 1 + target extended-remote :3333 2 + 3 + define mri 4 + monitor reset init 5 + end
+3 -1
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 9 tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040"] } 9 10 cortex-m.workspace = true 10 11 cortex-m-rt.workspace = true ··· 17 18 portable-atomic.workspace = true 18 19 mcp9808.workspace = true 19 20 usb-device.workspace = true 20 - usbd-serial.workspace = true 21 + usbd-serial.workspace = true 22 + crc32fast.workspace = true
+9
fw16-epd-main/src/main.rs
··· 1 1 #![no_main] 2 2 #![no_std] 3 3 4 + mod programs; 5 + 4 6 #[allow(unused_imports)] 5 7 use panic_probe as _; 6 8 #[allow(unused_imports)] ··· 30 32 use fw16_epd_bsp::pac::interrupt; 31 33 use tp370pgh01::rp2040::{Rp2040PervasiveSpiDelays, IoPin}; 32 34 use tp370pgh01::Tp370pgh01; 35 + use crate::programs::Programs; 33 36 34 37 static CORE1_STACK: Stack<8192> = Stack::new(); 35 38 ··· 154 157 } 155 158 } 156 159 }).unwrap(); 160 + 161 + 162 + let programs = Programs::new(); 163 + for _program in programs { 164 + cortex_m::asm::delay(0); 165 + } 157 166 158 167 loop { 159 168 cortex_m::asm::wfi();
+127
fw16-epd-main/src/programs.rs
··· 1 + use core::marker::PhantomData; 2 + use core::str::Utf8Error; 3 + use defmt::debug; 4 + use fw16_epd_program_interface::ProgramFunctionTable; 5 + 6 + #[link_section = ".prog1"] 7 + #[used] 8 + static PROG1: [u32; 11] = [ 9 + 0, // block_erase_cycles 10 + 1419452448, // crc 11 + 44, // len 12 + 4, // name_len 13 + 32, // name_offset 14 + 5, // version_len 15 + 36, // version_offset 16 + 0, // entry_offset 17 + 0x74736554, 18 + 0x2E302E30, 19 + 0x00000032, 20 + ]; 21 + 22 + const XIP_BASE: *const u8 = 0x10000000 as *const u8; 23 + 24 + const SLOT_SIZE: usize = 0x80000; 25 + 26 + pub(crate) const unsafe fn slot<'a>(id: u8) -> &'a ProgramSlotHeader { 27 + if id < 1 || id > 31 { 28 + panic!("slot ID must be between 1 and 31"); 29 + } 30 + 31 + &*XIP_BASE.add(SLOT_SIZE * id as usize).cast::<ProgramSlotHeader>() 32 + } 33 + 34 + #[repr(C)] 35 + pub(crate) struct ProgramSlotHeader { 36 + pub(crate) block_erase_cycles: usize, 37 + pub(crate) crc: u32, 38 + pub(crate) len: usize, 39 + pub(crate) name_len: usize, 40 + pub(crate) name_offset: usize, 41 + pub(crate) version_len: usize, 42 + pub(crate) version_offset: usize, 43 + pub(crate) entry_offset: usize, 44 + } 45 + 46 + impl ProgramSlotHeader { 47 + fn ptr(&self) -> *const u8 { 48 + (&raw const *self).cast() 49 + } 50 + 51 + pub(crate) fn is_valid_program(&self) -> bool { 52 + self.len != 0 53 + && self.check_crc() 54 + && self.name_offset.saturating_add(self.name_len) <= self.len 55 + && self.version_offset.saturating_add(self.version_len) <= self.len 56 + && self.entry_offset < self.len 57 + && self.name().is_ok() 58 + && self.version_string().is_ok() 59 + } 60 + 61 + pub(crate) fn check_crc(&self) -> bool { 62 + if self.len >= SLOT_SIZE || self.len < size_of::<ProgramSlotHeader>() { 63 + return false; 64 + } 65 + 66 + let ptr = unsafe { self.ptr().add(8) }; 67 + let slice = unsafe { core::slice::from_raw_parts(ptr, self.len - 8) }; 68 + let crc = crc32fast::hash(slice); 69 + crc == self.crc 70 + } 71 + 72 + pub(crate) fn name(&self) -> Result<&str, Utf8Error> { 73 + let ptr = unsafe { self.ptr().add(self.name_offset) }; 74 + let slice = unsafe { core::slice::from_raw_parts(ptr, self.name_len) }; 75 + core::str::from_utf8(slice) 76 + } 77 + 78 + pub(crate) fn version_string(&self) -> Result<&str, Utf8Error> { 79 + let ptr = unsafe { self.ptr().add(self.version_offset) }; 80 + let slice = unsafe { core::slice::from_raw_parts(ptr, self.version_len) }; 81 + core::str::from_utf8(slice) 82 + } 83 + 84 + pub(crate) unsafe fn entry(&self) -> unsafe extern "C" fn(&ProgramFunctionTable) -> () { 85 + let ptr = self.ptr().add(self.entry_offset); 86 + core::mem::transmute(ptr) 87 + } 88 + } 89 + 90 + pub(crate) struct Programs<'a> { 91 + id: u8, 92 + _phantom: PhantomData<&'a ProgramSlotHeader>, 93 + } 94 + 95 + impl<'a> Programs<'a> { 96 + pub(crate) fn new() -> Self { 97 + Self { id: 0, _phantom: PhantomData } 98 + } 99 + } 100 + 101 + impl<'a> Iterator for Programs<'a> { 102 + type Item = &'a ProgramSlotHeader; 103 + 104 + fn next(&mut self) -> Option<Self::Item> { 105 + loop { 106 + self.id += 1; 107 + 108 + if self.id == 32 { 109 + return None; 110 + } 111 + 112 + let s = unsafe { slot(self.id) }; 113 + 114 + if s.is_valid_program() { 115 + debug!("Found program {} version {} in slot {}", s.name().unwrap(), s.version_string().unwrap(), self.id); 116 + return Some(s); 117 + } else { 118 + debug!("No program found in slot {}", self.id); 119 + } 120 + 121 + } 122 + } 123 + 124 + fn size_hint(&self) -> (usize, Option<usize>) { 125 + (0, Some(32 - self.id as usize)) 126 + } 127 + }
+7
fw16-epd-program-interface/Cargo.toml
··· 1 + [package] 2 + name = "fw16-epd-program-interface" 3 + version = "0.1.0" 4 + edition = "2021" 5 + 6 + [dependencies] 7 + tp370pgh01 = { path = "../tp370pgh01" }
+8
fw16-epd-program-interface/src/lib.rs
··· 1 + #![no_std] 2 + 3 + pub use tp370pgh01::IMAGE_BYTES; 4 + 5 + #[repr(C)] 6 + pub struct ProgramFunctionTable { 7 + write_epd_image: extern "C" fn(&[u8; IMAGE_BYTES]), 8 + }
+10 -2
memory.x
··· 1 1 MEMORY { 2 2 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 3 - FLASH : ORIGIN = 0x10000100, LENGTH = 16384K - 0x100 3 + FLASH : ORIGIN = 0x10000100, LENGTH = 256K - 0x100 4 + RESERVED: ORIGIN = 0x10040000, LENGTH = 256K 5 + PROGRAM_SLOT_1: ORIGIN = 0x10080000, LENGTH = 512K 4 6 RAM : ORIGIN = 0x20000000, LENGTH = 256K 5 7 } 6 8 ··· 12 14 { 13 15 KEEP(*(.boot2)); 14 16 } > BOOT2 15 - } INSERT BEFORE .text; 17 + } INSERT BEFORE .text; 18 + 19 + SECTIONS { 20 + .prog1 ORIGIN(PROGRAM_SLOT_1) : { 21 + KEEP(*(.prog1)); 22 + } > PROGRAM_SLOT_1 23 + } INSERT AFTER .text;