Skip to main content

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}