aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/lcd.rs
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2024-06-14 16:55:05 +0200
committerDion Dokter <[email protected]>2024-06-14 16:55:05 +0200
commitf758c4b3910e8cb4d09c284db245e66de8cb5e5e (patch)
tree095ac0d4fe20d6205f2dd531569f383e8c72d566 /embassy-stm32/src/lcd.rs
parent74739997bd70d3c23b5c58d25aa5c9ba4db55f35 (diff)
Start implementing lcd
Diffstat (limited to 'embassy-stm32/src/lcd.rs')
-rw-r--r--embassy-stm32/src/lcd.rs176
1 files changed, 176 insertions, 0 deletions
diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs
new file mode 100644
index 000000000..89fca416f
--- /dev/null
+++ b/embassy-stm32/src/lcd.rs
@@ -0,0 +1,176 @@
1//! LCD
2use core::marker::PhantomData;
3
4use embassy_hal_internal::{into_ref, PeripheralRef};
5
6use crate::gpio::{AFType, AnyPin, SealedPin};
7use crate::rcc::{self, RccPeripheral};
8use crate::{peripherals, Peripheral};
9
10#[non_exhaustive]
11#[derive(Debug, Default, Clone, Copy)]
12pub struct Config {
13 pub use_voltage_output_buffer: bool,
14 pub use_segment_muxing: bool,
15 pub bias: Bias,
16 pub duty: Duty,
17 pub voltage_source: VoltageSource,
18 pub high_drive: bool,
19}
20
21#[repr(u8)]
22#[derive(Debug, Default, Clone, Copy)]
23pub enum Bias {
24 #[default]
25 Quarter = 0b00,
26 Half = 0b01,
27 Third = 0b10,
28}
29
30#[repr(u8)]
31#[derive(Debug, Default, Clone, Copy)]
32pub enum Duty {
33 #[default]
34 Static = 0b000,
35 Half = 0b001,
36 Third = 0b010,
37 Quarter = 0b011,
38 /// In this mode, `COM[7:4]` outputs are available on `SEG[51:48]`.
39 /// This allows reducing the number of available segments.
40 Eigth = 0b100,
41}
42
43#[repr(u8)]
44#[derive(Debug, Default, Clone, Copy)]
45pub enum VoltageSource {
46 #[default]
47 /// Voltage stepup converter
48 Internal,
49 /// VLCD pin
50 External,
51}
52
53/// LCD driver.
54pub struct Lcd<'d, T: Instance> {
55 _peri: PhantomData<&'d mut T>,
56}
57
58impl<'d, T: Instance> Lcd<'d, T> {
59 /// Initialize the lcd driver
60 pub fn new<const N: usize>(_peri: impl Peripheral<P = T> + 'd, config: Config, pins: [LcdPin<'d, T>; N]) -> Self {
61 rcc::enable_and_reset::<T>();
62
63 for pin in pins {
64 pin.pin.set_as_af(pin.af_num, AFType::OutputPushPull);
65 }
66
67 T::regs().cr().write(|w| {
68 w.set_bufen(config.use_voltage_output_buffer);
69 w.set_mux_seg(config.use_segment_muxing);
70 w.set_bias(config.bias as u8);
71 w.set_duty(config.duty as u8);
72 w.set_vsel(matches!(config.voltage_source, VoltageSource::External));
73 });
74
75 while !T::regs().sr().read().fcrsf() { }
76
77 T::regs().fcr().modify(|w| {
78 w.set_dead(0);
79 w.set_pon(0b111);
80 // w.set_hd(config.high_drive);
81 });
82 while !T::regs().sr().read().fcrsf() { }
83
84 for i in 0..8 {
85 T::regs().ram_com(i).low().write_value(0);
86 T::regs().ram_com(i).high().write_value(0);
87 }
88 T::regs().sr().write(|w| w.set_udr(true));
89
90 while !T::regs().sr().read().fcrsf() { }
91
92 T::regs().fcr().modify(|w| {
93 w.set_ps(2);
94 w.set_div(4);
95 });
96 while !T::regs().sr().read().fcrsf() { }
97
98 T::regs().fcr().modify(|w| {
99 w.set_cc(7);
100 });
101 while !T::regs().sr().read().fcrsf() { }
102
103 T::regs().cr().modify(|w| w.set_lcden(true));
104
105 while !T::regs().sr().read().rdy() { }
106
107 Self { _peri: PhantomData }
108 }
109
110 pub fn write_frame(&mut self, data: &[u32; 16]) {
111 defmt::info!("{:06b}", T::regs().sr().read().0);
112
113 // Wait until the last update is done
114 while T::regs().sr().read().udr() { }
115
116 for i in 0..8 {
117 T::regs().ram_com(i).low().write_value(data[i * 2]);
118 T::regs().ram_com(i).low().write_value(data[i * 2 + 1]);
119 }
120 T::regs().sr().write(|w| w.set_udr(true));
121 }
122}
123
124impl<'d, T: Instance> Drop for Lcd<'d, T> {
125 fn drop(&mut self) {
126 rcc::disable::<T>();
127 }
128}
129
130pub struct LcdPin<'d, T: Instance> {
131 pin: PeripheralRef<'d, AnyPin>,
132 af_num: u8,
133 _phantom: PhantomData<T>,
134}
135
136impl<'d, T: Instance, Pin: Peripheral<P: SegComPin<T>> + 'd> From<Pin> for LcdPin<'d, T> {
137 fn from(value: Pin) -> Self {
138 Self::new(value)
139 }
140}
141
142impl<'d, T: Instance> LcdPin<'d, T> {
143 pub fn new(pin: impl Peripheral<P = impl SegComPin<T>> + 'd) -> Self {
144 into_ref!(pin);
145
146 let af = pin.af_num();
147
148 Self {
149 pin: pin.map_into(),
150 af_num: af,
151 _phantom: PhantomData,
152 }
153 }
154}
155
156trait SealedInstance: crate::rcc::SealedRccPeripheral {
157 fn regs() -> crate::pac::lcd::Lcd;
158}
159
160/// DSI instance trait.
161#[allow(private_bounds)]
162pub trait Instance: SealedInstance + RccPeripheral + 'static {}
163
164pin_trait!(SegComPin, Instance);
165
166foreach_peripheral!(
167 (lcd, $inst:ident) => {
168 impl crate::lcd::SealedInstance for peripherals::$inst {
169 fn regs() -> crate::pac::lcd::Lcd {
170 crate::pac::$inst
171 }
172 }
173
174 impl crate::lcd::Instance for peripherals::$inst {}
175 };
176);