omnitiles/hw/
pins.rs

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