Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hal pwm impl #162

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions device-support/src/peripherals/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod pwm;
113 changes: 113 additions & 0 deletions device-support/src/peripherals/pwm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use lc3_traits::peripherals::pwm::{Pwm as lc3_pwm, *};
extern crate embedded_hal;
use embedded_hal as hal;
use embedded_hal::{Pwm as hal_pwm, PwmPin as hal_pwm_pin};
use core::marker::PhantomData;
use core::cell::RefCell;
use embedded_hal::prelude::_embedded_hal_PwmPin;

// Embedded hal; offers the Pwm and PwmPin trait, but it looks like
// PwmPin and Pwm hal traits don't really have anything to do with each other and are just both
// offered to allow users chose what they want. It's unlike the ADC case where the Oneshot trait did use
// the ADC Channel trait for individual pin references.
// In Pwm case though, there is an associated type for the Pwm trait called channel but using this would need
// custom implementation on that channel associated type to index into and access our pin arrays and this is a needless inconvenience
// Hence, we'll use the PwmPin trait here which has it's own self contained pwm operation functions and create an array of pins.
// PwmPin is also the more mature trait as the hal Pwm trait is marked unproven.
// Only drawback is the TM4C currently doesn't have an implementation for PwmPin (it has one for Pwm) but that is ok. TODO: Make PwmPin impl for TM4C

pub struct generic_pwm_unit<T, U>
where T: hal_pwm_pin + _embedded_hal_PwmPin<Duty = U>,
U: From<u16> + Into<u16> //adding this trait bound on duty to allow converting to integer form for our platform use. Similar approach as ADC
{
hal_pins: RefCell<PwmPinArr<T>>,
pin_states: PwmPinArr<PwmState>,
phantom: PhantomData<U>,
}

impl <T, U> Default for generic_pwm_unit<T, U>
where T: hal_pwm_pin<Duty = U>,
U: From<u16> + Into<u16>,
{
fn default() -> Self{
unimplemented!()
}
}

impl <T, U> generic_pwm_unit<T, U>
where T: hal_pwm_pin<Duty = U>,
U: From<u16> + Into<u16>,
{
fn new(pwm_device_pins: PwmPinArr<T>) -> Self{
Self{
hal_pins: RefCell::new(pwm_device_pins),
pin_states: PwmPinArr([PwmState::Disabled; PwmPin::NUM_PINS]),
phantom: PhantomData,
}
}
}

impl <T, U> lc3_pwm for generic_pwm_unit<T, U>
where T: hal_pwm_pin + _embedded_hal_PwmPin<Duty = U>,
U: From<u16> + Into<u16>,
{
fn set_state(&mut self, pin: PwmPin, state: PwmState){
let mut hal_pins = self.hal_pins.borrow_mut();
match state{
PwmState::Enabled(duty) => {
hal_pins[pin].enable();
hal_pins[pin].set_duty(U::from(core::num::NonZeroU8::get(duty) as u16));
}
PwmState::Disabled => {
hal_pins[pin].disable();
}
}
self.pin_states[pin] = state;
}
fn get_state(&self, pin: PwmPin) -> PwmState{
self.pin_states[pin]
}
#[inline]
fn get_states(&self) -> PwmPinArr<PwmState> {
let mut states = PwmPinArr([PwmState::Disabled; PwmPin::NUM_PINS]);

PWM_PINS
.iter()
.for_each(|p| states[*p] = self.get_state(*p));

states
}

//Should this function be infallible since there is no error return?
//For ADC, couldn't read a disabled pin for instance, but since there is no
//error checking here, just enable and set a pin of it is disabled.
//And just set duty to 1 if 0 to avoid crashing on unwrap
fn set_duty_cycle(&mut self, pin: PwmPin, duty_cycle: PwmDutyCycle){
let mut duty_cycle_temp = duty_cycle;
if(duty_cycle_temp == 0){
duty_cycle_temp = 1;
}
self.set_state(pin, PwmState::Enabled(core::num::NonZeroU8::new(duty_cycle_temp).unwrap()));
}
fn get_duty_cycle(&self, pin: PwmPin) -> PwmDutyCycle{
let state = self.get_state(pin);
let mut duty_return = core::num::NonZeroU8::new(1).unwrap();
match state{
PwmState::Enabled(duty) => {
duty_return = duty;
}
PwmState::Disabled => {}
}
core::num::NonZeroU8::get(duty_return)
}
#[inline]
fn get_duty_cycles(&self) -> PwmPinArr<PwmDutyCycle> {
let mut duty_cycles = PwmPinArr([0u8; PwmPin::NUM_PINS]);

PWM_PINS
.iter()
.for_each(|p| duty_cycles[*p] = self.get_duty_cycle(*p));

duty_cycles
}
}