aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32u0
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2025-11-20 17:48:04 +0100
committerDion Dokter <[email protected]>2025-11-20 17:48:04 +0100
commitdd2a4d6126988d13e6ff21b26dc15deac1977531 (patch)
tree0112da38fbc16ea5265ac6f5e645849734311272 /examples/stm32u0
parentd111eceb4ba0094d34f58a4695bb3d43d188e591 (diff)
Create demo
Diffstat (limited to 'examples/stm32u0')
-rw-r--r--examples/stm32u0/src/bin/lcd.rs331
1 files changed, 325 insertions, 6 deletions
diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs
index f27c4458b..f401b1dcd 100644
--- a/examples/stm32u0/src/bin/lcd.rs
+++ b/examples/stm32u0/src/bin/lcd.rs
@@ -5,8 +5,10 @@ use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::{ 6use embassy_stm32::{
7 lcd::{Bias, Config, Duty, Lcd, LcdPin}, 7 lcd::{Bias, Config, Duty, Lcd, LcdPin},
8 peripherals::LCD,
8 time::Hertz, 9 time::Hertz,
9}; 10};
11use embassy_time::Duration;
10use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
11 13
12#[embassy_executor::main] 14#[embassy_executor::main]
@@ -72,15 +74,332 @@ async fn main(_spawner: Spawner) {
72 ], 74 ],
73 ); 75 );
74 76
77 {
78 let mut buffer = DisplayBuffer::new();
79 for i in 0..4 {
80 buffer.write_colon(i);
81 buffer.write(&mut lcd);
82 embassy_time::Timer::after_millis(200).await;
83 buffer.write_dot(i);
84 buffer.write(&mut lcd);
85 embassy_time::Timer::after_millis(200).await;
86 }
87 for i in 0..4 {
88 buffer.write_bar(i);
89 buffer.write(&mut lcd);
90 embassy_time::Timer::after_millis(200).await;
91 }
92 }
93
94 embassy_time::Timer::after_millis(1000).await;
95
96 const MESSAGE: &str = "Hello embassy people. Hope you like this LCD demo :} ";
75 loop { 97 loop {
76 defmt::info!("Writing frame"); 98 print_message(MESSAGE, &mut lcd, Duration::from_millis(250)).await;
77 lcd.write_frame(&[0xAAAAAAAA; 16]); 99 print_message(characters::ALL_CHARS, &mut lcd, Duration::from_millis(500)).await;
100 }
101}
102
103async fn print_message(message: &str, lcd: &mut Lcd<'_, LCD>, delay: Duration) {
104 let mut display_buffer = DisplayBuffer::new();
105
106 let mut char_buffer = [' '; 6];
107 for char in message.chars() {
108 char_buffer.copy_within(1.., 0);
109 char_buffer[5] = char;
110
111 display_buffer.clear();
112 for (i, char) in char_buffer.iter().enumerate() {
113 display_buffer.write_char(i, *char);
114 }
115 display_buffer.write(lcd);
116
117 embassy_time::Timer::after(delay).await;
118 }
119}
120
121/// Display layout for the U0-DK
122mod display_layout {
123 // Character layout. There are 6 characters, left-to-right
124 // T
125 // ─────────
126 // │ N │
127 // │ │ │ │ │
128 // TL │ └┐ │ ┌┘ │ TR
129 // │NW│ │ │NE│
130 // │ │ │
131 // W─── ───E
132 // │ │ │
133 // │SW│ │ │SE│
134 // BL │ ┌┘ │ └┐ │ BR
135 // │ │ │ │ │
136 // │ S │
137 // ─────────
138 // B
139
140 pub const CHAR_N_COM: u8 = 3;
141 pub const CHAR_N_SEG: [u8; 6] = [39, 37, 35, 48, 26, 33];
142 pub const CHAR_NW_COM: u8 = 3;
143 pub const CHAR_NW_SEG: [u8; 6] = [49, 38, 36, 34, 27, 24];
144 pub const CHAR_W_COM: u8 = 0;
145 pub const CHAR_W_SEG: [u8; 6] = CHAR_NW_SEG;
146 pub const CHAR_SW_COM: u8 = 2;
147 pub const CHAR_SW_SEG: [u8; 6] = CHAR_NW_SEG;
148 pub const CHAR_S_COM: u8 = 2;
149 pub const CHAR_S_SEG: [u8; 6] = [22, 6, 46, 11, 15, 29];
150 pub const CHAR_SE_COM: u8 = 3;
151 pub const CHAR_SE_SEG: [u8; 6] = CHAR_S_SEG;
152 pub const CHAR_E_COM: u8 = 0;
153 pub const CHAR_E_SEG: [u8; 6] = [23, 45, 47, 14, 28, 32];
154 pub const CHAR_NE_COM: u8 = 2;
155 pub const CHAR_NE_SEG: [u8; 6] = CHAR_N_SEG;
156 pub const CHAR_T_COM: u8 = 1;
157 pub const CHAR_T_SEG: [u8; 6] = CHAR_N_SEG;
158 pub const CHAR_TL_COM: u8 = 1;
159 pub const CHAR_TL_SEG: [u8; 6] = CHAR_NW_SEG;
160 pub const CHAR_BL_COM: u8 = 0;
161 pub const CHAR_BL_SEG: [u8; 6] = CHAR_S_SEG;
162 pub const CHAR_B_COM: u8 = 1;
163 pub const CHAR_B_SEG: [u8; 6] = CHAR_S_SEG;
164 pub const CHAR_BR_COM: u8 = 1;
165 pub const CHAR_BR_SEG: [u8; 6] = CHAR_E_SEG;
166 pub const CHAR_TR_COM: u8 = 0;
167 pub const CHAR_TR_SEG: [u8; 6] = CHAR_N_SEG;
168
169 pub const COLON_COM: u8 = 2;
170 pub const COLON_SEG: [u8; 4] = [23, 45, 47, 14];
171 pub const DOT_COM: u8 = 3;
172 pub const DOT_SEG: [u8; 4] = COLON_SEG;
173 /// COM + SEG, bar from top to bottom
174 pub const BAR: [(u8, u8); 4] = [(2, 28), (3, 28), (2, 32), (3, 32)];
175}
176
177mod characters {
178 use super::CharSegment::{self, *};
179
180 pub const CHAR_0: &[CharSegment] = &[T, TL, BL, B, BR, TR, NW, SE];
181 pub const CHAR_1: &[CharSegment] = &[NE, TR, BR];
182 pub const CHAR_2: &[CharSegment] = &[T, BL, B, TR, E, W];
183 pub const CHAR_3: &[CharSegment] = &[T, B, BR, TR, E];
184 pub const CHAR_4: &[CharSegment] = &[TL, BR, TR, E, W];
185 pub const CHAR_5: &[CharSegment] = &[T, TL, B, BR, E, W];
186 pub const CHAR_6: &[CharSegment] = &[T, TL, BL, B, BR, E, W];
187 pub const CHAR_7: &[CharSegment] = &[T, NE, S];
188 pub const CHAR_8: &[CharSegment] = &[T, TL, BL, B, BR, TR, E, W];
189 pub const CHAR_9: &[CharSegment] = &[T, TL, BR, TR, E, W];
190
191 pub const CHAR_COLON: &[CharSegment] = &[N, S];
192 pub const CHAR_SEMICOLON: &[CharSegment] = &[N, SW];
193 pub const CHAR_EQUALS: &[CharSegment] = &[E, W, B];
194 pub const CHAR_SLASH: &[CharSegment] = &[SW, NE];
195 pub const CHAR_BACKSLASH: &[CharSegment] = &[SE, NW];
196 pub const CHAR_PLUS: &[CharSegment] = &[N, E, S, W];
197 pub const CHAR_STAR: &[CharSegment] = &[NE, N, NW, SE, S, SW];
198 pub const CHAR_QUOTE: &[CharSegment] = &[N];
199 pub const CHAR_BACKTICK: &[CharSegment] = &[NW];
200 pub const CHAR_DASH: &[CharSegment] = &[W, E];
201 pub const CHAR_COMMA: &[CharSegment] = &[SW];
202 pub const CHAR_DOT: &[CharSegment] = &[S];
203 pub const CHAR_CURLYOPEN: &[CharSegment] = &[T, NW, W, SW, B];
204 pub const CHAR_CURLYCLOSE: &[CharSegment] = &[T, NE, E, SE, B];
205 pub const CHAR_AMPERSAND: &[CharSegment] = &[T, NE, NW, W, BL, B, SE];
206
207 pub const CHAR_A: &[CharSegment] = &[T, TL, TR, E, W, BL, BR];
208 pub const CHAR_B: &[CharSegment] = &[T, TR, BR, B, N, S, E];
209 pub const CHAR_C: &[CharSegment] = &[T, TL, BL, B];
210 pub const CHAR_D: &[CharSegment] = &[T, TR, BR, B, N, S];
211 pub const CHAR_E: &[CharSegment] = &[T, TL, BL, B, W];
212 pub const CHAR_F: &[CharSegment] = &[T, TL, BL, W];
213 pub const CHAR_G: &[CharSegment] = &[T, TL, BL, B, BR, E];
214 pub const CHAR_H: &[CharSegment] = &[TL, BL, E, W, TR, BR];
215 pub const CHAR_I: &[CharSegment] = &[T, N, S, B];
216 pub const CHAR_J: &[CharSegment] = &[TR, BR, B, BL];
217 pub const CHAR_K: &[CharSegment] = &[TL, BL, W, NE, SE];
218 pub const CHAR_L: &[CharSegment] = &[TL, BL, B];
219 pub const CHAR_M: &[CharSegment] = &[BL, TL, NW, NE, TR, BR];
220 pub const CHAR_N: &[CharSegment] = &[BL, TL, NW, SE, BR, TR];
221 pub const CHAR_O: &[CharSegment] = &[T, TL, BL, B, BR, TR];
222 pub const CHAR_P: &[CharSegment] = &[BL, TL, T, TR, E, W];
223 pub const CHAR_Q: &[CharSegment] = &[T, TL, BL, B, BR, TR, SE];
224 pub const CHAR_R: &[CharSegment] = &[BL, TL, T, TR, E, W, SE];
225 pub const CHAR_S: &[CharSegment] = &[T, NW, E, BR, B];
226 pub const CHAR_T: &[CharSegment] = &[T, N, S];
227 pub const CHAR_U: &[CharSegment] = &[TL, BL, B, BR, TR];
228 pub const CHAR_V: &[CharSegment] = &[TL, BL, SW, NE];
229 pub const CHAR_W: &[CharSegment] = &[TL, BL, SW, SE, BR, TR];
230 pub const CHAR_X: &[CharSegment] = &[NE, NW, SE, SW];
231 pub const CHAR_Y: &[CharSegment] = &[NE, NW, S];
232 pub const CHAR_Z: &[CharSegment] = &[T, NE, SW, B];
233
234 pub const CHAR_UNKNOWN: &[CharSegment] = &[N, NW, W, SW, S, SE, E, NE, T, TL, BL, B, BR, TR];
235
236 pub const ALL_CHARS: &str =
237 "0 1 2 3 4 5 6 7 8 9 : ; = / \\ + * ' ` - , . { } & A B C D E F G H I J K L M N O P Q R S T U V W X Y Z � ";
238
239 pub fn get_char_segments(val: char) -> &'static [CharSegment] {
240 match val {
241 val if val.is_whitespace() => &[],
242
243 '0' => CHAR_0,
244 '1' => CHAR_1,
245 '2' => CHAR_2,
246 '3' => CHAR_3,
247 '4' => CHAR_4,
248 '5' => CHAR_5,
249 '6' => CHAR_6,
250 '7' => CHAR_7,
251 '8' => CHAR_8,
252 '9' => CHAR_9,
253
254 ':' => CHAR_COLON,
255 ';' => CHAR_SEMICOLON,
256 '=' => CHAR_EQUALS,
257 '/' => CHAR_SLASH,
258 '\\' => CHAR_BACKSLASH,
259 '+' => CHAR_PLUS,
260 '*' => CHAR_STAR,
261 '\'' => CHAR_QUOTE,
262 '`' => CHAR_BACKTICK,
263 '-' => CHAR_DASH,
264 ',' => CHAR_COMMA,
265 '.' => CHAR_DOT,
266 '{' => CHAR_CURLYOPEN,
267 '}' => CHAR_CURLYCLOSE,
268 '&' => CHAR_AMPERSAND,
78 269
79 embassy_time::Timer::after_secs(1).await; 270 'A' | 'a' => CHAR_A,
271 'B' | 'b' => CHAR_B,
272 'C' | 'c' => CHAR_C,
273 'D' | 'd' => CHAR_D,
274 'E' | 'e' => CHAR_E,
275 'F' | 'f' => CHAR_F,
276 'G' | 'g' => CHAR_G,
277 'H' | 'h' => CHAR_H,
278 'I' | 'i' => CHAR_I,
279 'J' | 'j' => CHAR_J,
280 'K' | 'k' => CHAR_K,
281 'L' | 'l' => CHAR_L,
282 'M' | 'm' => CHAR_M,
283 'N' | 'n' => CHAR_N,
284 'O' | 'o' => CHAR_O,
285 'P' | 'p' => CHAR_P,
286 'Q' | 'q' => CHAR_Q,
287 'R' | 'r' => CHAR_R,
288 'S' | 's' => CHAR_S,
289 'T' | 't' => CHAR_T,
290 'U' | 'u' => CHAR_U,
291 'V' | 'v' => CHAR_V,
292 'W' | 'w' => CHAR_W,
293 'X' | 'x' => CHAR_X,
294 'Y' | 'y' => CHAR_Y,
295 'Z' | 'z' => CHAR_Z,
80 296
81 defmt::info!("Writing frame"); 297 _ => CHAR_UNKNOWN,
82 lcd.write_frame(&[!0xAAAAAAAA; 16]); 298 }
299 }
300}
301
302pub struct DisplayBuffer {
303 pixels: [u64; 4],
304}
305
306impl DisplayBuffer {
307 pub const fn new() -> Self {
308 Self { pixels: [0; 4] }
309 }
310
311 pub fn clear(&mut self) {
312 *self = Self::new();
313 }
314
315 fn write_char_segment(&mut self, index: usize, value: CharSegment) {
316 defmt::assert!(index < 6);
317 let (com, segments) = value.get_com_seg();
318 self.pixels[com as usize] |= 1 << segments[index];
319 }
320
321 pub fn write_char(&mut self, index: usize, val: char) {
322 let segments = characters::get_char_segments(val);
323
324 for segment in segments {
325 self.write_char_segment(index, *segment);
326 }
327 }
328
329 pub fn write(&self, lcd: &mut Lcd<'_, LCD>) {
330 lcd.write_com_segments(0, self.pixels[0]);
331 lcd.write_com_segments(1, self.pixels[1]);
332 lcd.write_com_segments(2, self.pixels[2]);
333 lcd.write_com_segments(3, self.pixels[3]);
334 lcd.submit_frame();
335 }
336
337 pub fn write_colon(&mut self, index: usize) {
338 defmt::assert!(index < 4);
339 self.pixels[display_layout::COLON_COM as usize] |= 1 << display_layout::COLON_SEG[index];
340 }
341
342 pub fn write_dot(&mut self, index: usize) {
343 defmt::assert!(index < 4);
344 self.pixels[display_layout::DOT_COM as usize] |= 1 << display_layout::DOT_SEG[index];
345 }
346
347 pub fn write_bar(&mut self, index: usize) {
348 defmt::assert!(index < 4);
349 let (bar_com, bar_seg) = display_layout::BAR[index];
350 self.pixels[bar_com as usize] |= 1 << bar_seg;
351 }
352}
353
354#[derive(Debug, Clone, Copy)]
355enum CharSegment {
356 /// North
357 N,
358 /// North west
359 NW,
360 /// West
361 W,
362 /// South west
363 SW,
364 /// South
365 S,
366 /// South East
367 SE,
368 /// East
369 E,
370 /// North East
371 NE,
372 /// Top
373 T,
374 /// Top left
375 TL,
376 /// Bottom left
377 BL,
378 /// Bottom
379 B,
380 /// Bottom right
381 BR,
382 /// Top right
383 TR,
384}
83 385
84 embassy_time::Timer::after_secs(1).await; 386impl CharSegment {
387 fn get_com_seg(&self) -> (u8, [u8; 6]) {
388 match self {
389 CharSegment::N => (display_layout::CHAR_N_COM, display_layout::CHAR_N_SEG),
390 CharSegment::NW => (display_layout::CHAR_NW_COM, display_layout::CHAR_NW_SEG),
391 CharSegment::W => (display_layout::CHAR_W_COM, display_layout::CHAR_W_SEG),
392 CharSegment::SW => (display_layout::CHAR_SW_COM, display_layout::CHAR_SW_SEG),
393 CharSegment::S => (display_layout::CHAR_S_COM, display_layout::CHAR_S_SEG),
394 CharSegment::SE => (display_layout::CHAR_SE_COM, display_layout::CHAR_SE_SEG),
395 CharSegment::E => (display_layout::CHAR_E_COM, display_layout::CHAR_E_SEG),
396 CharSegment::NE => (display_layout::CHAR_NE_COM, display_layout::CHAR_NE_SEG),
397 CharSegment::T => (display_layout::CHAR_T_COM, display_layout::CHAR_T_SEG),
398 CharSegment::TL => (display_layout::CHAR_TL_COM, display_layout::CHAR_TL_SEG),
399 CharSegment::BL => (display_layout::CHAR_BL_COM, display_layout::CHAR_BL_SEG),
400 CharSegment::B => (display_layout::CHAR_B_COM, display_layout::CHAR_B_SEG),
401 CharSegment::BR => (display_layout::CHAR_BR_COM, display_layout::CHAR_BR_SEG),
402 CharSegment::TR => (display_layout::CHAR_TR_COM, display_layout::CHAR_TR_SEG),
403 }
85 } 404 }
86} 405}