rustuino/
time.rs

1//! This module contains everything that is related to timer based functions.
2//! 
3//! For information on whitch pins have PWM capabilities, check [`PWM_MAP`](crate::include::PWM_MAP)
4//! 
5//! # Examples
6//! 
7//! ```no_run
8//! #![no_std]
9//! #![no_main]
10//! 
11//! use rustuino::*;
12//! 
13//! #[entry]
14//! fn main() -> ! {
15//!   // Configure A8 for PWM use
16//!   let pwm_pin = pinmode_pwm(PA8).unwrap();
17//! 
18//!   loop {
19//!     for i in 0..256 {
20//!       pwm_write(&pwm_pin, i).unwrap();
21//!       delay(100);
22//!     }    
23//!   }
24//! }
25//! ```
26
27use crate::include::{GpioError, ProgError, PWM_MAP};
28use crate::gpio::{Pin, PWM};
29use stm32f4::stm32f446::{NVIC, Interrupt, interrupt};
30use cortex_m::interrupt::{Mutex, free};
31use core::cell::RefCell;
32use rtt_target::rprintln;
33
34static TIME_COUNTER: Mutex<RefCell<usize>> = Mutex::new(RefCell::new(0));
35
36
37// Public PWM Functions ===========================================================================
38#[doc(hidden)]
39pub fn setup_pwm(pin: (char, u8)) -> Result<(u8, u8, u8), ProgError>{
40  let peripheral_ptr;
41  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();}
42  let rcc = &peripheral_ptr.RCC;
43
44  let (timer, ccch, af) = match check_pwm(pin) {
45    Ok(target) => target,
46    Err(error) => return Err(error)
47  };
48
49  match timer {
50    1 => {
51      let tim1 = &peripheral_ptr.TIM1;
52      rcc.apb2enr.modify(|_, w| w.tim1en().enabled());
53      tim1.cr1.modify(|_, w| w.arpe().enabled());
54      tim1.psc.write(|w| w.psc().bits(1000));
55      tim1.arr.write(|w| w.arr().bits(255));
56      tim1.egr.write(|w| w.ug().set_bit());
57      match ccch {
58        1 => tim1.ccmr1_output().modify(|_, w| { w.oc1pe().enabled(); w.oc1m().pwm_mode1()}),
59        2 => tim1.ccmr1_output().modify(|_, w| { w.oc2pe().enabled(); w.oc2m().pwm_mode1()}),
60        3 => tim1.ccmr2_output().modify(|_, w| { w.oc3pe().enabled(); w.oc3m().pwm_mode1()}),
61        4 => tim1.ccmr2_output().modify(|_, w| { w.oc4pe().enabled(); w.oc4m().pwm_mode1()}),
62        _ => unreachable!()
63      };
64      tim1.ccer.modify(|r, w| unsafe {w.bits(r.bits() | (1 << (4 * (ccch - 1))))});
65      tim1.cr1.modify(|_, w| w.cen().enabled());
66    },
67    2 => {
68      let tim2 = &peripheral_ptr.TIM2;
69      rcc.apb2enr.modify(|_, w| w.tim1en().enabled());
70      tim2.cr1.modify(|_, w| w.arpe().enabled());
71      tim2.psc.write(|w| w.psc().bits(1000));
72      tim2.arr.write(|w| w.arr().bits(255));
73      tim2.egr.write(|w| w.ug().set_bit());
74      match ccch {
75        1 => tim2.ccmr1_output().modify(|_, w| { w.oc1pe().enabled(); w.oc1m().pwm_mode1()}),
76        2 => tim2.ccmr1_output().modify(|_, w| { w.oc2pe().enabled(); w.oc2m().pwm_mode1()}),
77        3 => tim2.ccmr2_output().modify(|_, w| { w.oc3pe().enabled(); w.oc3m().pwm_mode1()}),
78        4 => tim2.ccmr2_output().modify(|_, w| { w.oc4pe().enabled(); w.oc4m().pwm_mode1()}),
79        _ => unreachable!()
80      };
81      tim2.ccer.modify(|r, w| unsafe {w.bits(r.bits() | (1 << (4 * (ccch - 1))))});
82      tim2.cr1.modify(|_, w| w.cen().enabled());
83    },
84    3 => {
85      let tim3 = &peripheral_ptr.TIM3;
86      rcc.apb2enr.modify(|_, w| w.tim1en().enabled());
87      tim3.cr1.modify(|_, w| w.arpe().enabled());
88      tim3.psc.write(|w| w.psc().bits(1000));
89      tim3.arr.write(|w| w.arr().bits(255));
90      tim3.egr.write(|w| w.ug().set_bit());
91      match ccch {
92        1 => tim3.ccmr1_output().modify(|_, w| { w.oc1pe().enabled(); w.oc1m().pwm_mode1()}),
93        2 => tim3.ccmr1_output().modify(|_, w| { w.oc2pe().enabled(); w.oc2m().pwm_mode1()}),
94        3 => tim3.ccmr2_output().modify(|_, w| { w.oc3pe().enabled(); w.oc3m().pwm_mode1()}),
95        4 => tim3.ccmr2_output().modify(|_, w| { w.oc4pe().enabled(); w.oc4m().pwm_mode1()}),
96        _ => unreachable!()
97      };
98      tim3.ccer.modify(|r, w| unsafe {w.bits(r.bits() | (1 << (4 * (ccch - 1))))});
99      tim3.cr1.modify(|_, w| w.cen().enabled());
100    },
101    4 => {
102      let tim4 = &peripheral_ptr.TIM4;
103      rcc.apb2enr.modify(|_, w| w.tim1en().enabled());
104      tim4.cr1.modify(|_, w| w.arpe().enabled());
105      tim4.psc.write(|w| w.psc().bits(1000));
106      tim4.arr.write(|w| w.arr().bits(255));
107      tim4.egr.write(|w| w.ug().set_bit());
108      match ccch {
109        1 => tim4.ccmr1_output().modify(|_, w| { w.oc1pe().enabled(); w.oc1m().pwm_mode1()}),
110        2 => tim4.ccmr1_output().modify(|_, w| { w.oc2pe().enabled(); w.oc2m().pwm_mode1()}),
111        3 => tim4.ccmr2_output().modify(|_, w| { w.oc3pe().enabled(); w.oc3m().pwm_mode1()}),
112        4 => tim4.ccmr2_output().modify(|_, w| { w.oc4pe().enabled(); w.oc4m().pwm_mode1()}),
113        _ => unreachable!()
114      };
115      tim4.ccer.modify(|r, w| unsafe {w.bits(r.bits() | (1 << (4 * (ccch - 1))))});
116      tim4.cr1.modify(|_, w| w.cen().enabled());
117    },
118    _  => unreachable!()
119  };
120
121  return Ok((timer, ccch, af));
122}
123
124/// Sets the duty cycle of a PWM pin.
125/// 
126/// Takes pin identifier [A0, C5, etc.](crate::include::pins) and an 8bit value as arguments and sets the duty cycle
127/// of the pin.
128/// Panics if provided value is out of bounds (<0 or >255).
129/// 
130/// # Examples
131/// 
132/// ```no_run
133/// // Configure pin as an PWM output
134/// let pin = pinmode_pwm(PA8).unwrap();
135/// 
136/// // Set the duty cycle of the pin
137/// let mut value: u16 = pwm_write(&pin, 128).unwrap();
138/// ```
139pub fn pwm_write(pin: &Pin<PWM>, value: u8) -> Result<(), GpioError> {
140  let peripheral_ptr;
141  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();}
142
143  match pin.inner.timer {
144    1 => {
145      let tim1 = &peripheral_ptr.TIM1;
146      match pin.inner.ccch {
147        1 => tim1.ccr1.write(|w| w.ccr().bits(value.into())),
148        2 => tim1.ccr2.write(|w| w.ccr().bits(value.into())),
149        3 => tim1.ccr3.write(|w| w.ccr().bits(value.into())),
150        4 => tim1.ccr4.write(|w| w.ccr().bits(value.into())),
151        _ => unreachable!()
152      };
153    },
154    2 => {
155      let tim2 = &peripheral_ptr.TIM2;
156      match pin.inner.ccch {
157        1 => tim2.ccr1.write(|w| w.ccr().bits(value.into())),
158        2 => tim2.ccr2.write(|w| w.ccr().bits(value.into())),
159        3 => tim2.ccr3.write(|w| w.ccr().bits(value.into())),
160        4 => tim2.ccr4.write(|w| w.ccr().bits(value.into())),
161        _ => unreachable!()
162      };
163    },
164    3 => {
165      let tim3 = &peripheral_ptr.TIM3;
166      match pin.inner.ccch {
167        1 => tim3.ccr1.write(|w| w.ccr().bits(value.into())),
168        2 => tim3.ccr2.write(|w| w.ccr().bits(value.into())),
169        3 => tim3.ccr3.write(|w| w.ccr().bits(value.into())),
170        4 => tim3.ccr4.write(|w| w.ccr().bits(value.into())),
171        _ => unreachable!()
172      };
173    },
174    4 => {
175      let tim4 = &peripheral_ptr.TIM4;
176      match pin.inner.ccch {
177        1 => tim4.ccr1.write(|w| w.ccr().bits(value.into())),
178        2 => tim4.ccr2.write(|w| w.ccr().bits(value.into())),
179        3 => tim4.ccr3.write(|w| w.ccr().bits(value.into())),
180        4 => tim4.ccr4.write(|w| w.ccr().bits(value.into())),
181        _ => unreachable!()
182      };
183    },
184    _ => unreachable!()
185  };
186
187  return Ok(());
188}
189
190
191// Private PWM Functions ==========================================================================
192fn check_pwm(pin: (char, u8)) -> Result<(u8, u8, u8), ProgError> {
193  if !PWM_MAP.pins.contains(&pin) {return Err(ProgError::InvalidConfiguration);}
194  else {
195    let timer = PWM_MAP.timers[PWM_MAP.pins.iter().position(|&i| i == pin).unwrap()];
196    let ccch = PWM_MAP.ccchs[PWM_MAP.pins.iter().position(|&i| i == pin).unwrap()];
197    let af = match timer {
198      1 => 1,
199      2 => 1,
200      3 => 2,
201      4 => 2,
202      _  => unreachable!()
203    };
204
205    return Ok((timer, ccch, af));
206  }
207}
208
209
210// Public Time Functions ==========================================================================
211/// Lets the microcontroller wait for the specified time in milliseconds. In this time no other instructions
212/// other than interrupts can be run.
213///
214/// # Example
215///
216/// ```rust,no_run
217/// use rustuino::*;
218///
219/// let pin = PA0::output();
220///
221/// loop {
222///   pin.write(true);
223///   delay(1000);
224///   pin.write(false);
225///   delay(1000);
226/// }
227/// ```
228pub fn delay(ms: u16) {
229  let peripheral_ptr;
230  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();}
231  let rcc = &peripheral_ptr.RCC;
232  let tim6 = &peripheral_ptr.TIM6;
233
234  if rcc.apb1enr.read().tim6en().is_disabled() {
235    rcc.apb1enr.modify(|_, w| w.tim6en().enabled());
236    tim6.cr1.modify(|_, w| {
237      w.arpe().enabled();
238      w.opm().set_bit()
239    });
240
241    // 16MHz -> 1MHz : 1000 = 1kHz -> 1ms
242    tim6.psc.write(|w| w.psc().bits(16000));
243  }
244
245  tim6.arr.write(|w| w.arr().bits(ms));
246  tim6.egr.write(|w| w.ug().update());
247  tim6.cr1.modify(|_, w| w.cen().enabled());
248  while tim6.cr1.read().cen().bit_is_set() {}
249}
250
251/// Starts a timer that will continuously count the time in milliseconds.
252///
253/// This is used for non-blocking delays like [millis] and other time related applications.
254///
255/// # Example
256///
257/// ```rust,no_run
258/// use rustuino::*;
259///
260/// let mut counter: usize = 0;
261/// let delay: usize = 1000;
262/// start_time();
263///
264/// loop {
265///   if counter + delay >= millis() {
266///     // Do something
267///     counter = millis();
268///   }
269/// }
270/// ```
271pub fn start_time() {
272  let peripheral_ptr;
273  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();}
274  let rcc = &peripheral_ptr.RCC;
275  let tim7 = &peripheral_ptr.TIM7;
276
277  if rcc.apb1enr.read().tim7en().is_enabled() {
278    rprintln!("Millis Timer already configured! | start_time()");
279    return;
280  }
281
282  rcc.apb1enr.modify(|_, w| w.tim7en().enabled());
283  tim7.cr1.modify(|_, w| w.arpe().enabled());
284
285  tim7.dier.modify(|_, w| w.uie().enabled());
286  unsafe {NVIC::unmask(Interrupt::TIM7);}
287
288  // 16MHz -> 1MHz : 1000 = 1kHz -> 1ms
289  tim7.psc.write(|w| w.psc().bits(16));
290  tim7.arr.write(|w| w.arr().bits(1000));
291  tim7.egr.write(|w| w.ug().update());
292  tim7.cr1.modify(|_, w| w.cen().enabled());
293}
294
295/// Non-blocking delay function. Gives back the time in milliseconds since [start_time] was invoked.
296///
297/// # Example
298///
299/// ```rust,no_run
300/// use rustuino::*;
301///
302/// let mut counter: usize = 0;
303/// let delay: usize = 1000;
304/// start_time();
305///
306/// loop {
307///   if counter + delay >= millis() {
308///     // Do something
309///     counter = millis();
310///   }
311/// }
312/// ```
313pub fn millis() -> usize {
314  let peripheral_ptr;
315  unsafe {peripheral_ptr = stm32f4::stm32f446::Peripherals::steal();}
316  let tim7 = &peripheral_ptr.TIM6;
317
318  let buffer: usize;
319
320  tim7.cr1.modify(|_, w| w.cen().disabled());
321  buffer = free(|cs| *TIME_COUNTER.borrow(cs).borrow());
322  tim7.cr1.modify(|_, w| w.cen().enabled());
323
324  return buffer;
325}
326
327
328// Interrupts =====================================================================================
329#[allow(non_snake_case)]
330#[interrupt]
331fn TIM7() {
332  free(|cs| TIME_COUNTER.borrow(cs).replace_with(|&mut i| i + 1));
333}