stm32_rust_template/driver/gpio/
stm32f407.rs

1#[cfg(feature = "stm32f407")]
2extern crate alloc;
3
4use super::{Direction, EventTrigger, EventType, Gpio, OutputMode, Pin, PullResistor, Result};
5use crate::mcu::stm32f407::{self, gpio, rcc};
6use alloc::boxed::Box;
7use core::ops::FnMut;
8
9/// Configuration for a GPIO pin
10#[derive(Clone, Copy, Debug)]
11pub struct GpioConfig {
12    pub direction: Direction,
13    pub output_mode: OutputMode,
14    pub pull_resistor: PullResistor,
15    pub event_trigger: EventTrigger,
16}
17
18impl Default for GpioConfig {
19    fn default() -> Self {
20        Self {
21            direction: Direction::Input,
22            output_mode: OutputMode::PushPull,
23            pull_resistor: PullResistor::None,
24            event_trigger: EventTrigger::None,
25        }
26    }
27}
28
29/// A GPIO driver for STM32F407
30pub struct GpioDriver<'a> {
31    /// Callbacks for each pin (indexed by pin number)
32    callbacks: [Option<Box<dyn FnMut(Pin, EventType) + 'a>>; 16],
33    /// Configuration for each pin
34    configs: [GpioConfig; 16],
35}
36
37impl<'a> GpioDriver<'a> {
38    pub fn new() -> Self {
39        Self {
40            callbacks: [
41                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
42                None, None,
43            ],
44            configs: [GpioConfig::default(); 16],
45        }
46    }
47
48    /// Create a new GPIOA driver instance
49    pub fn new_gpioa() -> Self {
50        Self::new()
51    }
52
53    /// Create a new GPIOB driver instance
54    pub fn new_gpiob() -> Self {
55        Self::new()
56    }
57
58    /// Create a new GPIOC driver instance
59    pub fn new_gpioc() -> Self {
60        Self::new()
61    }
62
63    /// Create a new GPIOD driver instance
64    pub fn new_gpiod() -> Self {
65        Self::new()
66    }
67
68    /// Create a new GPIOE driver instance
69    pub fn new_gpioe() -> Self {
70        Self::new()
71    }
72
73    /// Get GPIO register block for a given port
74    fn get_gpio_regs(port: u8) -> *mut gpio::RegisterBlock {
75        match port {
76            0 => stm32f407::GPIOA_BASEADDR as *mut gpio::RegisterBlock, // GPIOA
77            1 => stm32f407::GPIOB_BASEADDR as *mut gpio::RegisterBlock, // GPIOB
78            2 => stm32f407::GPIOC_BASEADDR as *mut gpio::RegisterBlock, // GPIOC
79            3 => stm32f407::GPIOD_BASEADDR as *mut gpio::RegisterBlock, // GPIOD
80            4 => stm32f407::GPIOE_BASEADDR as *mut gpio::RegisterBlock, // GPIOE
81            _ => stm32f407::GPIOA_BASEADDR as *mut gpio::RegisterBlock, // Default to GPIOA
82        }
83    }
84
85    /// Get RCC register block
86    fn get_rcc_regs() -> *mut rcc::RegisterBlock {
87        stm32f407::RCC_BASEADDR as *mut rcc::RegisterBlock
88    }
89
90    /// Enable GPIO port clock
91    fn enable_gpio_clock(port: u8) {
92        let rcc = unsafe { &mut *Self::get_rcc_regs() };
93        let mask = match port {
94            0 => rcc::AHB1ENR_GPIOAEN_MASK, // GPIOA
95            1 => rcc::AHB1ENR_GPIOBEN_MASK, // GPIOB
96            2 => rcc::AHB1ENR_GPIOCEN_MASK, // GPIOC
97            3 => rcc::AHB1ENR_GPIODEN_MASK, // GPIOD
98            4 => rcc::AHB1ENR_GPIOEEN_MASK, // GPIOE
99            _ => rcc::AHB1ENR_GPIOAEN_MASK, // Default to GPIOA
100        };
101        unsafe {
102            rcc.ahb1enr |= mask;
103        }
104    }
105
106    /// Extract port and pin from Pin identifier
107    /// Pin format: (port << 4) | pin_number
108    /// where port: 0=GPIOA, 1=GPIOB, 2=GPIOC, 3=GPIOD, 4=GPIOE
109    /// and pin_number: 0-15
110    fn decode_pin(pin: Pin) -> (u8, u8) {
111        let port = ((pin >> 4) & 0xF) as u8;
112        let pin_num = (pin & 0xF) as u8;
113        (port, pin_num)
114    }
115
116    /// Encode port and pin into Pin identifier
117    fn encode_pin(port: u8, pin_num: u8) -> Pin {
118        ((port as u32) << 4) | (pin_num as u32)
119    }
120
121    /// Configure a GPIO pin
122    fn configure_pin(&mut self, pin: Pin, config: GpioConfig) -> Result<()> {
123        let (port, pin_num) = Self::decode_pin(pin);
124
125        if pin_num >= 16 {
126            return Err(-1); // Invalid pin number
127        }
128
129        // Enable GPIO port clock
130        Self::enable_gpio_clock(port);
131
132        let gpio_regs = unsafe { &mut *Self::get_gpio_regs(port) };
133
134        // Configure pin mode
135        let mode_val = match config.direction {
136            Direction::Input => gpio::MODER_INPUT,
137            Direction::Output => gpio::MODER_OUTPUT,
138        };
139        let shift = pin_num * 2;
140        let mask = 0x3 << shift;
141        unsafe {
142            gpio_regs.moder = (gpio_regs.moder & !mask) | (mode_val << shift);
143        }
144
145        // Configure output type (only relevant for output pins)
146        if config.direction == Direction::Output {
147            let otype_val = match config.output_mode {
148                OutputMode::PushPull => gpio::OTYPER_PUSHPULL,
149                OutputMode::OpenDrain => gpio::OTYPER_OPENDRAIN,
150            };
151            unsafe {
152                if otype_val == gpio::OTYPER_OPENDRAIN {
153                    gpio_regs.otyper |= 1 << pin_num;
154                } else {
155                    gpio_regs.otyper &= !(1 << pin_num);
156                }
157            }
158        }
159
160        // Configure pull-up/pull-down
161        let pupd_val = match config.pull_resistor {
162            PullResistor::None => gpio::PUPDR_FLOATING,
163            PullResistor::PullUp => gpio::PUPDR_PULLUP,
164            PullResistor::PullDown => gpio::PUPDR_PULLDOWN,
165        };
166        let shift = pin_num * 2;
167        let mask = 0x3 << shift;
168        unsafe {
169            gpio_regs.pupdr = (gpio_regs.pupdr & !mask) | (pupd_val << shift);
170        }
171
172        // Set default output speed to medium
173        let shift = pin_num * 2;
174        let mask = 0x3 << shift;
175        unsafe {
176            gpio_regs.ospeedr = (gpio_regs.ospeedr & !mask) | (gpio::OSPEEDR_MEDIUMSPEED << shift);
177        }
178
179        // Store configuration
180        self.configs[pin_num as usize] = config;
181
182        Ok(())
183    }
184}
185
186impl<'a> Gpio<'a> for GpioDriver<'a> {
187    fn setup(&mut self, pin: Pin, callback: impl FnMut(Pin, EventType) + 'a) -> Result<()> {
188        let (_, pin_num) = Self::decode_pin(pin);
189
190        if pin_num >= 16 {
191            return Err(-1); // Invalid pin number
192        }
193
194        // Store callback
195        self.callbacks[pin_num as usize] = Some(Box::new(callback));
196
197        // Configure pin with default settings (input)
198        let config = GpioConfig::default();
199        self.configure_pin(pin, config)?;
200
201        Ok(())
202    }
203
204    fn set_direction(&mut self, pin: Pin, direction: Direction) -> Result<()> {
205        let (_, pin_num) = Self::decode_pin(pin);
206
207        if pin_num >= 16 {
208            return Err(-1); // Invalid pin number
209        }
210
211        let mut config = self.configs[pin_num as usize];
212        config.direction = direction;
213        self.configure_pin(pin, config)
214    }
215
216    fn set_output_mode(&mut self, pin: Pin, mode: OutputMode) -> Result<()> {
217        let (_, pin_num) = Self::decode_pin(pin);
218
219        if pin_num >= 16 {
220            return Err(-1); // Invalid pin number
221        }
222
223        let mut config = self.configs[pin_num as usize];
224        config.output_mode = mode;
225        self.configure_pin(pin, config)
226    }
227
228    fn set_pull_resistor(&mut self, pin: Pin, resistor: PullResistor) -> Result<()> {
229        let (_, pin_num) = Self::decode_pin(pin);
230
231        if pin_num >= 16 {
232            return Err(-1); // Invalid pin number
233        }
234
235        let mut config = self.configs[pin_num as usize];
236        config.pull_resistor = resistor;
237        self.configure_pin(pin, config)
238    }
239
240    fn set_event_trigger(&mut self, pin: Pin, trigger: EventTrigger) -> Result<()> {
241        let (_, pin_num) = Self::decode_pin(pin);
242
243        if pin_num >= 16 {
244            return Err(-1); // Invalid pin number
245        }
246
247        let mut config = self.configs[pin_num as usize];
248        config.event_trigger = trigger;
249        self.configure_pin(pin, config)?;
250
251        // TODO: Configure EXTI for interrupt-based events
252        // For now, we'll just store the configuration
253
254        Ok(())
255    }
256
257    fn set_output(&mut self, pin: Pin, value: bool) {
258        let (port, pin_num) = Self::decode_pin(pin);
259
260        if pin_num >= 16 {
261            return; // Invalid pin number
262        }
263
264        let gpio_regs = unsafe { &mut *Self::get_gpio_regs(port) };
265
266        unsafe {
267            if value {
268                gpio_regs.bsrr = 1 << pin_num; // Set bit
269            } else {
270                gpio_regs.bsrr = 1 << (pin_num + 16); // Reset bit
271            }
272        }
273    }
274
275    fn get_input(&self, pin: Pin) -> bool {
276        let (port, pin_num) = Self::decode_pin(pin);
277
278        if pin_num >= 16 {
279            return false; // Invalid pin number
280        }
281
282        let gpio_regs = unsafe { &*Self::get_gpio_regs(port) };
283
284        unsafe { (gpio_regs.idr & (1 << pin_num)) != 0 }
285    }
286}
287
288// Helper functions for creating pin identifiers
289pub mod pins {
290    use super::Pin;
291
292    // GPIOA pins
293    pub const PA0: Pin = 0x00;
294    pub const PA1: Pin = 0x01;
295    pub const PA2: Pin = 0x02;
296    pub const PA3: Pin = 0x03;
297    pub const PA4: Pin = 0x04;
298    pub const PA5: Pin = 0x05;
299    pub const PA6: Pin = 0x06;
300    pub const PA7: Pin = 0x07;
301    pub const PA8: Pin = 0x08;
302    pub const PA9: Pin = 0x09;
303    pub const PA10: Pin = 0x0A;
304    pub const PA11: Pin = 0x0B;
305    pub const PA12: Pin = 0x0C;
306    pub const PA13: Pin = 0x0D;
307    pub const PA14: Pin = 0x0E;
308    pub const PA15: Pin = 0x0F;
309
310    // GPIOB pins
311    pub const PB0: Pin = 0x10;
312    pub const PB1: Pin = 0x11;
313    pub const PB2: Pin = 0x12;
314    pub const PB3: Pin = 0x13;
315    pub const PB4: Pin = 0x14;
316    pub const PB5: Pin = 0x15;
317    pub const PB6: Pin = 0x16;
318    pub const PB7: Pin = 0x17;
319    pub const PB8: Pin = 0x18;
320    pub const PB9: Pin = 0x19;
321    pub const PB10: Pin = 0x1A;
322    pub const PB11: Pin = 0x1B;
323    pub const PB12: Pin = 0x1C;
324    pub const PB13: Pin = 0x1D;
325    pub const PB14: Pin = 0x1E;
326    pub const PB15: Pin = 0x1F;
327
328    // GPIOC pins
329    pub const PC0: Pin = 0x20;
330    pub const PC1: Pin = 0x21;
331    pub const PC2: Pin = 0x22;
332    pub const PC3: Pin = 0x23;
333    pub const PC4: Pin = 0x24;
334    pub const PC5: Pin = 0x25;
335    pub const PC6: Pin = 0x26;
336    pub const PC7: Pin = 0x27;
337    pub const PC8: Pin = 0x28;
338    pub const PC9: Pin = 0x29;
339    pub const PC10: Pin = 0x2A;
340    pub const PC11: Pin = 0x2B;
341    pub const PC12: Pin = 0x2C;
342    pub const PC13: Pin = 0x2D;
343    pub const PC14: Pin = 0x2E;
344    pub const PC15: Pin = 0x2F;
345
346    // GPIOD pins
347    pub const PD0: Pin = 0x30;
348    pub const PD1: Pin = 0x31;
349    pub const PD2: Pin = 0x32;
350    pub const PD3: Pin = 0x33;
351    pub const PD4: Pin = 0x34;
352    pub const PD5: Pin = 0x35;
353    pub const PD6: Pin = 0x36;
354    pub const PD7: Pin = 0x37;
355    pub const PD8: Pin = 0x38;
356    pub const PD9: Pin = 0x39;
357    pub const PD10: Pin = 0x3A;
358    pub const PD11: Pin = 0x3B;
359    pub const PD12: Pin = 0x3C;
360    pub const PD13: Pin = 0x3D;
361    pub const PD14: Pin = 0x3E;
362    pub const PD15: Pin = 0x3F;
363
364    // GPIOE pins
365    pub const PE0: Pin = 0x40;
366    pub const PE1: Pin = 0x41;
367    pub const PE2: Pin = 0x42;
368    pub const PE3: Pin = 0x43;
369    pub const PE4: Pin = 0x44;
370    pub const PE5: Pin = 0x45;
371    pub const PE6: Pin = 0x46;
372    pub const PE7: Pin = 0x47;
373    pub const PE8: Pin = 0x48;
374    pub const PE9: Pin = 0x49;
375    pub const PE10: Pin = 0x4A;
376    pub const PE11: Pin = 0x4B;
377    pub const PE12: Pin = 0x4C;
378    pub const PE13: Pin = 0x4D;
379    pub const PE14: Pin = 0x4E;
380    pub const PE15: Pin = 0x4F;
381}