rustuino/
gpio.rs

1//! This module contains everything that is related to the digital IO functionality.
2//! 
3//! # Examples
4//! 
5//! ```no_run
6//! #![no_std]
7//! #![no_main]
8//! 
9//! use rustuino::*;
10//! 
11//! #[entry]
12//! fn main() -> ! {
13//!   // Configure pins and get the pin-structs
14//!   let in_pin = pinmode_input(PA0).unwrap();
15//!   let out_pin = pinmode_output(PA1).unwrap();
16//!   let af_pin = pinmode_alternate_function(PA2, 7).unwrap();
17//!   let analog_pin = pinmode_analog(PA4).unwrap();
18//! 
19//!   loop {
20//!     // Read from the input pin
21//!     let value = digital_read(&in_pin);
22//!     
23//!     // Set the output pin
24//!     digital_write(&out_pin, true);
25//!   }
26//! }
27//! ```
28
29use crate::analog::enable_channel;
30use crate::time::setup_pwm;
31use crate::include::{ProgError, PIN_CONF};
32use rtt_target::rprintln;
33
34/// Represents a configured pin. Is returned from pinmode-functions.
35pub struct Pin<T> {
36  #[doc(hidden)]
37  pub block: char,
38  #[doc(hidden)]
39  pub number: u8,
40  #[doc(hidden)]
41  pub inner: T
42}
43
44#[doc(hidden)]
45pub struct Input;
46#[doc(hidden)]
47pub struct Output;
48#[doc(hidden)]
49pub struct AlternateFunction(u32);
50#[doc(hidden)]
51pub struct Analog {
52  #[doc(hidden)]
53  pub core: u8,
54  #[doc(hidden)]
55  pub channel: u8
56}
57#[doc(hidden)]
58pub struct PWM {
59  #[doc(hidden)]
60  pub timer: u8,
61  #[doc(hidden)]
62  pub ccch: u8
63}
64
65/// Represents the options to configure the GPIO speed of a pin.
66///
67/// Keep in mind, that the internal clock of the MC needs to be faster than the IO speed to be used fully.
68///
69/// | Speed  | Max. IO Frequency |
70/// | ------ | ----------------- |
71/// | Low    | 4MHz              |
72/// | Medium | 25MHz             |
73/// | Fast   | 50MHz             |
74/// | High   | 100MHz            |
75pub enum GpioSpeed {
76  Low, Medium, Fast, High
77}
78
79/// Represents the options for pullup-/pulldown-resistors.
80pub enum GpioBias {
81  None, Pullup, Pulldown
82}
83
84
85// Public Functions ===============================================================================
86/// Configures a pin to be a digital input.
87/// 
88/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
89/// for other functions.
90/// Panics if pin identifier is not a valid pin.
91pub fn pinmode_input(pin: (char, u8)) -> Result<Pin<Input>, ProgError> {
92  let peripheral_ptr;
93  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
94  let rcc = &peripheral_ptr.RCC;
95
96  if let Err(error) = check_pin(pin) {return Err(error);}
97
98  unsafe {
99    if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
100    else {
101      rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
102      return Err(ProgError::AlreadyConfigured);
103    }
104  }
105
106  match pin.0 {
107    'a' => {
108      let gpioa = &peripheral_ptr.GPIOA;
109      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
110      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
111    },
112    'b' => {
113      let gpiob = &peripheral_ptr.GPIOB;
114      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
115      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
116    },
117    'c' => {
118      let gpioc = &peripheral_ptr.GPIOC;
119      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
120      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
121    },
122    'd' => {
123      let gpiod = &peripheral_ptr.GPIOD;
124      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
125      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
126    },
127    'h' => {
128      let gpioh = &peripheral_ptr.GPIOH;
129      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
130      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
131    },
132    _   => unreachable!()
133  };
134
135  return Ok(Pin {
136    block: pin.0,
137    number: pin.1,
138    inner: Input
139  });
140}
141
142/// Configures a pin to be a digital input. Disregard if pin is already configured.
143/// 
144/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
145/// for other functions.
146/// Panics if pin identifier is not a valid pin.
147/// 
148/// # Safety
149/// 
150/// This function can be used to get more than one pin-structs of a configured pin. Keep in mind that the registers of
151/// the pin will still be configured. This can easily break other functions for the pin.
152pub unsafe fn pinmode_input_force(pin: (char, u8)) -> Result<Pin<Input>, ProgError> {
153  let peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();
154  let rcc = &peripheral_ptr.RCC;
155
156  if let Err(error) = check_pin(pin) {return Err(error);}
157
158  match pin.0 {
159    'a' => {
160      let gpioa = &peripheral_ptr.GPIOA;
161      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
162      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
163    },
164    'b' => {
165      let gpiob = &peripheral_ptr.GPIOB;
166      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
167      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
168    },
169    'c' => {
170      let gpioc = &peripheral_ptr.GPIOC;
171      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
172      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
173    },
174    'd' => {
175      let gpiod = &peripheral_ptr.GPIOD;
176      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
177      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
178    },
179    'h' => {
180      let gpioh = &peripheral_ptr.GPIOH;
181      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
182      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)))});
183    },
184    _   => unreachable!()
185  };
186
187  return Ok(Pin {
188    block: pin.0,
189    number: pin.1,
190    inner: Input
191  });
192}
193
194/// Configures a pin to be a digital output.
195/// 
196/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
197/// for other functions.
198/// Panics if pin identifier is not a valid pin.
199pub fn pinmode_output(pin: (char, u8)) -> Result<Pin<Output>, ProgError> {
200  let peripheral_ptr;
201  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
202  let rcc = &peripheral_ptr.RCC;
203
204  if let Err(error) = check_pin(pin) {return Err(error);}
205
206  unsafe {
207    if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
208    else {
209      rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
210      return Err(ProgError::AlreadyConfigured);
211    }
212  }
213
214  match pin.0 {
215    'a' => {
216      let gpioa = &peripheral_ptr.GPIOA;
217      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
218      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
219    },
220    'b' => {
221      let gpiob = &peripheral_ptr.GPIOB;
222      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
223      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
224    },
225    'c' => {
226      let gpioc = &peripheral_ptr.GPIOC;
227      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
228      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
229    },
230    'd' => {
231      let gpiod = &peripheral_ptr.GPIOD;
232      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
233      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
234    },
235    'h' => {
236      let gpioh = &peripheral_ptr.GPIOH;
237      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
238      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
239    },
240    _   => unreachable!()
241  };
242
243  return Ok(Pin {
244    block: pin.0,
245    number: pin.1,
246    inner: Output
247  });
248}
249
250/// Configures a pin to be a digital output. Disregard if pin is already configured.
251/// 
252/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
253/// for other functions.
254/// Panics if pin identifier is not a valid pin.
255/// 
256/// # Safety
257/// 
258/// This function can be used to get more than one pin-structs of a configured pin. Keep in mind that the registers of
259/// the pin will still be configured. This can easily break other functions for the pin.
260pub unsafe fn pinmode_output_force(pin: (char, u8)) -> Result<Pin<Output>, ProgError> {
261  let peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();
262  let rcc = &peripheral_ptr.RCC;
263
264  if let Err(error) = check_pin(pin) {return Err(error);}
265
266  match pin.0 {
267    'a' => {
268      let gpioa = &peripheral_ptr.GPIOA;
269      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
270      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
271    },
272    'b' => {
273      let gpiob = &peripheral_ptr.GPIOB;
274      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
275      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
276    },
277    'c' => {
278      let gpioc = &peripheral_ptr.GPIOC;
279      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
280      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
281    },
282    'd' => {
283      let gpiod = &peripheral_ptr.GPIOD;
284      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
285      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
286    },
287    'h' => {
288      let gpioh = &peripheral_ptr.GPIOH;
289      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
290      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (1 << (2 * pin.1)))});
291    },
292    _   => unreachable!()
293  };
294
295  return Ok(Pin {
296    block: pin.0,
297    number: pin.1,
298    inner: Output
299  });
300}
301
302/// Configures an alternate function for a pin.
303/// 
304/// Takes pin identifier [A0, C5, etc.](crate::include::pins) and a AF number as arguments and returns a [pin-struct](crate::gpio::Pin)
305/// for other functions.
306/// Panics if either pin identifier is not a valid pin or the AF value is not valid.
307pub fn pinmode_alternate_function(pin: (char, u8), af: u32) -> Result<Pin<AlternateFunction>, ProgError> {
308  let peripheral_ptr;
309  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
310  let rcc = &peripheral_ptr.RCC;
311
312  if let Err(error) = check_pin(pin) {return Err(error);}
313  if af > 15 {
314    rprintln!("Only alternate funtion values between 0 and 15 are valid! | pin_mode()");
315    return Err(ProgError::InvalidConfiguration);
316  }
317
318  unsafe {
319    if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
320    else {
321      rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
322      return Err(ProgError::AlreadyConfigured);
323    }
324  }
325
326  match pin.0 {
327    'a' => {
328      let gpioa = &peripheral_ptr.GPIOA;
329      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
330      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
331      if pin.1 > 7 {gpioa.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
332      else {gpioa.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
333    },
334    'b' => {
335      let gpiob = &peripheral_ptr.GPIOB;
336      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
337      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
338      if pin.1 > 7 {gpiob.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
339      else {gpiob.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
340    },
341    'c' => {
342      let gpioc = &peripheral_ptr.GPIOC;
343      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
344      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
345      if pin.1 > 7 {gpioc.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
346      else {gpioc.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
347    },
348    'd' => {
349      let gpiod = &peripheral_ptr.GPIOD;
350      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
351      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
352      if pin.1 > 7 {gpiod.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
353      else {gpiod.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
354    },
355    'h' => {
356      let gpioh = &peripheral_ptr.GPIOH;
357      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
358      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
359      if pin.1 > 7 {gpioh.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
360      else {gpioh.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
361    },
362    _   => unreachable!()
363  };
364
365  return Ok(Pin {
366    block: pin.0,
367    number: pin.1,
368    inner: AlternateFunction(af)
369  });
370}
371
372/// Configures an alternate function for a pin.
373/// 
374/// Takes pin identifier [A0, C5, etc.](crate::include::pins) and a AF number as arguments and returns a [pin-struct](crate::gpio::Pin)
375/// for other functions.
376/// Panics if either pin identifier is not a valid pin or the AF value is not valid.
377/// 
378/// # Safety
379/// 
380/// This function can be used to get more than one pin-structs of a configured pin. Keep in mind that the registers of
381/// the pin will still be configured. This can easily break other functions for the pin.
382pub unsafe fn pinmode_alternate_function_force(pin: (char, u8), af: u32) -> Result<Pin<AlternateFunction>, ProgError> {
383  let peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();
384  let rcc = &peripheral_ptr.RCC;
385
386  if let Err(error) = check_pin(pin) {return Err(error);}
387  if af > 15 {
388    rprintln!("Only alternate funtion values between 0 and 15 are valid! | pin_mode()");
389    return Err(ProgError::InvalidConfiguration);
390  }
391
392  match pin.0 {
393    'a' => {
394      let gpioa = &peripheral_ptr.GPIOA;
395      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
396      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
397      if pin.1 > 7 {gpioa.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
398      else {gpioa.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
399    },
400    'b' => {
401      let gpiob = &peripheral_ptr.GPIOB;
402      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
403      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
404      if pin.1 > 7 {gpiob.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
405      else {gpiob.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
406    },
407    'c' => {
408      let gpioc = &peripheral_ptr.GPIOC;
409      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
410      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
411      if pin.1 > 7 {gpioc.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
412      else {gpioc.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
413    },
414    'd' => {
415      let gpiod = &peripheral_ptr.GPIOD;
416      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
417      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
418      if pin.1 > 7 {gpiod.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
419      else {gpiod.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
420    },
421    'h' => {
422      let gpioh = &peripheral_ptr.GPIOH;
423      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
424      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
425      if pin.1 > 7 {gpioh.afrh.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * (pin.1 - 8))))});}
426      else {gpioh.afrl.modify(|r, w| unsafe {w.bits(r.bits() | (af << (4 * pin.1)))});}
427    },
428    _   => unreachable!()
429  };
430
431  return Ok(Pin {
432    block: pin.0,
433    number: pin.1,
434    inner: AlternateFunction(af)
435  });
436}
437
438/// Configures a pin to be an analog input.
439/// 
440/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
441/// for other functions.
442/// Panics if pin identifier is not a pin that can be used the the internal ADCs. To see witch pins are available for
443/// analog functionality see the docs of [ADC_MAP](crate::include::ADC_MAP).
444pub fn pinmode_analog(pin: (char, u8)) -> Result<Pin<Analog>, ProgError> {
445  let peripheral_ptr;
446  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
447  let rcc = &peripheral_ptr.RCC;
448
449  let channel_data: (u8, u8);
450
451  if let Err(error) = check_pin(pin) {return Err(error);}
452
453  unsafe {
454    if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
455    else {
456      rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
457      return Err(ProgError::AlreadyConfigured);
458    }
459  }
460
461  match pin.0 {
462    'a' => {
463      let gpioa = &peripheral_ptr.GPIOA;
464      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
465      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
466      channel_data = match enable_channel(pin) {
467        Ok(value) => value,
468        Err(error) => return Err(error)
469      };
470    },
471    'b' => {
472      let gpiob = &peripheral_ptr.GPIOB;
473      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
474      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
475      channel_data = match enable_channel(pin) {
476        Ok(value) => value,
477        Err(error) => return Err(error)
478      };
479    },
480    'c' => {
481      let gpioc = &peripheral_ptr.GPIOC;
482      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
483      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
484      channel_data = match enable_channel(pin) {
485        Ok(value) => value,
486        Err(error) => return Err(error)
487      };
488    },
489    'd' => {
490      let gpiod = &peripheral_ptr.GPIOD;
491      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
492      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
493      channel_data = match enable_channel(pin) {
494        Ok(value) => value,
495        Err(error) => return Err(error)
496      };
497    },
498    'h' => {
499      let gpioh = &peripheral_ptr.GPIOH;
500      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
501      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
502      channel_data = match enable_channel(pin) {
503        Ok(value) => value,
504        Err(error) => return Err(error)
505      };
506    },
507    _   => unreachable!()
508  };
509
510  return Ok(Pin {
511    block: pin.0,
512    number: pin.1,
513    inner: Analog {
514      core: channel_data.0,
515      channel: channel_data.1
516    }
517  });
518}
519
520/// Configures a pin to be an analog input.
521/// 
522/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
523/// for other functions.
524/// Panics if pin identifier is not a pin that can be used the the internal ADCs.  To see witch pins are available
525/// for analog functionality see the docs of [ADC_MAP](crate::include::ADC_MAP).
526/// 
527/// # Safety
528/// 
529/// This function can be used to get more than one pin-structs of a configured pin. Keep in mind that the registers of
530/// the pin will still be configured. This can easily break other functions for the pin.
531pub unsafe fn pinmode_analog_force(pin: (char, u8)) -> Result<Pin<Analog>, ProgError> {
532  let peripheral_ptr;
533  peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();
534  let rcc = &peripheral_ptr.RCC;
535
536  let channel_data: (u8, u8);
537
538  if let Err(error) = check_pin(pin) {return Err(error);}
539
540  match pin.0 {
541    'a' => {
542      let gpioa = &peripheral_ptr.GPIOA;
543      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
544      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
545      channel_data = match enable_channel(pin) {
546        Ok(value) => value,
547        Err(error) => return Err(error)
548      };
549    },
550    'b' => {
551      let gpiob = &peripheral_ptr.GPIOB;
552      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
553      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
554      channel_data = match enable_channel(pin) {
555        Ok(value) => value,
556        Err(error) => return Err(error)
557      };
558    },
559    'c' => {
560      let gpioc = &peripheral_ptr.GPIOC;
561      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
562      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
563      channel_data = match enable_channel(pin) {
564        Ok(value) => value,
565        Err(error) => return Err(error)
566      };
567    },
568    'd' => {
569      let gpiod = &peripheral_ptr.GPIOD;
570      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
571      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
572      channel_data = match enable_channel(pin) {
573        Ok(value) => value,
574        Err(error) => return Err(error)
575      };
576    },
577    'h' => {
578      let gpioh = &peripheral_ptr.GPIOH;
579      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
580      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (3 << (2 * pin.1)))});
581      channel_data = match enable_channel(pin) {
582        Ok(value) => value,
583        Err(error) => return Err(error)
584      };
585    },
586    _   => unreachable!()
587  };
588
589  return Ok(Pin {
590    block: pin.0,
591    number: pin.1,
592    inner: Analog {
593      core: channel_data.0,
594      channel: channel_data.1
595    }
596  });
597}
598
599/// Configures a pin to be a PWM output.
600/// 
601/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
602/// for other functions.
603/// Panics if pin identifier is not a pin that can be used as a PWM output with the internal timers. To see witch pins
604/// are available for PWM functionality see the docs of [PWM_MAP](crate::include::PWM_MAP).
605pub fn pinmode_pwm(pin: (char, u8)) -> Result<Pin<PWM>, ProgError> {
606  let peripheral_ptr;
607  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
608  let rcc = &peripheral_ptr.RCC;
609
610  if let Err(error) = check_pin(pin) {return Err(error);}
611
612  unsafe {
613    if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
614    else {
615      rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
616      return Err(ProgError::AlreadyConfigured);
617    }
618  }
619
620  let returns = match setup_pwm(pin) {
621    Ok(values) => values,
622    Err(error) => return Err(error)
623  };
624
625  match pin.0 {
626    'a' => {
627      let gpioa = &peripheral_ptr.GPIOA;
628      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
629      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
630      if pin.1 > 7 {gpioa.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
631      else {gpioa.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
632    },
633    'b' => {
634      let gpiob = &peripheral_ptr.GPIOB;
635      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
636      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
637      if pin.1 > 7 {gpiob.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
638      else {gpiob.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
639    },
640    'c' => {
641      let gpioc = &peripheral_ptr.GPIOC;
642      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
643      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
644      if pin.1 > 7 {gpioc.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
645      else {gpioc.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
646    },
647    'd' => {
648      let gpiod = &peripheral_ptr.GPIOD;
649      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
650      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
651      if pin.1 > 7 {gpiod.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
652      else {gpiod.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
653    },
654    'h' => {
655      let gpioh = &peripheral_ptr.GPIOH;
656      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
657      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
658      if pin.1 > 7 {gpioh.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
659      else {gpioh.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
660    },
661    _   => unreachable!()
662  };
663
664  return Ok(Pin {
665    block: pin.0,
666    number: pin.1,
667    inner: PWM {
668      timer: returns.0,
669      ccch: returns.1
670    }
671  });
672}
673
674/// Configures a pin to be a PWM output.
675/// 
676/// Takes pin identifier [A0, C5, etc.](crate::include::pins) as an argument and returns a [pin-struct](crate::gpio::Pin)
677/// for other functions.
678/// Panics if pin identifier is not a pin that can be used as a PWM output with the internal timers. To see witch pins
679/// are available for PWM functionality see the docs of [PWM_MAP](crate::include::PWM_MAP).
680/// 
681/// # Safety
682/// 
683/// This function can be used to get more than one pin-structs of a configured pin. Keep in mind that the registers of
684/// the pin will still be configured. This can easily break other functions for the pin.
685pub unsafe fn pinmode_pwm_force(pin: (char, u8)) -> Result<Pin<PWM>, ProgError> {
686  let peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();
687  let rcc = &peripheral_ptr.RCC;
688
689  if let Err(error) = check_pin(pin) {return Err(error);}
690
691  if !PIN_CONF.contains(&pin) {PIN_CONF.push(pin).unwrap();}
692  else {
693    rprintln!("P{}{} is already configured! | pin_mode()", pin.0.to_uppercase(), pin.1);
694    return Err(ProgError::AlreadyConfigured);
695  }
696
697  let returns = match setup_pwm(pin) {
698    Ok(values) => values,
699    Err(error) => return Err(error)
700  };
701
702  match pin.0 {
703    'a' => {
704      let gpioa = &peripheral_ptr.GPIOA;
705      rcc.ahb1enr.modify(|_, w| w.gpioaen().enabled());
706      gpioa.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
707      if pin.1 > 7 {gpioa.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
708      else {gpioa.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
709    },
710    'b' => {
711      let gpiob = &peripheral_ptr.GPIOB;
712      rcc.ahb1enr.modify(|_, w| w.gpioben().enabled());
713      gpiob.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
714      if pin.1 > 7 {gpiob.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
715      else {gpiob.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
716    },
717    'c' => {
718      let gpioc = &peripheral_ptr.GPIOC;
719      rcc.ahb1enr.modify(|_, w| w.gpiocen().enabled());
720      gpioc.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
721      if pin.1 > 7 {gpioc.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
722      else {gpioc.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
723    },
724    'd' => {
725      let gpiod = &peripheral_ptr.GPIOD;
726      rcc.ahb1enr.modify(|_, w| w.gpioden().enabled());
727      gpiod.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
728      if pin.1 > 7 {gpiod.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
729      else {gpiod.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
730    },
731    'h' => {
732      let gpioh = &peripheral_ptr.GPIOH;
733      rcc.ahb1enr.modify(|_, w| w.gpiohen().enabled());
734      gpioh.moder.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * pin.1)) | (2 << (2 * pin.1)))});
735      if pin.1 > 7 {gpioh.afrh.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * (pin.1 - 8))))});}
736      else {gpioh.afrl.modify(|r, w| unsafe {w.bits(r.bits() | ((returns.2 as u32) << (4 * pin.1)))});}
737    },
738    _   => unreachable!()
739  };
740
741  return Ok(Pin {
742    block: pin.0,
743    number: pin.1,
744    inner: PWM {
745      timer: returns.0,
746      ccch: returns.1
747    }
748  });
749}
750
751/// Sets the state of an output pin.
752/// 
753/// Takes [pin-struct](crate::gpio::Pin) of an output pin and a boolean value as arguments and sets the pin to that value.
754pub fn digital_write(pin: &Pin<Output>, value: bool) {
755  let peripheral_ptr;
756  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
757
758  match pin.block {
759    'a' => {
760      let gpioa = &peripheral_ptr.GPIOA;
761      if value {gpioa.bsrr.write(|w| unsafe {w.bits(1 << pin.number)});}
762      else {gpioa.bsrr.write(|w| unsafe {w.bits(1 << (pin.number + 16))});}
763    },
764    'b' => {
765      let gpiob = &peripheral_ptr.GPIOB;
766      if value {gpiob.bsrr.write(|w| unsafe {w.bits(1 << pin.number)});}
767      else {gpiob.bsrr.write(|w| unsafe {w.bits(1 << (pin.number + 16))});}
768    },
769    'c' => {
770      let gpioc = &peripheral_ptr.GPIOC;
771      if value {gpioc.bsrr.write(|w| unsafe {w.bits(1 << pin.number)});}
772      else {gpioc.bsrr.write(|w| unsafe {w.bits(1 << (pin.number + 16))});}
773    },
774    'd' => {
775      let gpiod = &peripheral_ptr.GPIOD;
776      if value {gpiod.bsrr.write(|w| unsafe {w.bits(1 << pin.number)});}
777      else {gpiod.bsrr.write(|w| unsafe {w.bits(1 << (pin.number + 16))});}
778    },
779    'h' => {
780      let gpioh = &peripheral_ptr.GPIOH;
781      if value {gpioh.bsrr.write(|w| unsafe {w.bits(1 << pin.number)});}
782      else {gpioh.bsrr.write(|w| unsafe {w.bits(1 << (pin.number + 16))});}
783    },
784    _   => unreachable!()
785  };
786}
787
788/// Reads the state of an input pin.
789/// 
790/// Takes [pin-struct](crate::gpio::Pin) of an output pin as an argument and returns the boolean value of that pin.
791pub fn digital_read(pin: &Pin<Input>) -> bool {
792  let peripheral_ptr;
793  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
794
795  let bits = match pin.block {
796    'a' => {
797      let gpioa = &peripheral_ptr.GPIOA;
798      gpioa.idr.read().bits()
799    },
800    'b' => {
801      let gpiob = &peripheral_ptr.GPIOB;
802      gpiob.idr.read().bits()
803    },
804    'c' => {
805      let gpioc = &peripheral_ptr.GPIOC;
806      gpioc.idr.read().bits()
807    },
808    'd' => {
809      let gpiod = &peripheral_ptr.GPIOD;
810      gpiod.idr.read().bits()
811    },
812    'h' => {
813      let gpioh = &peripheral_ptr.GPIOH;
814      gpioh.idr.read().bits()
815    },
816    _   => unreachable!()
817  };
818
819  return bits & (1 << pin.number) == (1 << pin.number);
820}
821
822/// Reads the set state of an output pin.
823/// 
824/// Takes [pin-struct](crate::gpio::Pin) of an output pin as an argument and returns the set state of that pin.
825pub fn digital_state(pin: &Pin<Output>) -> bool {
826  let peripheral_ptr;
827  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
828
829  let bits = match pin.block {
830    'a' => {
831      let gpioa = &peripheral_ptr.GPIOA;
832      gpioa.odr.read().bits()
833    },
834    'b' => {
835      let gpiob = &peripheral_ptr.GPIOB;
836      gpiob.odr.read().bits()
837    },
838    'c' => {
839      let gpioc = &peripheral_ptr.GPIOC;
840      gpioc.odr.read().bits()
841    },
842    'd' => {
843      let gpiod = &peripheral_ptr.GPIOD;
844      gpiod.odr.read().bits()
845    },
846    'h' => {
847      let gpioh = &peripheral_ptr.GPIOH;
848      gpioh.odr.read().bits()
849    },
850    _   => unreachable!()
851  };
852
853  return bits & (1 << pin.number) == (1 << pin.number);
854}
855
856/// Sets if the pin has a pullup-, pulldown- or no bias-resistor connected internally.
857/// 
858/// Takes [pin-struct](crate::gpio::Pin) of a pin and the [config](crate::gpio::GpioBias) as arguments and sets the
859/// bias of that pin.
860pub fn set_bias<T>(pin: &Pin<T>, bias: GpioBias) {
861  let peripheral_ptr;
862  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
863
864  let num = pin.number;
865
866  match pin.block {
867    'a' => {
868      let gpioa = &peripheral_ptr.GPIOA;
869      match bias {
870        GpioBias::None => gpioa.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
871        GpioBias::Pullup => gpioa.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
872        GpioBias::Pulldown => gpioa.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))})
873      };
874    },
875    'b' => {
876      let gpiob = &peripheral_ptr.GPIOB;
877      match bias {
878        GpioBias::None => gpiob.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
879        GpioBias::Pullup => gpiob.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
880        GpioBias::Pulldown => gpiob.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))})
881      };
882    },
883    'c' => {
884      let gpioc = &peripheral_ptr.GPIOC;
885      match bias {
886        GpioBias::None => gpioc.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
887        GpioBias::Pullup => gpioc.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
888        GpioBias::Pulldown => gpioc.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))})
889      };
890    },
891    'd' => {
892      let gpiod = &peripheral_ptr.GPIOD;
893      match bias {
894        GpioBias::None => gpiod.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
895        GpioBias::Pullup => gpiod.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
896        GpioBias::Pulldown => gpiod.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))})
897      };
898    },
899    'h' => {
900      let gpioh = &peripheral_ptr.GPIOH;
901      match bias {
902        GpioBias::None => gpioh.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
903        GpioBias::Pullup => gpioh.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
904        GpioBias::Pulldown => gpioh.pupdr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))})
905      };
906    },
907    _   => unreachable!()
908  };
909}
910
911/// Sets the driving speed of the pin.
912/// 
913/// Takes [pin-struct](crate::gpio::Pin) of a pin and the [speed](crate::gpio::GpioSpeed) as arguments and sets the
914/// speed of that pin.
915/// See the documentation of [GpioSpeed](crate::gpio::GpioSpeed) for frequency ratings.
916pub fn set_speed<T>(pin: &Pin<T>, speed: GpioSpeed) {
917  let peripheral_ptr;
918  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
919
920  let num = pin.number;
921
922  match pin.block {
923    'a' => {
924      let gpioa = &peripheral_ptr.GPIOA;
925      match speed {
926        GpioSpeed::Low => gpioa.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
927        GpioSpeed::Medium => gpioa.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
928        GpioSpeed::Fast => gpioa.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))}),
929        GpioSpeed::High => gpioa.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() | (3 << (2 * num)))})
930      };
931    },
932    'b' => {
933      let gpiob = &peripheral_ptr.GPIOB;
934      match speed {
935        GpioSpeed::Low => gpiob.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
936        GpioSpeed::Medium => gpiob.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
937        GpioSpeed::Fast => gpiob.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))}),
938        GpioSpeed::High => gpiob.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() | (3 << (2 * num)))})
939      };
940    },
941    'c' => {
942      let gpioc = &peripheral_ptr.GPIOC;
943      match speed {
944        GpioSpeed::Low => gpioc.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
945        GpioSpeed::Medium => gpioc.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
946        GpioSpeed::Fast => gpioc.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))}),
947        GpioSpeed::High => gpioc.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() | (3 << (2 * num)))})
948      };
949    },
950    'd' => {
951      let gpiod = &peripheral_ptr.GPIOD;
952      match speed {
953        GpioSpeed::Low => gpiod.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
954        GpioSpeed::Medium => gpiod.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
955        GpioSpeed::Fast => gpiod.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))}),
956        GpioSpeed::High => gpiod.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() | (3 << (2 * num)))})
957      };
958    },
959    'h' => {
960      let gpioh = &peripheral_ptr.GPIOH;
961      match speed {
962        GpioSpeed::Low => gpioh.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)))}),
963        GpioSpeed::Medium => gpioh.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (1 << (2 * num)))}),
964        GpioSpeed::Fast => gpioh.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() & !(3 << (2 * num)) | (2 << (2 * num)))}),
965        GpioSpeed::High => gpioh.ospeedr.modify(|r, w| unsafe {w.bits(r.bits() | (3 << (2 * num)))})
966      };
967    },
968    _   => unreachable!()
969  };
970}
971
972/// Sets if the pin is driven in push-pull- or open-drain-configuration.
973/// 
974/// Takes [pin-struct](crate::gpio::Pin) of a pin and a boolean value as arguments and sets the drive-mode of that pin.
975/// If the value is false the config is push-pull, if the value is true the config is open-drain.
976pub fn open_drain<T>(pin: &Pin<T>, op: bool) {
977  let peripheral_ptr;
978  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();} 
979
980  match pin.block {
981    'a' => {
982      let gpioa = &peripheral_ptr.GPIOA;
983      if op {gpioa.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (1 << pin.number))});}
984      else {gpioa.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (0 << pin.number))});}
985    },
986    'b' => {
987      let gpiob = &peripheral_ptr.GPIOB;
988      if op {gpiob.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (1 << pin.number))});}
989      else {gpiob.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (0 << pin.number))});}
990    },
991    'c' => {
992      let gpioc = &peripheral_ptr.GPIOC;
993      if op {gpioc.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (1 << pin.number))});}
994      else {gpioc.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (0 << pin.number))});}
995    },
996    'd' => {
997      let gpiod = &peripheral_ptr.GPIOD;
998      if op {gpiod.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (1 << pin.number))});}
999      else {gpiod.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (0 << pin.number))});}
1000    },
1001    'h' => {
1002      let gpioh = &peripheral_ptr.GPIOH;
1003      if op {gpioh.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (1 << pin.number))});}
1004      else {gpioh.otyper.modify(|r, w| unsafe {w.bits(r.bits() | (0 << pin.number))});}
1005    },
1006    _   => unreachable!()
1007  };
1008}
1009
1010
1011// Private Functions ==============================================================================
1012fn check_pin(pin: (char, u8)) -> Result<(), ProgError> {
1013  if pin.1 > 15 || pin.0 == 'd' && pin.1 != 2 || pin.0 == 'h' && pin.1 != 0 && pin.1 != 1 {
1014    rprintln!("P{}{} is not an available GPIO Pin!", pin.0.to_uppercase(), pin.1);
1015    return Err(ProgError::InvalidConfiguration);
1016  }
1017  else {return Ok(());}
1018}
1019
1020impl<T> Drop for Pin<T> {
1021  fn drop(&mut self) {
1022    unsafe {PIN_CONF.swap_remove(PIN_CONF.iter().position(|&i| i == (self.block, self.number)).unwrap());}
1023  }
1024}