A fork of pulp-os for the xteink4 adding custom apps
2
fork

Configure Feed

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

add: basic display refresh

hansmrtn d50c3f3e 8dd15162

+151 -18
+40
Cargo.lock
··· 15 15 checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 16 16 17 17 [[package]] 18 + name = "az" 19 + version = "1.2.1" 20 + source = "registry+https://github.com/rust-lang/crates.io-index" 21 + checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 22 + 23 + [[package]] 18 24 name = "base64" 19 25 version = "0.13.1" 20 26 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 355 361 ] 356 362 357 363 [[package]] 364 + name = "embedded-graphics-core" 365 + version = "0.4.1" 366 + source = "registry+https://github.com/rust-lang/crates.io-index" 367 + checksum = "95743bef3ff70fcba3930246c4e6872882bbea0dcc6da2ca860112e0cd4bd09f" 368 + dependencies = [ 369 + "az", 370 + "byteorder", 371 + ] 372 + 373 + [[package]] 358 374 name = "embedded-hal" 359 375 version = "0.2.7" 360 376 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 376 392 source = "registry+https://github.com/rust-lang/crates.io-index" 377 393 checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" 378 394 dependencies = [ 395 + "embedded-hal 1.0.0", 396 + ] 397 + 398 + [[package]] 399 + name = "embedded-hal-bus" 400 + version = "0.3.0" 401 + source = "registry+https://github.com/rust-lang/crates.io-index" 402 + checksum = "513e0b3a8fb7d3013a8ae17a834283f170deaf7d0eeab0a7c1a36ad4dd356d22" 403 + dependencies = [ 404 + "critical-section", 379 405 "embedded-hal 1.0.0", 380 406 ] 381 407 ··· 1012 1038 "critical-section", 1013 1039 "embassy-executor", 1014 1040 "embassy-time", 1041 + "embedded-hal 1.0.0", 1042 + "embedded-hal-bus", 1015 1043 "esp-alloc", 1016 1044 "esp-backtrace", 1017 1045 "esp-bootloader-esp-idf", ··· 1019 1047 "esp-println", 1020 1048 "esp-rtos", 1021 1049 "log", 1050 + "ssd1677", 1022 1051 "static_cell", 1023 1052 ] 1024 1053 ··· 1184 1213 version = "0.2.2" 1185 1214 source = "registry+https://github.com/rust-lang/crates.io-index" 1186 1215 checksum = "a0f368519fc6c85fc1afdb769fb5a51123f6158013e143656e25a3485a0d401c" 1216 + 1217 + [[package]] 1218 + name = "ssd1677" 1219 + version = "0.1.0" 1220 + source = "registry+https://github.com/rust-lang/crates.io-index" 1221 + checksum = "2560a0e0d835b69b9666494f3337d723801db172255970d983996bb274d2be13" 1222 + dependencies = [ 1223 + "embedded-graphics-core", 1224 + "embedded-hal 1.0.0", 1225 + "log", 1226 + ] 1187 1227 1188 1228 [[package]] 1189 1229 name = "stable_deref_trait"
+3
Cargo.toml
··· 33 33 34 34 critical-section = "1.2.0" 35 35 static_cell = "2.1.1" 36 + embedded-hal = "1.0.0" 37 + ssd1677 = "0.1.0" 38 + embedded-hal-bus = "0.3.0" 36 39 37 40 38 41 [profile.dev]
+108 -18
src/bin/main.rs
··· 8 8 #![deny(clippy::large_stack_frames)] 9 9 10 10 use embassy_executor::Spawner; 11 - use embassy_time::{Duration, Timer}; 11 + // use embassy_time::{Duration, Timer}; 12 12 use esp_backtrace as _; 13 13 use esp_hal::analog::adc::{Adc, AdcCalCurve, AdcConfig, Attenuation}; 14 14 use esp_hal::clock::CpuClock; 15 - use esp_hal::gpio::{Input, InputConfig, Pull}; 16 - use esp_hal::peripherals::ADC1; 15 + // use esp_hal::gpio::{Input, InputConfig, Pull}; 16 + // use esp_hal::peripherals::ADC1; 17 17 use esp_hal::timer::timg::TimerGroup; 18 18 use log::info; 19 + 20 + use embassy_time::{Delay, Duration, Timer}; 21 + use esp_hal::{ 22 + gpio::{Input, InputConfig, Output, OutputConfig, Pull}, 23 + peripherals::ADC1, 24 + spi::master::{Config as SpiConfig, Spi}, 25 + time::Rate, 26 + }; 27 + use ssd1677::{ 28 + Builder, Dimensions, Display, Interface, RefreshMode, Region, Rotation, UpdateRegion, 29 + }; 19 30 20 31 extern crate alloc; 21 32 ··· 57 68 /// Decode GPIO1 resistor ladder (Right, Left, Confirm, Back) 58 69 /// Values ordered low → high. Idle = ~2851. 59 70 fn decode_gpio1(mv: u16) -> Option<Button> { 60 - if in_range(mv, 3, 50) { return Some(Button::Right); } 61 - if in_range(mv, 1113, TOLERANCE) { return Some(Button::Left); } 62 - if in_range(mv, 1984, TOLERANCE) { return Some(Button::Confirm); } 63 - if in_range(mv, 2556, TOLERANCE) { return Some(Button::Back); } 71 + if in_range(mv, 3, 50) { 72 + return Some(Button::Right); 73 + } 74 + if in_range(mv, 1113, TOLERANCE) { 75 + return Some(Button::Left); 76 + } 77 + if in_range(mv, 1984, TOLERANCE) { 78 + return Some(Button::Confirm); 79 + } 80 + if in_range(mv, 2556, TOLERANCE) { 81 + return Some(Button::Back); 82 + } 64 83 None 65 84 } 66 85 67 86 /// Decode GPIO2 resistor ladder (Vol Down, Vol Up) 68 87 /// Values ordered low → high. Idle = ~2851. 69 88 fn decode_gpio2(mv: u16) -> Option<Button> { 70 - if in_range(mv, 3, 50) { return Some(Button::VolDown); } 71 - if in_range(mv, 1659, TOLERANCE) { return Some(Button::VolUp); } 89 + if in_range(mv, 3, 50) { 90 + return Some(Button::VolDown); 91 + } 92 + if in_range(mv, 1659, TOLERANCE) { 93 + return Some(Button::VolUp); 94 + } 72 95 None 73 96 } 74 97 75 98 fn in_range(val: u16, center: u16, tol: u16) -> bool { 76 99 val >= center.saturating_sub(tol) && val <= center.saturating_add(tol) 77 100 } 78 - 79 101 80 102 #[allow( 81 103 clippy::large_stack_frames, ··· 97 119 98 120 // --- ADC setup with calibration --- 99 121 let mut adc1_config = AdcConfig::new(); 100 - let mut btn_row1_pin = adc1_config.enable_pin_with_cal::<_, AdcCalCurve<ADC1>>( 101 - peripherals.GPIO1, 102 - Attenuation::_11dB, 103 - ); 104 - let mut btn_row2_pin = adc1_config.enable_pin_with_cal::<_, AdcCalCurve<ADC1>>( 105 - peripherals.GPIO2, 106 - Attenuation::_11dB, 107 - ); 122 + let mut btn_row1_pin = adc1_config 123 + .enable_pin_with_cal::<_, AdcCalCurve<ADC1>>(peripherals.GPIO1, Attenuation::_11dB); 124 + let mut btn_row2_pin = adc1_config 125 + .enable_pin_with_cal::<_, AdcCalCurve<ADC1>>(peripherals.GPIO2, Attenuation::_11dB); 108 126 let mut adc1 = Adc::new(peripherals.ADC1, adc1_config).into_async(); 109 127 110 128 // Power button: digital, active LOW ··· 116 134 let _ = spawner; 117 135 118 136 let mut last_button: Option<Button> = None; 137 + 138 + let config = esp_hal::Config::default().with_cpu_clock(esp_hal::clock::CpuClock::max()); 139 + // let p = esp_hal::init(config); 140 + 141 + // --- EPD pins (Xteink X4 reference) --- 142 + // CS=21, DC=4, RST=5, BUSY=6; SCLK=8, MOSI=10 :contentReference[oaicite:8]{index=8} 143 + let cs = Output::new( 144 + peripherals.GPIO21, 145 + esp_hal::gpio::Level::High, 146 + OutputConfig::default(), 147 + ); 148 + let dc = Output::new( 149 + peripherals.GPIO4, 150 + esp_hal::gpio::Level::Low, 151 + OutputConfig::default(), 152 + ); 153 + let rst = Output::new( 154 + peripherals.GPIO5, 155 + esp_hal::gpio::Level::High, 156 + OutputConfig::default(), 157 + ); 158 + let busy = Input::new( 159 + peripherals.GPIO6, 160 + InputConfig::default().with_pull(Pull::None), 161 + ); 162 + 163 + // --- SPI (write-only is fine for most EPD flows) --- 164 + // Pick the correct SPI peripheral for your chip (ESP32-C3 commonly uses SPI2). 165 + let spi_cfg = SpiConfig::default().with_frequency(Rate::from_mhz(10)); // start conservative; you can raise later 166 + let spi_bus = Spi::new(peripherals.SPI2, spi_cfg) 167 + .unwrap() 168 + .with_sck(peripherals.GPIO8) 169 + .with_mosi(peripherals.GPIO10); 170 + 171 + let mut spi = embedded_hal_bus::spi::ExclusiveDevice::new(spi_bus, cs, Delay).unwrap(); 172 + 173 + // --- SSD1677 driver setup --- 174 + let interface = Interface::new(spi, dc, rst, busy); 175 + 176 + // Dimensions::new(rows, cols) == (height, width) per driver README. :contentReference[oaicite:10]{index=10} 177 + let dims = Dimensions::new(480, 800).unwrap(); 178 + let cfg = Builder::new() 179 + .dimensions(dims) 180 + .rotation(Rotation::Rotate0) 181 + .build() 182 + .unwrap(); 183 + 184 + let mut epd = Display::new(interface, cfg); 185 + 186 + // Blocking delay object that satisfies embedded-hal DelayNs. :contentReference[oaicite:11]{index=11} 187 + let mut delay = Delay; 188 + 189 + epd.reset(&mut delay); 190 + 191 + // --- Memory-friendly: update a small region --- 192 + // Region x and w should be multiples of 8 pixels (byte aligned). :contentReference[oaicite:12]{index=12} 193 + let region = Region::new(0, 0, 800, 480); // 200 must be multiple of 8; change as needed 194 + let n = region.buffer_size(); // compute required bytes :contentReference[oaicite:13]{index=13} 195 + 196 + let mut bw = alloc::vec![0xFFu8; n]; // all white (1=white, 0=black) :contentReference[oaicite:14]{index=14} 197 + // draw something by clearing bits in `bw`... 198 + 199 + let update = UpdateRegion { 200 + region, 201 + black_buffer: &bw, 202 + red_buffer: &[], // disables red plane :contentReference[oaicite:15]{index=15} 203 + mode: RefreshMode::Full, // or Full / Partial :contentReference[oaicite:16]{index=16} 204 + }; 205 + 206 + epd.update_region(update, &mut delay); 207 + 208 + info!("refreshed display!"); 119 209 120 210 loop { 121 211 // Read current button state