omnitiles/hw/
pins_v1.rs

1// SPDX-License-Identifier: MIT
2// © 2025–2026 Christopher Liu
3
4//! Pin definitions for STM32F777 MCU for OmniTiles PCB v1.
5
6use stm32f7xx_hal::{
7    gpio::{
8        gpioa, gpiob, gpioc, gpiod, gpioe, gpioh, Alternate, Analog, Floating, Input, Output,
9        PushPull,
10    },
11    pac,
12    prelude::*,
13};
14
15/// All board pins. Construct this once at startup using:
16///
17/// ```rust
18/// let pins = BoardPins::new(dp.GPIOA, dp.GPIOB, dp.GPIOD, dp.GPIOE);
19/// ```
20pub struct BoardPins {
21    pub leds: LedPins,
22    pub usart1: Usart1Pins,
23    pub spi4: Spi4Pins,
24    pub m1: Motor1Pins,
25    pub m2: Motor2Pins,
26    pub encoder: EncoderPins,
27    pub can1: Can1Pins,
28    pub can2: Can2Pins,
29}
30
31pub struct LedPins {
32    pub red: gpiod::PD8<Output<PushPull>>,
33    pub yellow: gpiod::PD9<Output<PushPull>>,
34    pub green: gpiod::PD10<Output<PushPull>>,
35}
36
37pub struct Usart1Pins {
38    pub tx: gpioa::PA9<Alternate<7>>,
39    pub rx: gpioa::PA10<Alternate<7>>,
40}
41
42/// SPI4 SCK/MISO/MOSI and CS
43pub struct Spi4Pins {
44    pub sck: gpioe::PE12<Alternate<5>>,
45    pub miso: gpioe::PE13<Alternate<5>>,
46    pub mosi: gpioe::PE14<Alternate<5>>,
47    pub cs1: gpioe::PE4<Output<PushPull>>,
48    pub cs2: gpioe::PE11<Output<PushPull>>,
49}
50
51/// TIM2/TIM3 Quadrature Encoder Inputs
52pub struct EncoderPins {
53    pub tim2_ch1: gpioa::PA0<Alternate<1>>,
54    pub tim2_ch2: gpioa::PA1<Alternate<1>>,
55
56    pub tim3_ch1: gpioa::PA6<Alternate<2>>,
57    pub tim3_ch2: gpioa::PA7<Alternate<2>>,
58}
59
60/// Motor 1 control pins
61pub struct Motor1Pins {
62    pub in1: gpioh::PH1<Output<PushPull>>,
63    pub in2: gpioc::PC0<Output<PushPull>>,
64    pub nsleep: gpioa::PA4<Output<PushPull>>,
65    pub disable: gpioa::PA3<Output<PushPull>>,
66    pub nfault: gpioa::PA2<Input<Floating>>,
67    pub iprop1: gpioc::PC4<Analog>, // ADC1_IN14
68    pub iprop2: gpioc::PC5<Analog>, // ADC1_IN15
69}
70
71/// Motor 2 control pins
72pub struct Motor2Pins {
73    pub in1: gpiod::PD3<Output<PushPull>>,
74    pub in2: gpiod::PD4<Output<PushPull>>,
75    pub nsleep: gpiod::PD2<Output<PushPull>>,
76    pub disable: gpiod::PD1<Output<PushPull>>,
77    pub nfault: gpiod::PD0<Input<Floating>>,
78    pub iprop1: gpioc::PC2<Analog>, // ADC1_IN12
79    pub iprop2: gpioc::PC3<Analog>, // ADC1_IN13
80}
81
82/// CAN1 bus pins
83pub struct Can1Pins {
84    pub tx: gpioa::PA12<Alternate<9>>,
85    pub rx: gpioa::PA11<Alternate<9>>,
86}
87
88/// CAN2 bus pins
89pub struct Can2Pins {
90    pub tx: gpiob::PB13<Alternate<9>>,
91    pub rx: gpiob::PB12<Alternate<9>>,
92}
93
94impl BoardPins {
95    /// Create all named pins from raw GPIO peripherals.
96    pub fn new(
97        gpioa: pac::GPIOA,
98        gpiob: pac::GPIOB,
99        gpioc: pac::GPIOC,
100        gpiod: pac::GPIOD,
101        gpioe: pac::GPIOE,
102        gpioh: pac::GPIOH,
103    ) -> Self {
104        let gpioa = gpioa.split();
105        let gpiob = gpiob.split();
106        let gpioc = gpioc.split();
107        let gpiod = gpiod.split();
108        let gpioe = gpioe.split();
109        let gpioh = gpioh.split();
110
111        Self {
112            leds: LedPins {
113                red: gpiod.pd8.into_push_pull_output(),
114                yellow: gpiod.pd9.into_push_pull_output(),
115                green: gpiod.pd10.into_push_pull_output(),
116            },
117
118            usart1: Usart1Pins {
119                tx: gpioa.pa9.into_alternate::<7>(),
120                rx: gpioa.pa10.into_alternate::<7>(),
121            },
122
123            spi4: Spi4Pins {
124                sck: gpioe.pe12.into_alternate::<5>(),
125                miso: gpioe.pe13.into_alternate::<5>(),
126                mosi: gpioe.pe14.into_alternate::<5>(),
127                cs1: gpioe.pe4.into_push_pull_output(),
128                cs2: gpioe.pe11.into_push_pull_output(),
129            },
130
131            encoder: EncoderPins {
132                tim2_ch1: gpioa.pa0.into_alternate::<1>(),
133                tim2_ch2: gpioa.pa1.into_alternate::<1>(),
134                tim3_ch1: gpioa.pa6.into_alternate::<2>(),
135                tim3_ch2: gpioa.pa7.into_alternate::<2>(),
136            },
137
138            m1: Motor1Pins {
139                in1: gpioh.ph1.into_push_pull_output(),
140                in2: gpioc.pc0.into_push_pull_output(),
141                nsleep: gpioa.pa4.into_push_pull_output(),
142                disable: gpioa.pa3.into_push_pull_output(),
143                nfault: gpioa.pa2.into_floating_input(),
144                iprop1: gpioc.pc4.into_analog(),
145                iprop2: gpioc.pc5.into_analog(),
146            },
147
148            m2: Motor2Pins {
149                in1: gpiod.pd3.into_push_pull_output(),
150                in2: gpiod.pd4.into_push_pull_output(),
151                nsleep: gpiod.pd2.into_push_pull_output(),
152                disable: gpiod.pd1.into_push_pull_output(),
153                nfault: gpiod.pd0.into_floating_input(),
154                iprop1: gpioc.pc2.into_analog(),
155                iprop2: gpioc.pc3.into_analog(),
156            },
157
158            can1: Can1Pins {
159                tx: gpioa.pa12.into_alternate::<9>(),
160                rx: gpioa.pa11.into_alternate::<9>().internal_pull_up(true),
161            },
162
163            can2: Can2Pins {
164                tx: gpiob.pb13.into_alternate::<9>(),
165                rx: gpiob.pb12.into_alternate::<9>().internal_pull_up(true),
166            },
167        }
168    }
169}