Skip to content

Commit f0380a4

Browse files
dalpilRahix
authored andcommitted
Reimplements simple PWM for some atmega MCUs
1 parent 46fbe4f commit f0380a4

File tree

7 files changed

+665
-17
lines changed

7 files changed

+665
-17
lines changed

arduino-hal/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ pub use delay::{delay_ms, delay_us, Delay};
112112

113113
#[cfg(feature = "board-selected")]
114114
pub mod port;
115+
116+
#[cfg(feature = "board-selected")]
117+
pub mod simple_pwm;
118+
115119
#[doc(no_inline)]
116120
#[cfg(feature = "board-selected")]
117121
pub use port::Pins;

arduino-hal/src/simple_pwm.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//! Simple PWM output for supported Pins.
2+
//!
3+
//! This module implements simple (FastPWM) PWM output for supported Pins.
4+
//!
5+
//! Check the documentation for each of the TimerXPwm-structs for usage
6+
//! examples.
7+
8+
pub use avr_hal_generic::simple_pwm::IntoPwmPin;
9+
pub use avr_hal_generic::simple_pwm::Prescaler;
10+
pub use atmega_hal::simple_pwm::*;

avr-hal-generic/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub mod usart;
2222
pub mod i2c;
2323
pub mod spi;
2424
pub mod adc;
25-
pub mod pwm;
25+
pub mod simple_pwm;
2626
pub mod wdt;
2727

2828
/// Prelude containing all HAL traits

avr-hal-generic/src/port.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ pub mod mode {
2424
impl Io for OpenDrain {}
2525
impl crate::Sealed for OpenDrain {}
2626

27+
pub struct PwmOutput<TC> {
28+
pub(crate) _timer: PhantomData<TC>
29+
}
30+
impl<TC> super::PinMode for PwmOutput<TC> {}
31+
impl<TC> crate::Sealed for PwmOutput<TC> {}
32+
2733
pub trait InputMode: crate::Sealed {}
2834

2935
/// Pin is configured as digital input (floating or pulled-up).

avr-hal-generic/src/pwm.rs renamed to avr-hal-generic/src/simple_pwm.rs

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
//! PWM Implementation
22
3+
use core::marker::PhantomData;
4+
5+
use crate::port::Pin;
6+
use crate::port::mode;
7+
38
/// Clock prescaler for PWM
49
///
510
/// The prescaler dictates the PWM frequency, together with the IO clock. The formula is as
@@ -31,15 +36,61 @@ pub enum Prescaler {
3136
}
3237

3338
/// Implement traits and types for PWM timers
39+
pub trait PwmPinOps<TC> {
40+
type Duty;
41+
42+
fn enable(&mut self);
43+
fn disable(&mut self);
44+
fn get_duty(&self) -> Self::Duty;
45+
fn get_max_duty(&self) -> Self::Duty;
46+
47+
fn set_duty(&mut self, value: u8);
48+
}
49+
50+
pub trait IntoPwmPin<TC, PIN> {
51+
fn into_pwm(self, timer: &TC) -> Pin<mode::PwmOutput<TC>, PIN>;
52+
}
53+
54+
impl<TC, PIN: PwmPinOps<TC>> IntoPwmPin<TC, PIN> for Pin<mode::Output, PIN> {
55+
fn into_pwm(self, _timer: &TC) -> Pin<mode::PwmOutput<TC>, PIN> {
56+
Pin {
57+
pin: self.pin,
58+
_mode: PhantomData
59+
}
60+
}
61+
}
62+
63+
impl<TC, PIN: PwmPinOps<TC>> Pin<mode::PwmOutput<TC>, PIN> {
64+
pub fn enable(&mut self) {
65+
self.pin.enable();
66+
}
67+
68+
pub fn disable(&mut self) {
69+
self.pin.disable();
70+
}
71+
72+
pub fn get_duty(&self) -> <PIN as PwmPinOps<TC>>::Duty {
73+
self.pin.get_duty()
74+
}
75+
76+
pub fn get_max_duty(&self) -> <PIN as PwmPinOps<TC>>::Duty {
77+
self.pin.get_max_duty()
78+
}
79+
80+
pub fn set_duty(&mut self, duty: u8) {
81+
self.pin.set_duty(duty);
82+
}
83+
}
84+
3485
#[macro_export]
35-
macro_rules! impl_pwm {
86+
macro_rules! impl_simple_pwm {
3687
(
3788
$(#[$timer_pwm_attr:meta])*
3889
pub struct $TimerPwm:ident {
3990
timer: $TIMER:ty,
4091
init: |$init_timer:ident, $prescaler:ident| $init_block:block,
4192
pins: {$(
42-
$port:ident::$PXi:ident: {
93+
$PXi:ident: {
4394
ocr: $ocr:ident,
4495
$into_pwm:ident: |$pin_timer:ident| if enable
4596
$pin_enable_block:block else $pin_disable_block:block,
@@ -53,7 +104,7 @@ macro_rules! impl_pwm {
53104
}
54105

55106
impl $TimerPwm {
56-
pub fn new(timer: $TIMER, prescaler: $crate::pwm::Prescaler) -> $TimerPwm {
107+
pub fn new(timer: $TIMER, prescaler: $crate::simple_pwm::Prescaler) -> $TimerPwm {
57108
let mut t = $TimerPwm { timer };
58109

59110
{
@@ -67,15 +118,7 @@ macro_rules! impl_pwm {
67118
}
68119

69120
$(
70-
impl $port::$PXi<$crate::port::mode::Output> {
71-
pub fn $into_pwm(self, pwm_timer: &mut $TimerPwm)
72-
-> $port::$PXi<$crate::port::mode::Pwm<$TimerPwm>>
73-
{
74-
$port::$PXi { _mode: core::marker::PhantomData }
75-
}
76-
}
77-
78-
impl $crate::hal::PwmPin for $port::$PXi<$crate::port::mode::Pwm<$TimerPwm>> {
121+
impl avr_hal_generic::simple_pwm::PwmPinOps<$TimerPwm> for $PXi {
79122
type Duty = u8;
80123

81124
fn enable(&mut self) {
@@ -85,7 +128,7 @@ macro_rules! impl_pwm {
85128
$crate::avr_device::interrupt::free(|_| {
86129
let $pin_timer = unsafe { &*<$TIMER>::ptr() };
87130
$pin_enable_block
88-
})
131+
});
89132
}
90133

91134
fn disable(&mut self) {
@@ -95,7 +138,7 @@ macro_rules! impl_pwm {
95138
$crate::avr_device::interrupt::free(|_| {
96139
let $pin_timer = unsafe { &*<$TIMER>::ptr() };
97140
$pin_disable_block
98-
})
141+
});
99142
}
100143

101144
fn get_duty(&self) -> Self::Duty {
@@ -109,9 +152,9 @@ macro_rules! impl_pwm {
109152
fn set_duty(&mut self, duty: Self::Duty) {
110153
// SAFETY: This register is exclusively used here so there are no concurrency
111154
// issues.
112-
unsafe { (&*<$TIMER>::ptr()).$ocr.write(|w| w.bits(duty.into())) };
155+
unsafe { (&*<$TIMER>::ptr()).$ocr.write(|w| w.bits(duty.into())); };
113156
}
114157
}
115158
)+
116159
}
117-
}
160+
}

mcu/atmega-hal/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ pub mod port;
9090
#[cfg(feature = "device-selected")]
9191
pub use port::Pins;
9292

93+
#[cfg(feature = "device-selected")]
94+
pub mod simple_pwm;
95+
9396
#[cfg(feature = "device-selected")]
9497
pub mod usart;
9598
#[cfg(feature = "device-selected")]

0 commit comments

Comments
 (0)