Skip to main content

rmk_q1_pro_iso/
main.rs

1#![no_main]
2#![no_std]
3#![deny(warnings)]
4#![warn(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)]
5#![feature(
6    const_trait_impl,
7    const_cmp,
8    const_option_ops,
9    const_index,
10    const_convert,
11    const_result_trait_fn,
12    optimize_attribute
13)]
14#![expect(
15    clippy::implicit_return,
16    clippy::blanket_clippy_restriction_lints,
17    clippy::separated_literal_suffix,
18    clippy::single_call_fn,
19    clippy::self_named_module_files,
20    clippy::future_not_send,
21    reason = "Implementation specific ignored lints"
22)]
23/// Backlight driver integration.
24mod backlight;
25/// Default keymap definitions.
26mod keymap;
27/// Matrix scanning components.
28mod matrix;
29/// Vial configuration constants.
30mod vial;
31
32use crate::{
33    backlight::{init::backlight_runner, lock_indicator::LedIndicatorProcessor},
34    matrix::{
35        layer_toggle::{LayerToggle, MatrixPos},
36        shiftreg_matrix::ShiftRegMatrixConfig,
37    },
38    vial::VIAL_SERIAL,
39};
40use embassy_executor::{Spawner, main};
41use embassy_stm32::{
42    Config,
43    bind_interrupts,
44    dma,
45    exti::{self, ExtiInput},
46    flash,
47    flash::Flash,
48    gpio::{Level, Output, Pull, Speed},
49    i2c,
50    init,
51    interrupt::typelevel,
52    peripherals::{self, USB},
53    rcc::{self},
54    time::Hertz,
55    usb::{self, Driver},
56};
57use embassy_time::Timer;
58use matrix::{hc595_cols::Hc595Cols, shiftreg_matrix::ShiftRegMatrix};
59use rmk::{
60    KeymapData,
61    config::{BehaviorConfig, DeviceConfig, PositionalConfig, RmkConfig, StorageConfig, VialConfig},
62    futures::future::join4,
63    initialize_keymap_and_storage,
64    input_device::{Runnable as _, rotary_encoder::RotaryEncoder},
65    keyboard::Keyboard,
66    run_all,
67    run_rmk,
68};
69use vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
70
71bind_interrupts!(struct Irqs {
72    DMA1_CHANNEL6 => dma::InterruptHandler<peripherals::DMA1_CH6>;
73    DMA1_CHANNEL7 => dma::InterruptHandler<peripherals::DMA1_CH7>;
74    EXTI0 => exti::InterruptHandler<typelevel::EXTI0>;
75    EXTI3 => exti::InterruptHandler<typelevel::EXTI3>;
76    EXTI4 => exti::InterruptHandler<typelevel::EXTI4>;
77    EXTI9_5 => exti::InterruptHandler<typelevel::EXTI9_5>;
78    EXTI15_10 => exti::InterruptHandler<typelevel::EXTI15_10>;
79    FLASH => flash::InterruptHandler;
80    I2C1_EV => i2c::EventInterruptHandler<peripherals::I2C1>;
81    I2C1_ER => i2c::ErrorInterruptHandler<peripherals::I2C1>;
82    USB => usb::InterruptHandler<USB>;
83});
84
85#[main]
86async fn main(spawner: Spawner) {
87    // Explicitly drop spawner.
88    let _: Spawner = spawner;
89    // RCC config
90    let mut config = Config::default();
91
92    config.rcc.hsi = true;
93    config.rcc.hsi48 = Some(rcc::Hsi48Config {
94        sync_from_usb: true, // needed if USB uses HSI48
95    });
96    config.rcc.pll = Some(rcc::Pll {
97        source: rcc::PllSource::Hsi,
98        prediv: rcc::PllPreDiv::Div1, // 16 MHz / 1 = 16
99        mul: rcc::PllMul::Mul10,      // VCO = 160 MHz
100        divp: None,
101        divq: None,                     // not used for USB
102        divr: Some(rcc::PllRDiv::Div2), // 160 / 2 = 80 MHz SYSCLK
103    });
104
105    config.rcc.sys = rcc::Sysclk::Pll1R;
106    config.rcc.ahb_pre = rcc::AHBPrescaler::Div1; // 80 MHz
107    config.rcc.apb1_pre = rcc::APBPrescaler::Div1; // 80 MHz
108    config.rcc.apb2_pre = rcc::APBPrescaler::Div1; // 80 MHz
109    config.rcc.mux.clk48sel = rcc::mux::Clk48sel::Hsi48;
110
111    // Initialize peripherals
112    let peripheral = init(config);
113
114    // Initialize LED backlight
115    let _led_driver_en = Output::new(peripheral.PC14, Level::High, Speed::Low);
116    Timer::after_millis(10).await;
117    let mut i2c_cfg_backlight = i2c::Config::default();
118    i2c_cfg_backlight.frequency = Hertz(400_000);
119    let i2c = i2c::I2c::new(
120        peripheral.I2C1,
121        peripheral.PB6,      // SCL
122        peripheral.PB7,      // SDA
123        peripheral.DMA1_CH6, // TX DMA
124        peripheral.DMA1_CH7, // RX DMA
125        Irqs,
126        i2c_cfg_backlight,
127    );
128
129    // Usb config
130    let driver = Driver::new(peripheral.USB, Irqs, peripheral.PA12, peripheral.PA11);
131
132    // Use internal flash to emulate eeprom
133    let flash = Flash::new(peripheral.FLASH, Irqs);
134
135    // Keyboard config
136    let rmk_config = RmkConfig {
137        vial_config: VialConfig::new(VIAL_KEYBOARD_ID, VIAL_KEYBOARD_DEF, &[(5, 0), (3, 1)]),
138        device_config: DeviceConfig {
139            manufacturer: "Keychron",
140            product_name: "Q1 Pro",
141            vid: 0x3434,
142            pid: 0x0611,
143            serial_number: VIAL_SERIAL,
144        },
145        ..Default::default()
146    };
147
148    // Shift register GPIO bit-bang pins
149    let data = Output::new(peripheral.PA7, Level::Low, Speed::VeryHigh); // SER
150    let clk = Output::new(peripheral.PA1, Level::Low, Speed::VeryHigh); // SRCLK
151    let lat = Output::new(peripheral.PB0, Level::Low, Speed::VeryHigh); // RCLK
152
153    // Pin config for cols from shift register
154    let cols = Hc595Cols::new(data, clk, lat, 1);
155
156    // 6 row inputs
157    let rows = [
158        ExtiInput::new(peripheral.PB5, peripheral.EXTI5, Pull::Up, Irqs),
159        ExtiInput::new(peripheral.PB4, peripheral.EXTI4, Pull::Up, Irqs),
160        ExtiInput::new(peripheral.PB3, peripheral.EXTI3, Pull::Up, Irqs),
161        ExtiInput::new(peripheral.PA15, peripheral.EXTI15, Pull::Up, Irqs),
162        ExtiInput::new(peripheral.PA14, peripheral.EXTI14, Pull::Up, Irqs),
163        ExtiInput::new(peripheral.PA13, peripheral.EXTI13, Pull::Up, Irqs),
164    ];
165
166    // Rotary encoder
167    let pin_a = ExtiInput::new(peripheral.PA10, peripheral.EXTI10, Pull::None, Irqs);
168    let pin_b = ExtiInput::new(peripheral.PA0, peripheral.EXTI0, Pull::None, Irqs);
169    let mut encoder = RotaryEncoder::with_resolution(pin_a, pin_b, 4, true, 0);
170
171    // Layer Toggle Switch
172    let layer_toggle_pin = ExtiInput::new(peripheral.PA8, peripheral.EXTI8, Pull::Up, Irqs);
173    let mut layer_toggle = LayerToggle::new_with_default_debounce(
174        layer_toggle_pin,
175        MatrixPos { row: 5, col: 7 }, // HIGH taps this
176        MatrixPos { row: 5, col: 8 }, // LOW taps this
177    );
178
179    // Initialize the storage and keymap
180    let mut keymap_data = KeymapData::new_with_encoder(keymap::get_default_keymap(), keymap::get_default_encoder_map());
181    let mut behavior_config = BehaviorConfig::default();
182    let storage_config = StorageConfig::default();
183    let key_config = PositionalConfig::default();
184    let (keymap, mut storage) =
185        initialize_keymap_and_storage(&mut keymap_data, flash, &storage_config, &mut behavior_config, &key_config)
186            .await;
187
188    // Initialize the matrix + keyboard
189    let mut matrix = ShiftRegMatrix::<6, 16>::new(rows, cols, ShiftRegMatrixConfig::default());
190    let mut keyboard = Keyboard::new(&keymap);
191    let mut led_indicator = LedIndicatorProcessor::new();
192
193    // Start
194    join4(
195        run_all!(matrix, encoder, layer_toggle, led_indicator),
196        keyboard.run(),
197        run_rmk(&keymap, driver, &mut storage, rmk_config),
198        backlight_runner(i2c, 0x77, 0x74),
199    )
200    .await;
201}