alpha
Login
or
Join now
arthomnix.dev
/
eepy
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
fw16-epd-main: implement sleep
author
arthomnix
date
1 year ago
(Jan 12, 2025, 1:43 PM UTC)
commit
23b73e75
23b73e75863b0d908927676479754469a356786e
parent
3e08acd0
3e08acd071ff2a83cba079ba0da433cc83f75582
+180
-43
5 changed files
Expand all
Collapse all
Unified
Split
Cargo.toml
fw16-epd-bsp
src
lib.rs
fw16-epd-main
Cargo.toml
src
gui.rs
main.rs
-1
Cargo.toml
Reviewed
···
14
14
cortex-m = "0.7"
15
15
cortex-m-rt = "0.7"
16
16
embedded-hal = "1.0"
17
17
-
embedded-hal-bus = "0.2"
18
17
defmt = "0.3"
19
18
defmt-rtt = "0.4"
20
19
panic-probe = { version = "0.3", features = ["print-defmt"] }
+18
-3
fw16-epd-bsp/src/lib.rs
Reviewed
···
21
21
}
22
22
},
23
23
24
24
-
Gpio3 { name: epd_touch_rst },
24
24
+
Gpio3 {
25
25
+
name: epd_touch_rst,
26
26
+
aliases: {
27
27
+
FunctionSioOutput, PullNone: EpdTouchReset
28
28
+
}
29
29
+
},
25
30
26
31
Gpio4 {
27
32
name: i2c_sda,
···
37
42
}
38
43
}
39
44
40
40
-
Gpio6 { name: epd_pwr_sw },
45
45
+
Gpio6 {
46
46
+
name: epd_pwr_sw,
47
47
+
aliases: {
48
48
+
FunctionSioOutput, PullNone: EpdPowerSwitch
49
49
+
}
50
50
+
},
41
51
42
52
Gpio8 {
43
53
name: epd_busy,
···
83
93
}
84
94
}
85
95
86
86
-
Gpio25 { name: laptop_sleep },
96
96
+
Gpio25 {
97
97
+
name: laptop_sleep,
98
98
+
aliases: {
99
99
+
FunctionSioInput, PullUp: LaptopSleep
100
100
+
}
101
101
+
},
87
102
}
88
103
89
104
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
+1
-2
fw16-epd-main/Cargo.toml
Reviewed
···
12
12
cortex-m-rt.workspace = true
13
13
rp2040-flash.workspace = true
14
14
embedded-hal.workspace = true
15
15
-
embedded-hal-bus.workspace = true
16
15
defmt.workspace = true
17
16
defmt-rtt.workspace = true
18
17
panic-probe.workspace = true
···
23
22
usbd-serial.workspace = true
24
23
crc32fast.workspace = true
25
24
embedded-graphics.workspace = true
26
26
-
heapless.workspace = true
25
25
+
heapless.workspace = true
+3
fw16-epd-main/src/gui.rs
Reviewed
···
1
1
use core::fmt::Write;
2
2
+
use defmt::debug;
2
3
use embedded_graphics::mono_font::ascii::FONT_10X20;
3
4
use embedded_graphics::mono_font::MonoTextStyle;
4
5
use embedded_graphics::pixelcolor::BinaryColor;
···
12
13
use crate::{next_touch_event, set_touch_enabled};
13
14
14
15
pub(crate) fn gui_main(mut draw_target: EpdDrawTarget) -> ! {
16
16
+
debug!("gui_main");
17
17
+
15
18
draw_target.refresh(false, true);
16
19
17
20
unsafe { set_touch_enabled(true) };
+158
-37
fw16-epd-main/src/main.rs
Reviewed
···
12
12
use core::cell::RefCell;
13
13
use critical_section::Mutex;
14
14
use defmt::{debug, info, trace, warn};
15
15
-
use embedded_hal::digital::{OutputPin, PinState};
15
15
+
use embedded_hal::digital::{InputPin, OutputPin, PinState};
16
16
use embedded_hal::i2c::I2c;
17
17
use mcp9808::MCP9808;
18
18
+
use mcp9808::reg_conf::{Configuration, ShutdownMode};
18
19
use mcp9808::reg_res::ResolutionVal;
19
20
use mcp9808::reg_temp_generic::ReadableTempRegister;
20
21
use portable_atomic::{AtomicBool, AtomicU8};
···
22
23
use usb_device::bus::UsbBusAllocator;
23
24
use usb_device::prelude::*;
24
25
use usbd_serial::SerialPort;
25
25
-
use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdReset, EpdSck, EpdSdaWrite, EpdTouchInt, I2CScl, I2CSda, Pins};
26
26
+
use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdPowerSwitch, EpdReset, EpdSck, EpdSdaWrite, EpdTouchInt, EpdTouchReset, I2CScl, I2CSda, LaptopSleep, Pins};
26
27
use fw16_epd_bsp::hal::{Sio, Timer, I2C};
27
28
use fw16_epd_bsp::hal::clocks::ClockSource;
28
29
use fw16_epd_bsp::hal::fugit::{RateExtU32, ExtU32};
29
29
-
use fw16_epd_bsp::hal::gpio::Interrupt::EdgeLow;
30
30
+
use fw16_epd_bsp::hal::gpio::Interrupt::{EdgeHigh, EdgeLow};
30
31
use fw16_epd_bsp::hal::multicore::{Multicore, Stack};
31
32
use fw16_epd_bsp::hal::timer::{Alarm, Alarm0};
32
32
-
use fw16_epd_bsp::pac::I2C0;
33
33
+
use fw16_epd_bsp::pac::{CorePeripherals, I2C0};
33
34
use fw16_epd_bsp::pac::interrupt;
34
35
use fw16_epd_gui::draw_target::EpdDrawTarget;
35
36
use fw16_epd_program_interface::{SafeOption, TouchEvent, TouchEventType};
···
41
42
42
43
static GLOBAL_TOUCH_INT_PIN: Mutex<RefCell<Option<EpdTouchInt>>> = Mutex::new(RefCell::new(None));
43
44
static GLOBAL_I2C: Mutex<RefCell<Option<I2C<I2C0, (I2CSda, I2CScl)>>>> = Mutex::new(RefCell::new(None));
45
45
+
static GLOBAL_SLEEP_PIN: Mutex<RefCell<Option<LaptopSleep>>> = Mutex::new(RefCell::new(None));
46
46
+
static GLOBAL_EPD_POWER_PIN: Mutex<RefCell<Option<EpdPowerSwitch>>> = Mutex::new(RefCell::new(None));
47
47
+
static GLOBAL_TOUCH_RESET_PIN: Mutex<RefCell<Option<EpdTouchReset>>> = Mutex::new(RefCell::new(None));
44
48
45
49
static GLOBAL_ALARM0: Mutex<RefCell<Option<Alarm0>>> = Mutex::new(RefCell::new(None));
46
50
47
51
static IMAGE_BUFFER: Mutex<RefCell<[u8; IMAGE_BYTES]>> = Mutex::new(RefCell::new([0; IMAGE_BYTES]));
48
52
static DO_REFRESH: AtomicBool = AtomicBool::new(false);
49
53
static FAST_REFRESH: AtomicBool = AtomicBool::new(false);
54
54
+
static REFRESHING: AtomicBool = AtomicBool::new(false);
55
55
+
static EPD_NEEDS_HARD_RESET: AtomicBool = AtomicBool::new(true);
50
56
static TEMP: AtomicU8 = AtomicU8::new(20);
51
57
52
58
static mut GLOBAL_USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
···
54
60
static mut GLOBAL_USB_SERIAL: Option<SerialPort<hal::usb::UsbBus>> = None;
55
61
56
62
static TOUCH_EVENT_BUFFER: Mutex<RefCell<TouchEventBuffer>> = Mutex::new(RefCell::new(TouchEventBuffer::new()));
63
63
+
static TOUCH_ENABLED: AtomicBool = AtomicBool::new(false);
57
64
58
65
extern "C" fn write_image(image: &[u8; IMAGE_BYTES]) {
59
66
critical_section::with(|cs| IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(image));
···
74
81
}
75
82
76
83
unsafe extern "C" fn set_touch_enabled(enable: bool) {
77
77
-
if enable {
78
78
-
pac::NVIC::unpend(interrupt::IO_IRQ_BANK0);
79
79
-
pac::NVIC::unmask(interrupt::IO_IRQ_BANK0);
80
80
-
} else {
81
81
-
pac::NVIC::mask(interrupt::IO_IRQ_BANK0);
84
84
+
TOUCH_ENABLED.store(enable, Ordering::Relaxed);
85
85
+
if !enable {
82
86
critical_section::with(|cs| TOUCH_EVENT_BUFFER.borrow_ref_mut(cs).clear());
83
87
}
84
88
}
···
143
147
#[entry]
144
148
fn main() -> ! {
145
149
let mut pac = pac::Peripherals::take().unwrap();
150
150
+
let mut core = pac::CorePeripherals::take().unwrap();
146
151
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
147
152
148
153
let clocks = hal::clocks::init_clocks_and_plls(
···
154
159
&mut pac.RESETS,
155
160
&mut watchdog,
156
161
).unwrap();
162
162
+
163
163
+
core.SCB.set_sleepdeep();
157
164
158
165
// Read flash unique ID
159
166
cortex_m::interrupt::disable();
···
185
192
);
186
193
187
194
188
188
-
let _power = pins.epd_pwr_sw.into_push_pull_output_in_state(PinState::Low);
195
195
+
let mut epd_power: EpdPowerSwitch = pins.epd_pwr_sw.reconfigure();
196
196
+
epd_power.set_low().unwrap();
197
197
+
critical_section::with(|cs| GLOBAL_EPD_POWER_PIN.borrow_ref_mut(cs).replace(epd_power));
198
198
+
199
199
+
let mut sleep = pins.laptop_sleep.into_pull_up_input();
200
200
+
sleep.set_interrupt_enabled(EdgeLow, true);
201
201
+
sleep.set_interrupt_enabled(EdgeHigh, true);
202
202
+
sleep.clear_interrupt(EdgeLow);
203
203
+
sleep.clear_interrupt(EdgeHigh);
204
204
+
critical_section::with(|cs| GLOBAL_SLEEP_PIN.borrow_ref_mut(cs).replace(sleep));
189
205
190
190
-
let mut touch_reset = pins.epd_touch_rst.into_push_pull_output_in_state(PinState::High);
206
206
+
let mut touch_reset: EpdTouchReset = pins.epd_touch_rst.reconfigure();
207
207
+
touch_reset.set_high().unwrap();
191
208
cortex_m::asm::delay(1000000);
192
209
touch_reset.set_low().unwrap();
193
210
cortex_m::asm::delay(1000000);
194
211
touch_reset.set_high().unwrap();
195
212
cortex_m::asm::delay(10000000);
213
213
+
critical_section::with(|cs| GLOBAL_TOUCH_RESET_PIN.borrow_ref_mut(cs).replace(touch_reset));
196
214
197
215
let cs: EpdCs = pins.spi3_epd_cs.reconfigure();
198
216
let dc: EpdDc = pins.epd_dc.reconfigure();
···
204
222
let i2c_sda: I2CSda = pins.i2c_sda.reconfigure();
205
223
let i2c_scl: I2CScl = pins.i2c_scl.reconfigure();
206
224
let int: EpdTouchInt = pins.epd_touch_int.reconfigure();
207
207
-
// Actually unmasking this interrupt is done by calling set_touch_enabled(true)
208
225
int.set_interrupt_enabled(EdgeLow, true);
209
226
210
227
let mut timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
211
228
let mut alarm = timer.alarm_0().unwrap();
212
229
alarm.enable_interrupt();
213
230
critical_section::with(|cs| GLOBAL_ALARM0.borrow_ref_mut(cs).replace(alarm));
214
214
-
unsafe { pac::NVIC::unmask(interrupt::TIMER_IRQ_0); }
231
231
+
unsafe {
232
232
+
core.NVIC.set_priority(interrupt::TIMER_IRQ_0, 0b10000000);
233
233
+
pac::NVIC::unmask(interrupt::TIMER_IRQ_0);
234
234
+
}
215
235
pac::NVIC::pend(interrupt::TIMER_IRQ_0);
216
236
217
237
let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
···
262
282
unsafe { pac::NVIC::unmask(interrupt::USBCTRL_IRQ) };
263
283
264
284
let mut epd = Tp370pgh01::new(cs, IoPin::new(sda), sck, dc, busy, rst, timer, Rp2040PervasiveSpiDelays);
265
265
-
epd.hard_reset().unwrap();
266
285
267
286
let mut prev_image = [0u8; IMAGE_BYTES];
268
287
let mut image = [0u8; IMAGE_BYTES];
···
270
289
loop {
271
290
cortex_m::asm::wfe();
272
291
292
292
+
if EPD_NEEDS_HARD_RESET.swap(false, Ordering::Relaxed) {
293
293
+
epd.hard_reset().unwrap();
294
294
+
}
295
295
+
296
296
+
REFRESHING.store(true, Ordering::Relaxed);
297
297
+
273
298
if DO_REFRESH.swap(false, Ordering::Relaxed) {
274
299
if FAST_REFRESH.load(Ordering::Relaxed) {
275
300
prev_image.copy_from_slice(&image);
···
282
307
epd.refresh(&image, TEMP.load(Ordering::Relaxed)).unwrap();
283
308
}
284
309
}
310
310
+
311
311
+
REFRESHING.store(false, Ordering::Relaxed);
285
312
}
286
313
}).unwrap();
287
314
288
288
-
unsafe { set_touch_enabled(false) };
289
289
-
315
315
+
unsafe {
316
316
+
core.NVIC.set_priority(interrupt::IO_IRQ_BANK0, 0);
317
317
+
core.NVIC.set_priority(interrupt::SW0_IRQ, 0b01000000);
318
318
+
pac::NVIC::unmask(interrupt::IO_IRQ_BANK0);
319
319
+
pac::NVIC::unmask(interrupt::SW0_IRQ);
320
320
+
};
290
321
291
322
let draw_target = EpdDrawTarget::new(write_image, refresh);
292
292
-
293
323
gui::gui_main(draw_target);
294
324
}
295
325
···
368
398
#[interrupt]
369
399
fn IO_IRQ_BANK0() {
370
400
static mut TOUCH_INT_PIN: Option<EpdTouchInt> = None;
401
401
+
static mut SLEEP_PIN: Option<LaptopSleep> = None;
402
402
+
static mut EPD_POWER_PIN: Option<EpdPowerSwitch> = None;
403
403
+
static mut TOUCH_RESET_PIN: Option<EpdTouchReset> = None;
371
404
372
405
trace!("IO_IRQ_BANK0");
373
406
···
375
408
critical_section::with(|cs| *TOUCH_INT_PIN = GLOBAL_TOUCH_INT_PIN.borrow(cs).take());
376
409
}
377
410
411
411
+
if SLEEP_PIN.is_none() {
412
412
+
critical_section::with(|cs| *SLEEP_PIN = GLOBAL_SLEEP_PIN.borrow(cs).take());
413
413
+
}
414
414
+
415
415
+
if EPD_POWER_PIN.is_none() {
416
416
+
critical_section::with(|cs| *EPD_POWER_PIN = GLOBAL_EPD_POWER_PIN.borrow(cs).take());
417
417
+
}
418
418
+
419
419
+
if TOUCH_RESET_PIN.is_none() {
420
420
+
critical_section::with(|cs| *TOUCH_RESET_PIN = GLOBAL_TOUCH_RESET_PIN.borrow(cs).take());
421
421
+
}
422
422
+
378
423
let mut i2c = critical_section::with(|cs| GLOBAL_I2C.borrow(cs).take());
379
424
380
425
if let Some(pin) = TOUCH_INT_PIN {
381
381
-
if let Some(i2c) = &mut i2c {
382
382
-
let mut buf = [0u8; 9];
383
383
-
i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap();
384
384
-
let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16;
385
385
-
let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16;
426
426
+
if pin.interrupt_status(EdgeLow) {
427
427
+
428
428
+
if TOUCH_ENABLED.load(Ordering::Relaxed) {
429
429
+
if let Some(i2c) = &mut i2c {
430
430
+
let mut buf = [0u8; 9];
431
431
+
i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap();
432
432
+
let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16;
433
433
+
let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16;
434
434
+
435
435
+
let state = match buf[3] >> 6 {
436
436
+
0 => TouchEventType::Down,
437
437
+
1 => TouchEventType::Up,
438
438
+
2 => TouchEventType::Move,
439
439
+
_ => panic!("received invalid touch event type {}", buf[3] >> 6),
440
440
+
};
441
441
+
442
442
+
let event = TouchEvent {
443
443
+
ev_type: state,
444
444
+
x,
445
445
+
y,
446
446
+
};
447
447
+
448
448
+
debug!("touch event: {}", event);
449
449
+
450
450
+
if !critical_section::with(|cs| TOUCH_EVENT_BUFFER.borrow_ref_mut(cs).push(event)) {
451
451
+
warn!("touch event buffer full");
452
452
+
}
453
453
+
}
454
454
+
}
455
455
+
456
456
+
}
457
457
+
pin.clear_interrupt(EdgeLow);
458
458
+
}
386
459
387
387
-
let state = match buf[3] >> 6 {
388
388
-
0 => TouchEventType::Down,
389
389
-
1 => TouchEventType::Up,
390
390
-
2 => TouchEventType::Move,
391
391
-
_ => panic!("received invalid touch event type {}", buf[3] >> 6),
392
392
-
};
460
460
+
if let Some(pin) = SLEEP_PIN {
461
461
+
if pin.interrupt_status(EdgeLow) {
462
462
+
debug!("sleeping");
463
463
+
pin.clear_interrupt(EdgeLow);
464
464
+
465
465
+
if let Some(touch_int) = TOUCH_INT_PIN {
466
466
+
touch_int.set_interrupt_enabled(EdgeLow, false);
467
467
+
}
393
468
394
394
-
let event = TouchEvent {
395
395
-
ev_type: state,
396
396
-
x,
397
397
-
y,
398
398
-
};
469
469
+
// Wait until refresh has finished
470
470
+
while REFRESHING.load(Ordering::Relaxed) {}
399
471
400
400
-
debug!("touch event: {}", event);
472
472
+
// Power down temp sensor
473
473
+
if let Some(i2c) = &mut i2c {
474
474
+
let mut mcp9808 = MCP9808::new(i2c);
475
475
+
let mut config = mcp9808.read_configuration().unwrap();
476
476
+
config.set_shutdown_mode(ShutdownMode::Shutdown);
477
477
+
mcp9808.write_register(config).unwrap();
478
478
+
}
401
479
402
402
-
if !critical_section::with(|cs| TOUCH_EVENT_BUFFER.borrow_ref_mut(cs).push(event)) {
403
403
-
warn!("touch event buffer full");
480
480
+
// Power down display
481
481
+
if let Some(power_pin) = EPD_POWER_PIN {
482
482
+
power_pin.set_high().unwrap();
404
483
}
484
484
+
485
485
+
pac::NVIC::pend(interrupt::SW0_IRQ);
405
486
}
406
487
407
407
-
pin.clear_interrupt(EdgeLow);
488
488
+
if pin.interrupt_status(EdgeHigh) {
489
489
+
pin.clear_interrupt(EdgeHigh);
490
490
+
491
491
+
// Power up temp sensor
492
492
+
if let Some(i2c) = &mut i2c {
493
493
+
let mut mcp9808 = MCP9808::new(i2c);
494
494
+
let mut config = mcp9808.read_configuration().unwrap();
495
495
+
config.set_shutdown_mode(ShutdownMode::Continuous);
496
496
+
mcp9808.write_register(config).unwrap();
497
497
+
}
498
498
+
499
499
+
// Power up EPD
500
500
+
if let Some(power_pin) = EPD_POWER_PIN {
501
501
+
power_pin.set_low().unwrap();
502
502
+
}
503
503
+
504
504
+
EPD_NEEDS_HARD_RESET.store(true, Ordering::Relaxed);
505
505
+
506
506
+
if let Some(reset) = TOUCH_RESET_PIN {
507
507
+
cortex_m::asm::delay(1000000);
508
508
+
reset.set_high().unwrap();
509
509
+
cortex_m::asm::delay(1000000);
510
510
+
reset.set_low().unwrap();
511
511
+
cortex_m::asm::delay(1000000);
512
512
+
reset.set_high().unwrap();
513
513
+
cortex_m::asm::delay(10000000);
514
514
+
}
515
515
+
516
516
+
if let Some(touch_int) = TOUCH_INT_PIN {
517
517
+
touch_int.clear_interrupt(EdgeLow);
518
518
+
touch_int.set_interrupt_enabled(EdgeLow, true);
519
519
+
}
520
520
+
521
521
+
debug!("woken up");
522
522
+
}
408
523
}
409
524
410
525
critical_section::with(|cs| GLOBAL_I2C.borrow(cs).replace(i2c));
526
526
+
}
527
527
+
528
528
+
#[interrupt]
529
529
+
fn SW0_IRQ() {
530
530
+
trace!("SW0_IRQ");
531
531
+
cortex_m::asm::wfi();
411
532
}