avr_hal_generic/
simple_pwm.rs
1use core::marker::PhantomData;
4use embedded_hal::pwm;
5use embedded_hal::pwm::{ErrorKind, ErrorType, SetDutyCycle};
6
7use crate::port::mode;
8use crate::port::Pin;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
27pub enum Prescaler {
28 Direct,
30 Prescale8,
32 Prescale64,
34 Prescale256,
36 Prescale1024,
38}
39
40pub trait PwmPinOps<TC> {
42 type Duty;
43
44 fn enable(&mut self);
45 fn disable(&mut self);
46 fn get_duty(&self) -> Self::Duty;
47 fn get_max_duty(&self) -> Self::Duty;
48
49 fn set_duty(&mut self, value: u8);
50}
51
52pub trait IntoPwmPin<TC, PIN> {
53 fn into_pwm(self, timer: &TC) -> Pin<mode::PwmOutput<TC>, PIN>;
54}
55
56impl<TC, PIN: PwmPinOps<TC>> IntoPwmPin<TC, PIN> for Pin<mode::Output, PIN> {
57 fn into_pwm(self, _timer: &TC) -> Pin<mode::PwmOutput<TC>, PIN> {
58 Pin {
59 pin: self.pin,
60 _mode: PhantomData,
61 }
62 }
63}
64
65impl<TC, PIN: PwmPinOps<TC>> Pin<mode::PwmOutput<TC>, PIN> {
66 pub fn enable(&mut self) {
67 self.pin.enable();
68 }
69
70 pub fn disable(&mut self) {
71 self.pin.disable();
72 }
73
74 pub fn get_duty(&self) -> <PIN as PwmPinOps<TC>>::Duty {
75 self.pin.get_duty()
76 }
77
78 pub fn get_max_duty(&self) -> <PIN as PwmPinOps<TC>>::Duty {
79 self.pin.get_max_duty()
80 }
81
82 pub fn set_duty(&mut self, duty: u8) {
83 self.pin.set_duty(duty);
84 }
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
88pub enum PwmError {
89 DutyCycleTooLarge,
92}
93
94impl pwm::Error for PwmError {
95 fn kind(&self) -> ErrorKind {
96 ErrorKind::Other
97 }
98}
99
100impl<TC, PIN: PwmPinOps<TC>> ErrorType for Pin<mode::PwmOutput<TC>, PIN> {
101 type Error = PwmError;
102}
103
104impl<TC, PIN: PwmPinOps<TC, Duty = u8>> SetDutyCycle for Pin<mode::PwmOutput<TC>, PIN> {
105 fn max_duty_cycle(&self) -> u16 {
106 self.get_max_duty() as u16
107 }
108
109 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
110 if duty > u8::MAX as u16 {
111 return Err(PwmError::DutyCycleTooLarge);
112 }
113 self.set_duty(duty as u8);
114 Ok(())
115 }
116}
117
118#[macro_export]
119macro_rules! impl_simple_pwm {
120 (
121 $(#[$timer_pwm_attr:meta])*
122 pub struct $TimerPwm:ident {
123 timer: $TIMER:ty,
124 init: |$init_timer:ident, $prescaler:ident| $init_block:block,
125 pins: {$(
126 $PXi:ident: {
127 ocr: $ocr:ident,
128 $into_pwm:ident: |$pin_timer:ident| if enable
129 $pin_enable_block:block else $pin_disable_block:block,
130 },
131 )+},
132 }
133 ) => {
134 $(#[$timer_pwm_attr])*
135 pub struct $TimerPwm {
136 timer: $TIMER,
137 }
138
139 impl $TimerPwm {
140 pub fn new(timer: $TIMER, prescaler: $crate::simple_pwm::Prescaler) -> $TimerPwm {
141 let mut t = $TimerPwm { timer };
142
143 {
144 let $init_timer = &mut t.timer;
145 let $prescaler = prescaler;
146 $init_block
147 }
148
149 t
150 }
151 }
152
153 $(
154 impl avr_hal_generic::simple_pwm::PwmPinOps<$TimerPwm> for $PXi {
155 type Duty = u8;
156
157 fn enable(&mut self) {
158 $crate::avr_device::interrupt::free(|_| {
162 let $pin_timer = unsafe { &*<$TIMER>::ptr() };
163 $pin_enable_block
164 });
165 }
166
167 fn disable(&mut self) {
168 $crate::avr_device::interrupt::free(|_| {
172 let $pin_timer = unsafe { &*<$TIMER>::ptr() };
173 $pin_disable_block
174 });
175 }
176
177 fn get_duty(&self) -> Self::Duty {
178 unsafe { (&*<$TIMER>::ptr()) }.$ocr.read().bits() as Self::Duty
179 }
180
181 fn get_max_duty(&self) -> Self::Duty {
182 u8::MAX
183 }
184
185 fn set_duty(&mut self, duty: Self::Duty) {
186 unsafe { (&*<$TIMER>::ptr()).$ocr.write(|w| w.bits(duty.into())); };
189 }
190 }
191 )+
192 }
193}