Skip to content

Commit

Permalink
implement embedded-hal v1 SetDutyCycle
Browse files Browse the repository at this point in the history
this also ships with an example making use of it. note that the fading
of the new example is faster than the existing `uno-simple-pwm.rs`
example, since the latter fades with 255 steps while the new example
uses 0 - 100% percent (and thus only sleeps 200 * 10ms instead of
512 * 10ms).
  • Loading branch information
rursprung committed Dec 24, 2023
1 parent 0abafde commit 0d8b3e5
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
31 changes: 31 additions & 0 deletions avr-hal-generic/src/simple_pwm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! PWM Implementation

use core::marker::PhantomData;
use embedded_hal::pwm;
use embedded_hal::pwm::{ErrorKind, ErrorType, SetDutyCycle};

use crate::port::mode;
use crate::port::Pin;
Expand Down Expand Up @@ -82,6 +84,35 @@ impl<TC, PIN: PwmPinOps<TC>> Pin<mode::PwmOutput<TC>, PIN> {
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum PwmError {
/// `embedded-hal` supports duty cycles up to `u16`, however `avr` devices only support up to `u8`.
/// Passing a duty cycle larger than [`u8::MAX`] will result in this error.
DutyCycleTooLarge,
}

impl pwm::Error for PwmError {
fn kind(&self) -> ErrorKind {
ErrorKind::Other
}
}

impl<TC, PIN: PwmPinOps<TC>> ErrorType for Pin<mode::PwmOutput<TC>, PIN> { type Error = PwmError; }

impl<TC, PIN: PwmPinOps<TC, Duty=u8>> SetDutyCycle for Pin<mode::PwmOutput<TC>, PIN> {
fn max_duty_cycle(&self) -> u16 {
self.get_max_duty() as u16
}

fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
if duty > u8::MAX as u16 {
return Err(PwmError::DutyCycleTooLarge);
}
self.set_duty(duty as u8);
Ok(())
}
}

#[macro_export]
macro_rules! impl_simple_pwm {
(
Expand Down
36 changes: 36 additions & 0 deletions examples/arduino-uno/src/bin/uno-simple-pwm-embedded-hal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
* Example of using simple_pwm to fade a LED in and out on pin d5, but with a twist:
* the fade function is not aware of `avr-hal` and only uses `embedded-hal` traits.
*/
#![no_std]
#![no_main]

use embedded_hal::delay::DelayNs;
use embedded_hal::pwm::SetDutyCycle;
use arduino_hal::simple_pwm::*;
use panic_halt as _;

fn fade(led: &mut impl SetDutyCycle, delay: &mut impl DelayNs) -> ! {
loop {
for pct in (0..=100).chain((0..100).rev()) {
led.set_duty_cycle_percent(pct).unwrap();
delay.delay_ms(10);
}
}
}

#[arduino_hal::entry]
fn main() -> ! {
let dp = arduino_hal::Peripherals::take().unwrap();
let pins = arduino_hal::pins!(dp);

let timer0 = Timer0Pwm::new(dp.TC0, Prescaler::Prescale64);

// Digital pin 5 is connected to a LED and a resistor in series
let mut pwm_led = pins.d5.into_output().into_pwm(&timer0);
pwm_led.enable();

let mut delay = arduino_hal::Delay::new();

fade(&mut pwm_led, &mut delay);
}

0 comments on commit 0d8b3e5

Please sign in to comment.