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: basic drawing and USB
author
arthomnix
date
1 year ago
(Jan 9, 2025, 10:44 AM UTC)
commit
985923c3
985923c3a4d0dd6c77df4b8483284d7941b86cce
parent
49f0f779
49f0f7792d3e416b8cd113868d14572fbcb1d37d
+336
-3
5 changed files
Expand all
Collapse all
Unified
Split
Cargo.toml
fw16-epd-main
.cargo
config.toml
Cargo.toml
src
main.rs
memory.x
+6
-1
Cargo.toml
Reviewed
···
16
16
embedded-hal-bus = "0.2"
17
17
defmt = "0.3"
18
18
defmt-rtt = "0.4"
19
19
-
panic-probe = { version = "0.3", features = ["print-defmt"] }
19
19
+
panic-probe = { version = "0.3", features = ["print-defmt"] }
20
20
+
critical-section = "1.2"
21
21
+
portable-atomic = { version = "1.10", features = ["critical-section"] }
22
22
+
mcp9808 = "0.4"
23
23
+
usb-device = "0.3"
24
24
+
usbd-serial = "0.2"
+7
fw16-epd-main/.cargo/config.toml
Reviewed
···
1
1
+
[target.thumbv6m-none-eabi]
2
2
+
rustflags = [
3
3
+
"-C", "link-arg=--nmagic",
4
4
+
"-C", "link-arg=-Tlink.x",
5
5
+
"-C", "link-arg=-Tdefmt.x",
6
6
+
]
7
7
+
runner = "probe-rs run --chip RP2040"
+7
-1
fw16-epd-main/Cargo.toml
Reviewed
···
5
5
6
6
[dependencies]
7
7
fw16-epd-bsp = { path = "../fw16-epd-bsp" }
8
8
+
tp370pgh01 = { path = "../tp370pgh01", features = ["rp2040"] }
8
9
cortex-m.workspace = true
9
10
cortex-m-rt.workspace = true
10
11
embedded-hal.workspace = true
11
12
embedded-hal-bus.workspace = true
12
13
defmt.workspace = true
13
14
defmt-rtt.workspace = true
14
14
-
panic-probe.workspace = true
15
15
+
panic-probe.workspace = true
16
16
+
critical-section.workspace = true
17
17
+
portable-atomic.workspace = true
18
18
+
mcp9808.workspace = true
19
19
+
usb-device.workspace = true
20
20
+
usbd-serial.workspace = true
+301
-1
fw16-epd-main/src/main.rs
Reviewed
···
6
6
#[allow(unused_imports)]
7
7
use defmt_rtt as _;
8
8
9
9
-
use fw16_epd_bsp::{entry, hal, pac};
9
9
+
use core::cell::{RefCell, RefMut};
10
10
+
use critical_section::Mutex;
11
11
+
use defmt::{debug, error, info, trace};
12
12
+
use embedded_hal::digital::PinState;
13
13
+
use embedded_hal::i2c::I2c;
14
14
+
use embedded_hal_bus::i2c::RefCellDevice;
15
15
+
use mcp9808::MCP9808;
16
16
+
use mcp9808::reg_res::ResolutionVal;
17
17
+
use mcp9808::reg_temp_generic::ReadableTempRegister;
18
18
+
use portable_atomic::{AtomicBool, AtomicU8};
19
19
+
use portable_atomic::Ordering;
20
20
+
use usb_device::bus::UsbBusAllocator;
21
21
+
use usb_device::prelude::*;
22
22
+
use usbd_serial::SerialPort;
23
23
+
use fw16_epd_bsp::{entry, hal, pac, EpdBusy, EpdCs, EpdDc, EpdReset, EpdSck, EpdSdaRead, EpdTouchInt, I2CScl, I2CSda, Pins};
24
24
+
use fw16_epd_bsp::hal::{Sio, Timer, I2C};
25
25
+
use fw16_epd_bsp::hal::clocks::ClockSource;
26
26
+
use fw16_epd_bsp::hal::fugit::RateExtU32;
27
27
+
use fw16_epd_bsp::hal::gpio::Interrupt::EdgeLow;
28
28
+
use fw16_epd_bsp::hal::multicore::{Multicore, Stack};
29
29
+
use fw16_epd_bsp::pac::I2C0;
30
30
+
use fw16_epd_bsp::pac::interrupt;
31
31
+
use tp370pgh01::rp2040::Rp2040PervasiveSpiDelays;
32
32
+
use tp370pgh01::Tp370pgh01;
33
33
+
34
34
+
static CORE1_STACK: Stack<8192> = Stack::new();
35
35
+
36
36
+
static GLOBAL_TOUCH_INT_PIN: Mutex<RefCell<Option<EpdTouchInt>>> = Mutex::new(RefCell::new(None));
37
37
+
static GLOBAL_I2C: Mutex<RefCell<Option<I2C<I2C0, (I2CSda, I2CScl)>>>> = Mutex::new(RefCell::new(None));
38
38
+
39
39
+
static IMAGE_BUFFER: Mutex<RefCell<[u8; tp370pgh01::IMAGE_BYTES]>> = Mutex::new(RefCell::new([0; tp370pgh01::IMAGE_BYTES]));
40
40
+
static DO_REFRESH: AtomicBool = AtomicBool::new(false);
41
41
+
static FAST_REFRESH: AtomicBool = AtomicBool::new(false);
42
42
+
static TEMP: AtomicU8 = AtomicU8::new(20);
43
43
+
44
44
+
static mut GLOBAL_USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
45
45
+
static mut GLOBAL_USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
46
46
+
static mut GLOBAL_USB_SERIAL: Option<SerialPort<hal::usb::UsbBus>> = None;
10
47
11
48
#[entry]
12
49
fn main() -> ! {
13
50
let mut pac = pac::Peripherals::take().unwrap();
51
51
+
let core = pac::CorePeripherals::take().unwrap();
14
52
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
15
53
16
54
let clocks = hal::clocks::init_clocks_and_plls(
···
23
61
&mut watchdog,
24
62
).unwrap();
25
63
64
64
+
let mut sio = Sio::new(pac.SIO);
65
65
+
let pins = Pins::new(
66
66
+
pac.IO_BANK0,
67
67
+
pac.PADS_BANK0,
68
68
+
sio.gpio_bank0,
69
69
+
&mut pac.RESETS,
70
70
+
);
71
71
+
72
72
+
73
73
+
let _power = pins.epd_pwr_sw.into_push_pull_output_in_state(PinState::Low);
74
74
+
75
75
+
let cs: EpdCs = pins.spi3_epd_cs.reconfigure();
76
76
+
let dc: EpdDc = pins.epd_dc.reconfigure();
77
77
+
let busy: EpdBusy = pins.epd_busy.reconfigure();
78
78
+
let rst: EpdReset = pins.epd_rst.reconfigure();
79
79
+
let sda: EpdSdaRead = pins.spi3_epd_sda.reconfigure();
80
80
+
let sck: EpdSck = pins.spi3_epd_sck.reconfigure();
81
81
+
82
82
+
let i2c_sda: I2CSda = pins.i2c_sda.reconfigure();
83
83
+
let i2c_scl: I2CScl = pins.i2c_scl.reconfigure();
84
84
+
let int: EpdTouchInt = pins.epd_touch_int.reconfigure();
85
85
+
86
86
+
let timer = Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);
87
87
+
88
88
+
let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
89
89
+
pac.USBCTRL_REGS,
90
90
+
pac.USBCTRL_DPRAM,
91
91
+
clocks.usb_clock,
92
92
+
true,
93
93
+
&mut pac.RESETS,
94
94
+
));
95
95
+
96
96
+
unsafe {
97
97
+
GLOBAL_USB_BUS = Some(usb_bus);
98
98
+
}
99
99
+
100
100
+
let bus_ref = unsafe { GLOBAL_USB_BUS.as_ref().unwrap() };
101
101
+
102
102
+
let serial = SerialPort::new(bus_ref);
103
103
+
let usb_device = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x2e8a, 0x000a))
104
104
+
.strings(&[StringDescriptors::default()
105
105
+
.manufacturer("arthomnix")
106
106
+
.product("Touchscreen EPD Input Module for Framework 16")
107
107
+
])
108
108
+
.unwrap()
109
109
+
.device_class(usbd_serial::USB_CLASS_CDC)
110
110
+
.build();
111
111
+
112
112
+
unsafe {
113
113
+
GLOBAL_USB_SERIAL = Some(serial);
114
114
+
GLOBAL_USB_DEVICE = Some(usb_device);
115
115
+
}
116
116
+
117
117
+
let mut mc = Multicore::new(&mut pac.PSM, &mut pac.PPB, &mut sio.fifo);
118
118
+
let core1 = &mut mc.cores()[1];
119
119
+
core1.spawn(CORE1_STACK.take().unwrap(), move || {
120
120
+
int.set_interrupt_enabled(EdgeLow, true);
121
121
+
122
122
+
let i2c = hal::i2c::I2C::i2c0(pac.I2C0, i2c_sda, i2c_scl, 400.kHz(), &mut pac.RESETS, clocks.system_clock.get_freq());
123
123
+
124
124
+
critical_section::with(|cs| {
125
125
+
GLOBAL_TOUCH_INT_PIN.borrow_ref_mut(cs).replace(int);
126
126
+
GLOBAL_I2C.borrow_ref_mut(cs).replace(i2c);
127
127
+
});
128
128
+
129
129
+
unsafe {
130
130
+
pac::NVIC::unmask(interrupt::IO_IRQ_BANK0);
131
131
+
pac::NVIC::unmask(interrupt::USBCTRL_IRQ);
132
132
+
}
133
133
+
134
134
+
let mut epd = Tp370pgh01::new(cs, Some(sda), sck, dc, busy, rst, timer, Rp2040PervasiveSpiDelays);
135
135
+
epd.hard_reset().unwrap();
136
136
+
137
137
+
let mut prev_image = [0u8; tp370pgh01::IMAGE_BYTES];
138
138
+
let mut image = [0u8; tp370pgh01::IMAGE_BYTES];
139
139
+
140
140
+
loop {
141
141
+
cortex_m::asm::wfe();
142
142
+
143
143
+
if DO_REFRESH.swap(false, Ordering::Relaxed) {
144
144
+
if FAST_REFRESH.load(Ordering::Relaxed) {
145
145
+
prev_image.copy_from_slice(&image);
146
146
+
critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref()));
147
147
+
epd.soft_reset().unwrap();
148
148
+
epd.refresh_fast(&image, &prev_image, TEMP.load(Ordering::Relaxed)).unwrap();
149
149
+
} else {
150
150
+
critical_section::with(|cs| image.copy_from_slice(IMAGE_BUFFER.borrow_ref(cs).as_ref()));
151
151
+
epd.soft_reset().unwrap();
152
152
+
epd.refresh(&image, TEMP.load(Ordering::Relaxed)).unwrap();
153
153
+
}
154
154
+
}
155
155
+
}
156
156
+
}).unwrap();
157
157
+
26
158
loop {
27
159
cortex_m::asm::wfi();
160
160
+
}
161
161
+
}
162
162
+
163
163
+
fn plot(data: &mut RefMut<[u8; 12480]>, x: u16, y: u16) {
164
164
+
let bit_index = (y as usize) * 240 + (x as usize);
165
165
+
let i = bit_index / 8;
166
166
+
let j = 1 << (bit_index % 8);
167
167
+
168
168
+
let val = &mut data[i];
169
169
+
*val |= j;
170
170
+
}
171
171
+
172
172
+
fn plot_line_low(data: &mut RefMut<[u8; 12480]>, x0: i16, y0: i16, x1: i16, y1: i16) {
173
173
+
let dx = x1 - x0;
174
174
+
let mut dy = y1 - y0;
175
175
+
let mut yi = 1;
176
176
+
if dy < 0 {
177
177
+
yi = -1;
178
178
+
dy = -dy;
179
179
+
}
180
180
+
let mut d = (2 * dy) - dx;
181
181
+
let mut y = y0;
182
182
+
183
183
+
for x in x0..=x1 {
184
184
+
plot(data, x as u16, y as u16);
185
185
+
if d > 0 {
186
186
+
y += yi;
187
187
+
d += 2 * (dy - dx);
188
188
+
} else {
189
189
+
d += 2 * dy;
190
190
+
}
191
191
+
}
192
192
+
}
193
193
+
194
194
+
fn plot_line_high(data: &mut RefMut<[u8; 12480]>, x0: i16, y0: i16, x1: i16, y1: i16) {
195
195
+
let mut dx = x1 - x0;
196
196
+
let dy = y1 - y0;
197
197
+
let mut xi = 1;
198
198
+
if dx < 0 {
199
199
+
xi = -1;
200
200
+
dx = -dx;
201
201
+
}
202
202
+
let mut d = (2 * dx) - dy;
203
203
+
let mut x = x0;
204
204
+
205
205
+
for y in y0..=y1 {
206
206
+
plot(data, x as u16, y as u16);
207
207
+
if d > 0 {
208
208
+
x += xi;
209
209
+
d += 2 * (dx - dy);
210
210
+
} else {
211
211
+
d += 2 * dx;
212
212
+
}
213
213
+
}
214
214
+
}
215
215
+
216
216
+
fn plot_line(data: &mut RefMut<[u8; 12480]>, x0: u16, y0: u16, x1: u16, y1: u16) {
217
217
+
if y1.abs_diff(y0) < x1.abs_diff(x0) {
218
218
+
if x0 > x1 {
219
219
+
plot_line_low(data, x1 as i16, y1 as i16, x0 as i16, y0 as i16);
220
220
+
} else {
221
221
+
plot_line_low(data, x0 as i16, y0 as i16, x1 as i16, y1 as i16);
222
222
+
}
223
223
+
} else {
224
224
+
if y0 > y1 {
225
225
+
plot_line_high(data, x1 as i16, y1 as i16, x0 as i16, y0 as i16);
226
226
+
} else {
227
227
+
plot_line_high(data, x0 as i16, y0 as i16, x1 as i16, y1 as i16);
228
228
+
}
229
229
+
}
230
230
+
}
231
231
+
232
232
+
#[interrupt]
233
233
+
fn USBCTRL_IRQ() {
234
234
+
static mut INDEX: usize = 0;
235
235
+
236
236
+
trace!("USBCTRL_IRQ");
237
237
+
238
238
+
let usb_dev = unsafe { GLOBAL_USB_DEVICE.as_mut().unwrap() };
239
239
+
let serial = unsafe { GLOBAL_USB_SERIAL.as_mut().unwrap() };
240
240
+
241
241
+
if usb_dev.poll(&mut [serial]) {
242
242
+
critical_section::with(|cs| {
243
243
+
let mut buf = IMAGE_BUFFER.borrow_ref_mut(cs);
244
244
+
match serial.read(&mut buf.as_mut()[*INDEX..]) {
245
245
+
Err(UsbError::WouldBlock) => {},
246
246
+
Err(e) => panic!("{e:?}"),
247
247
+
Ok(count) => {
248
248
+
*INDEX += count;
249
249
+
if *INDEX >= (240 * 416) / 8 {
250
250
+
info!("Finished rx frame over USB");
251
251
+
*INDEX = 0;
252
252
+
FAST_REFRESH.store(false, Ordering::Relaxed);
253
253
+
DO_REFRESH.store(true, Ordering::Relaxed);
254
254
+
}
255
255
+
}
256
256
+
}
257
257
+
})
258
258
+
}
259
259
+
}
260
260
+
261
261
+
#[interrupt]
262
262
+
fn IO_IRQ_BANK0() {
263
263
+
static mut TOUCH_INT_PIN: Option<EpdTouchInt> = None;
264
264
+
static mut I2C: Option<I2C<I2C0, (I2CSda, I2CScl)>> = None;
265
265
+
static mut PREV_POS: (u16, u16) = (0, 0);
266
266
+
267
267
+
trace!("IO_IRQ_BANK0");
268
268
+
269
269
+
if TOUCH_INT_PIN.is_none() {
270
270
+
critical_section::with(|cs| *TOUCH_INT_PIN = GLOBAL_TOUCH_INT_PIN.borrow(cs).take());
271
271
+
}
272
272
+
273
273
+
if I2C.is_none() {
274
274
+
critical_section::with(|cs| *I2C = GLOBAL_I2C.borrow(cs).take());
275
275
+
}
276
276
+
277
277
+
if let Some(i2c) = I2C {
278
278
+
let rc = RefCell::new(i2c);
279
279
+
let mut i2c = RefCellDevice::new(&rc);
280
280
+
let mut mcp9808 = MCP9808::new(RefCellDevice::new(&rc));
281
281
+
282
282
+
let temp = match mcp9808.read_temperature().unwrap().get_celsius(ResolutionVal::Deg_0_0625C) {
283
283
+
..=0.0 => 0u8,
284
284
+
60.0.. => 60u8,
285
285
+
t => t as u8,
286
286
+
};
287
287
+
TEMP.store(temp, Ordering::Relaxed);
288
288
+
289
289
+
if let Some(int) = TOUCH_INT_PIN {
290
290
+
if int.interrupt_status(EdgeLow) {
291
291
+
let mut buf = [0u8; 9];
292
292
+
i2c.write_read(0x38u8, &[0x00], &mut buf).unwrap();
293
293
+
let x = (((buf[3] & 0x0f) as u16) << 8) | buf[4] as u16;
294
294
+
let y = (((buf[5] & 0x0f) as u16) << 8) | buf[6] as u16;
295
295
+
296
296
+
let state = buf[3] >> 6;
297
297
+
298
298
+
if state == 1 && y > 400 {
299
299
+
critical_section::with(|cs| {
300
300
+
IMAGE_BUFFER.borrow_ref_mut(cs).copy_from_slice(&[0; (240 * 416) / 8]);
301
301
+
});
302
302
+
FAST_REFRESH.store(false, Ordering::Relaxed);
303
303
+
DO_REFRESH.store(true, Ordering::Relaxed);
304
304
+
} else if state == 1 && y < 20 {
305
305
+
hal::rom_data::reset_to_usb_boot(0, 0);
306
306
+
} else {
307
307
+
if state == 1 || state == 2 {
308
308
+
let (x0, y0) = *PREV_POS;
309
309
+
let (x1, y1) = (x, y);
310
310
+
critical_section::with(|cs| {
311
311
+
plot_line(&mut IMAGE_BUFFER.borrow_ref_mut(cs), x0, y0, x1, y1);
312
312
+
});
313
313
+
}
314
314
+
FAST_REFRESH.store(true, Ordering::Relaxed);
315
315
+
DO_REFRESH.store(true, Ordering::Relaxed);
316
316
+
317
317
+
if state == 0 || state == 2 {
318
318
+
*PREV_POS = (x, y);
319
319
+
}
320
320
+
}
321
321
+
int.clear_interrupt(EdgeLow);
322
322
+
}
323
323
+
} else {
324
324
+
error!("int pin is None");
325
325
+
}
326
326
+
} else {
327
327
+
error!("i2c is None");
28
328
}
29
329
}
+15
memory.x
Reviewed
···
1
1
+
MEMORY {
2
2
+
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3
3
+
FLASH : ORIGIN = 0x10000100, LENGTH = 16384K - 0x100
4
4
+
RAM : ORIGIN = 0x20000000, LENGTH = 256K
5
5
+
}
6
6
+
7
7
+
EXTERN(BOOT2_FIRMWARE)
8
8
+
9
9
+
SECTIONS {
10
10
+
/* ### Boot loader */
11
11
+
.boot2 ORIGIN(BOOT2) :
12
12
+
{
13
13
+
KEEP(*(.boot2));
14
14
+
} > BOOT2
15
15
+
} INSERT BEFORE .text;