feat set frequency embedded hal (#880)

* Add SetDutyCycle and PwmPin trait

* Add comments

* Fix method call for esp32c6 and esp32h2

* Add changelog
This commit is contained in:
Marc-Antoine Manningham 2023-11-08 22:33:47 -05:00 committed by GitHub
parent c196b67587
commit 62894e3f84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 149 additions and 0 deletions

View File

@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Implement SetFrequencyCycle and PwmPin from embedded_hal for PwmPin of MCPWM. (#880)
- Added `embassy-time-systick` to ESP32-S2 (#827) - Added `embassy-time-systick` to ESP32-S2 (#827)
- Implement enabling/disabling BLE clock on ESP32-C6 (#784) - Implement enabling/disabling BLE clock on ESP32-C6 (#784)
- Async support for RMT (#787) - Async support for RMT (#787)

View File

@ -501,6 +501,27 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
} }
} }
/// Get the old timestamp.
/// The value of the timestamp will take effect according to the set
/// [`PwmUpdateMethod`].
#[cfg(esp32)]
pub fn get_timestamp(&self) -> u16 {
// SAFETY:
// We only read to our GENx_TSTMP_x register
let block = unsafe { &*PWM::block() };
match (OP, IS_A) {
(0, true) => block.gen0_tstmp_a.read().gen0_a().bits(),
(1, true) => block.gen1_tstmp_a.read().gen1_a().bits(),
(2, true) => block.gen2_tstmp_a.read().gen2_a().bits(),
(0, false) => block.gen0_tstmp_b.read().gen0_b().bits(),
(1, false) => block.gen1_tstmp_b.read().gen1_b().bits(),
(2, false) => block.gen2_tstmp_b.read().gen2_b().bits(),
_ => {
unreachable!()
}
}
}
/// Write a new timestamp. /// Write a new timestamp.
/// The written value will take effect according to the set /// The written value will take effect according to the set
/// [`PwmUpdateMethod`]. /// [`PwmUpdateMethod`].
@ -522,6 +543,27 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
} }
} }
/// Get the old timestamp.
/// The value of the timestamp will take effect according to the set
/// [`PwmUpdateMethod`].
#[cfg(esp32s3)]
pub fn get_timestamp(&self) -> u16 {
// SAFETY:
// We only read to our GENx_TSTMP_x register
let block = unsafe { &*PWM::block() };
match (OP, IS_A) {
(0, true) => block.cmpr0_value0.read().cmpr0_a().bits(),
(1, true) => block.cmpr1_value0.read().cmpr1_a().bits(),
(2, true) => block.cmpr2_value0.read().cmpr2_a().bits(),
(0, false) => block.cmpr0_value1.read().cmpr0_b().bits(),
(1, false) => block.cmpr1_value1.read().cmpr1_b().bits(),
(2, false) => block.cmpr2_value1.read().cmpr2_b().bits(),
_ => {
unreachable!()
}
}
}
/// Write a new timestamp. /// Write a new timestamp.
/// The written value will take effect according to the set /// The written value will take effect according to the set
/// [`PwmUpdateMethod`]. /// [`PwmUpdateMethod`].
@ -542,6 +584,112 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
} }
} }
} }
/// Get the old timestamp.
/// The value of the timestamp will take effect according to the set
/// [`PwmUpdateMethod`].
#[cfg(any(esp32c6, esp32h2))]
pub fn get_timestamp(&self) -> u16 {
// SAFETY:
// We only read to our GENx_TSTMP_x register
let block = unsafe { &*PWM::block() };
match (OP, IS_A) {
(0, true) => block.gen0_tstmp_a.read().cmpr0_a().bits(),
(1, true) => block.gen1_tstmp_a.read().cmpr1_a().bits(),
(2, true) => block.gen2_tstmp_a.read().cmpr2_a().bits(),
(0, false) => block.gen0_tstmp_b.read().cmpr0_b().bits(),
(1, false) => block.gen1_tstmp_b.read().cmpr1_b().bits(),
(2, false) => block.gen2_tstmp_b.read().cmpr2_b().bits(),
_ => {
unreachable!()
}
}
}
/// Get the period of the timer.
fn get_period(&self) -> u16 {
// SAFETY:
// We only grant access to our CFG0 register with the lifetime of &mut self
let block = unsafe { &*PWM::block() };
let tim_select = block.operator_timersel.read();
let tim = match OP {
0 => tim_select.operator0_timersel().bits(),
1 => tim_select.operator1_timersel().bits(),
2 => tim_select.operator2_timersel().bits(),
_ => {
unreachable!()
}
};
// SAFETY:
// The CFG0 registers are identical for all timers so we can pretend they're
// TIMER0_CFG0
let timer0_cfg = match tim {
0 => &block.timer0_cfg0,
1 => unsafe { &*(&block.timer1_cfg0 as *const _ as *const _) },
2 => unsafe { &*(&block.timer2_cfg0 as *const _ as *const _) },
_ => unreachable!(),
};
timer0_cfg.read().timer0_period().bits()
}
}
impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> embedded_hal::PwmPin
for PwmPin<'d, Pin, PWM, OP, IS_A>
{
type Duty = u16;
/// This only set the timestamp to 0, if you want to disable the PwmPin,
/// it must be done on the timer itself.
fn disable(&mut self) {
self.set_timestamp(0);
}
/// This only set the timestamp to the maximum, if you want to disable the
/// PwmPin, it must be done on the timer itself.
fn enable(&mut self) {
self.set_timestamp(u16::MAX);
}
/// Get the duty of the pin
fn get_duty(&self) -> Self::Duty {
self.get_timestamp()
}
/// Get the max duty of the pin
fn get_max_duty(&self) -> Self::Duty {
self.get_period()
}
/// Set the duty of the pin
fn set_duty(&mut self, duty: Self::Duty) {
self.set_timestamp(duty);
}
}
/// Implement no error type for the PwmPin because the method are infallible
#[cfg(feature = "eh1")]
impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
embedded_hal_1::pwm::ErrorType for &mut PwmPin<'d, Pin, PWM, OP, IS_A>
{
type Error = core::convert::Infallible;
}
/// Implement the trait SetDutyCycle for PwmPin
#[cfg(feature = "eh1")]
impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
embedded_hal_1::pwm::SetDutyCycle for &mut PwmPin<'d, Pin, PWM, OP, IS_A>
{
/// Get the max duty of the PwmPin
fn get_max_duty_cycle(&self) -> u16 {
self.get_period()
}
/// Set the max duty of the PwmPin
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), core::convert::Infallible> {
self.set_timestamp(duty);
Ok(())
}
} }
/// An action the operator applies to an output /// An action the operator applies to an output