rmk_q6_he_ansi/matrix/hc164_cols.rs
1use core::hint::unlikely;
2use cortex_m::asm::delay;
3use embassy_stm32::gpio::Output;
4
5/// Column selector driven by an HC164 shift register.
6pub struct Hc164Cols<'peripherals> {
7 /// Clock input (`CP`) for shifting data into the register.
8 cp: Output<'peripherals>,
9 /// Serial data input (`DS`) for the shift register.
10 ds: Output<'peripherals>,
11 /// Master reset (`MR`) input for clearing the register.
12 mr: Output<'peripherals>,
13 /// CPU cycles between pin transitions.
14 shifter_delay_cycles: u32,
15}
16
17impl<'peripherals> Hc164Cols<'peripherals> {
18 /// Create a new column selector for the HC164.
19 pub const fn new(
20 ds: Output<'peripherals>,
21 cp: Output<'peripherals>,
22 mr: Output<'peripherals>,
23 shifter_delay_cycles: u32,
24 ) -> Self {
25 Self { cp, ds, mr, shifter_delay_cycles }
26 }
27
28 /// Pulse the clock pin for one shift step.
29 fn pulse_cp(&mut self) {
30 self.cp.set_high();
31 delay(self.shifter_delay_cycles);
32 self.cp.set_low();
33 delay(self.shifter_delay_cycles);
34 }
35
36 /// Select the given column.
37 ///
38 /// For column 0: clears the register via MR then clocks in a high bit,
39 /// placing the walking-one at position 0.
40 ///
41 /// For all other columns: clocks in a low bit, advancing the walking-one
42 /// to the next position. Must be called in strictly ascending order
43 /// starting from 0 each scan.
44 pub fn select(&mut self, col: usize) {
45 if unlikely(col == 0) {
46 // Clear all outputs by pulsing MR low.
47 self.mr.set_low();
48 delay(self.shifter_delay_cycles);
49 self.mr.set_high();
50 delay(self.shifter_delay_cycles);
51
52 // Clock in the walking-one at position 0.
53 self.ds.set_high();
54 delay(self.shifter_delay_cycles);
55 self.pulse_cp();
56 self.ds.set_low();
57 } else {
58 // Clock the walking-one to the next position.
59 self.pulse_cp();
60 }
61 }
62}