aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2024-06-15 11:46:22 +0200
committerDion Dokter <[email protected]>2024-06-15 11:46:22 +0200
commit10a1a19e9470b96664f94cb9fc3aa53ea51695a4 (patch)
tree146018820d3cbba54335b9a4cc63bf301efcccb8
parentf758c4b3910e8cb4d09c284db245e66de8cb5e5e (diff)
More debugging
-rw-r--r--embassy-stm32/src/lcd.rs120
-rw-r--r--examples/stm32u0/src/bin/lcd.rs2
2 files changed, 92 insertions, 30 deletions
diff --git a/embassy-stm32/src/lcd.rs b/embassy-stm32/src/lcd.rs
index 89fca416f..5c5f46861 100644
--- a/embassy-stm32/src/lcd.rs
+++ b/embassy-stm32/src/lcd.rs
@@ -5,10 +5,11 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
5 5
6use crate::gpio::{AFType, AnyPin, SealedPin}; 6use crate::gpio::{AFType, AnyPin, SealedPin};
7use crate::rcc::{self, RccPeripheral}; 7use crate::rcc::{self, RccPeripheral};
8use crate::time::Hertz;
8use crate::{peripherals, Peripheral}; 9use crate::{peripherals, Peripheral};
9 10
10#[non_exhaustive] 11#[non_exhaustive]
11#[derive(Debug, Default, Clone, Copy)] 12#[derive(Debug, Clone, Copy)]
12pub struct Config { 13pub struct Config {
13 pub use_voltage_output_buffer: bool, 14 pub use_voltage_output_buffer: bool,
14 pub use_segment_muxing: bool, 15 pub use_segment_muxing: bool,
@@ -16,6 +17,21 @@ pub struct Config {
16 pub duty: Duty, 17 pub duty: Duty,
17 pub voltage_source: VoltageSource, 18 pub voltage_source: VoltageSource,
18 pub high_drive: bool, 19 pub high_drive: bool,
20 pub target_fps: Hertz,
21}
22
23impl Default for Config {
24 fn default() -> Self {
25 Self {
26 use_voltage_output_buffer: Default::default(),
27 use_segment_muxing: Default::default(),
28 bias: Default::default(),
29 duty: Default::default(),
30 voltage_source: Default::default(),
31 high_drive: Default::default(),
32 target_fps: Hertz(30),
33 }
34 }
19} 35}
20 36
21#[repr(u8)] 37#[repr(u8)]
@@ -60,49 +76,91 @@ impl<'d, T: Instance> Lcd<'d, T> {
60 pub fn new<const N: usize>(_peri: impl Peripheral<P = T> + 'd, config: Config, pins: [LcdPin<'d, T>; N]) -> Self { 76 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>(); 77 rcc::enable_and_reset::<T>();
62 78
79 // Set the pins
63 for pin in pins { 80 for pin in pins {
64 pin.pin.set_as_af(pin.af_num, AFType::OutputPushPull); 81 pin.pin.set_as_af(pin.af_num, AFType::OutputPushPull);
82 pin.pin.set_speed(crate::gpio::Speed::VeryHigh);
65 } 83 }
66 84
67 T::regs().cr().write(|w| { 85 // Initialize the display ram to 0
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 { 86 for i in 0..8 {
85 T::regs().ram_com(i).low().write_value(0); 87 T::regs().ram_com(i).low().write_value(0);
86 T::regs().ram_com(i).high().write_value(0); 88 T::regs().ram_com(i).high().write_value(0);
87 } 89 }
88 T::regs().sr().write(|w| w.set_udr(true));
89 90
90 while !T::regs().sr().read().fcrsf() { } 91 // Calculate the clock dividers
92 let Some(lcd_clk) = (unsafe { rcc::get_freqs().rtc }) else {
93 panic!("The LCD driver needs the RTC/LCD clock to be running");
94 };
95 let duty_divider = match config.duty {
96 Duty::Static => 1,
97 Duty::Half => 2,
98 Duty::Third => 3,
99 Duty::Quarter => 4,
100 Duty::Eigth => 8,
101 };
102 let target_clock = config.target_fps.0 * duty_divider;
103 let target_division = lcd_clk.0 / target_clock;
104
105 let mut ps = 0;
106 let mut div = 0;
107 let mut best_fps_match = u32::MAX;
108
109 for trial_div in 0..0xF {
110 let trial_ps = (target_division / (trial_div + 16))
111 .next_power_of_two()
112 .trailing_zeros();
113 let fps = lcd_clk.0 / ((1 << trial_ps) * (trial_div + 16)) / duty_divider;
114
115 if fps < config.target_fps.0 {
116 continue;
117 }
118
119 if fps < best_fps_match {
120 ps = trial_ps;
121 div = trial_div;
122 best_fps_match = fps;
123 }
124 }
125
126 trace!("lcd_clk: {}, fps: {}, ps: {}, div: {}", lcd_clk, best_fps_match, ps, div);
91 127
128 if best_fps_match == u32::MAX || ps > 0xF {
129 panic!("Lcd clock error");
130 }
131
132 // Set the frame control
92 T::regs().fcr().modify(|w| { 133 T::regs().fcr().modify(|w| {
93 w.set_ps(2); 134 w.0 = 0x7C5C41;
94 w.set_div(4); 135 // w.set_ps(ps as u8);
136 // w.set_div(div as u8);
137 // w.set_cc(0);
138 // w.set_dead(0);
139 // w.set_pon(0);
140 // // w.set_hd(config.high_drive);
95 }); 141 });
96 while !T::regs().sr().read().fcrsf() { }
97 142
98 T::regs().fcr().modify(|w| { 143 // Wait for the frame control to synchronize
99 w.set_cc(7); 144 while !T::regs().sr().read().fcrsf() {}
145
146 // Set the control register values
147 T::regs().cr().modify(|w| {
148 w.0 = 0x4E;
149 // w.set_bufen(config.use_voltage_output_buffer);
150 // w.set_mux_seg(config.use_segment_muxing);
151 // w.set_bias(config.bias as u8);
152 // w.set_duty(config.duty as u8);
153 // w.set_vsel(matches!(config.voltage_source, VoltageSource::External));
100 }); 154 });
101 while !T::regs().sr().read().fcrsf() { }
102 155
156 // Enable the lcd
103 T::regs().cr().modify(|w| w.set_lcden(true)); 157 T::regs().cr().modify(|w| w.set_lcden(true));
104 158
105 while !T::regs().sr().read().rdy() { } 159 // Wait for the lcd to be enabled
160 while !T::regs().sr().read().ens() {}
161
162 // Wait for the stepup converter to be ready
163 while !T::regs().sr().read().rdy() {}
106 164
107 Self { _peri: PhantomData } 165 Self { _peri: PhantomData }
108 } 166 }
@@ -111,12 +169,16 @@ impl<'d, T: Instance> Lcd<'d, T> {
111 defmt::info!("{:06b}", T::regs().sr().read().0); 169 defmt::info!("{:06b}", T::regs().sr().read().0);
112 170
113 // Wait until the last update is done 171 // Wait until the last update is done
114 while T::regs().sr().read().udr() { } 172 while T::regs().sr().read().udr() {}
115 173
116 for i in 0..8 { 174 for i in 0..8 {
117 T::regs().ram_com(i).low().write_value(data[i * 2]); 175 T::regs().ram_com(i).low().write_value(data[i * 2]);
118 T::regs().ram_com(i).low().write_value(data[i * 2 + 1]); 176 T::regs().ram_com(i).low().write_value(data[i * 2 + 1]);
119 } 177 }
178
179 // Clear the update done flag
180 T::regs().sr().write(|w| w.set_udd(true));
181 // Set the update request flag
120 T::regs().sr().write(|w| w.set_udr(true)); 182 T::regs().sr().write(|w| w.set_udr(true));
121 } 183 }
122} 184}
diff --git a/examples/stm32u0/src/bin/lcd.rs b/examples/stm32u0/src/bin/lcd.rs
index 8612c3dfc..7a7c3a8a1 100644
--- a/examples/stm32u0/src/bin/lcd.rs
+++ b/examples/stm32u0/src/bin/lcd.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 divq: None, 22 divq: None,
23 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz 23 divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz
24 }); 24 });
25 config.rcc.ls = LsConfig::default(); 25 config.rcc.ls = LsConfig::default_lse();
26 } 26 }
27 27
28 let p = embassy_stm32::init(config); 28 let p = embassy_stm32::init(config);