diff --git a/src/mcpwm/mod.rs b/src/mcpwm/mod.rs index 9a6682c2160..949445866ce 100644 --- a/src/mcpwm/mod.rs +++ b/src/mcpwm/mod.rs @@ -59,6 +59,7 @@ use core::borrow::Borrow; use crate::gpio::OutputPin; use crate::units::{FromValueType, Hertz}; +use crate::mcpwm::operator::{HwOperator, OPERATOR0, OPERATOR1, OPERATOR2}; use esp_idf_sys::*; // MCPWM clock source frequency for ESP32 and ESP32-s3 @@ -116,23 +117,13 @@ impl MCPWM { } pub trait Unit: Default { - fn unit() -> mcpwm_unit_t; + const ID: mcpwm_unit_t; } impl Unit for UnitZero { - fn unit() -> mcpwm_unit_t { - mcpwm_unit_t_MCPWM_UNIT_0 - } + const ID: mcpwm_unit_t = mcpwm_unit_t_MCPWM_UNIT_0; } impl Unit for UnitOne { - fn unit() -> mcpwm_unit_t { - mcpwm_unit_t_MCPWM_UNIT_1 - } -} - -trait OptionalOperator> {} - -struct NoOperator; -impl OptionalOperator for NoOperator {} - + const ID: mcpwm_unit_t = mcpwm_unit_t_MCPWM_UNIT_1; +} \ No newline at end of file diff --git a/src/mcpwm/operator.rs b/src/mcpwm/operator.rs index aafaac9536e..dfaab85935b 100644 --- a/src/mcpwm/operator.rs +++ b/src/mcpwm/operator.rs @@ -1,24 +1,28 @@ +use std::borrow::Borrow; + +use esp_idf_sys::{mcpwm_io_signals_t, mcpwm_unit_t, mcpwm_operator_t, + mcpwm_io_signals_t_MCPWM0A, mcpwm_io_signals_t_MCPWM0B, + mcpwm_io_signals_t_MCPWM1A, mcpwm_io_signals_t_MCPWM1B, + mcpwm_io_signals_t_MCPWM2A, mcpwm_io_signals_t_MCPWM2B, EspError +}; + +use crate::{mcpwm::{Unit, UnitZero, UnitOne}, gpio::OutputPin}; + +use super::{Duty, timer_connection::OptionalOutputPin}; + // The hardware for ESP32 and ESP32-S3 can associate any operator(within the mcpwm module) with any // timer(within the mcpwm module) for example allowing using the same timer for all three operators. -// However at least as of IDF v4.4 timer0 is hardcoded to operator0 and timer1 to operator1 and so on... -pub trait HwOperator: Into> { - fn signal_a() -> mcpwm_io_signals_t; - fn signal_b() -> mcpwm_io_signals_t; - fn unit() -> mcpwm_unit_t { - U::unit() - } +pub trait HwOperator { + const SIGNAL_A: mcpwm_io_signals_t; + const SIGNAL_B: mcpwm_io_signals_t; + const UNIT_ID: mcpwm_unit_t = U::ID; } macro_rules! impl_operator_helper { ($instance:ident: $timer:expr, $signal_a:expr, $signal_b:expr, $unit:ty) => { impl HwOperator<$unit> for $instance<$unit> { - fn signal_a() -> mcpwm_io_signals_t { - $signal_a - } - - fn signal_b() -> mcpwm_io_signals_t { - $signal_b - } + const SIGNAL_A: mcpwm_io_signals_t = $signal_a; + const SIGNAL_B: mcpwm_io_signals_t = $signal_b; } }; } @@ -40,16 +44,6 @@ macro_rules! impl_operator { } } - impl Into> for $instance { - fn into(self) -> Operator { - Operator { - _instance: self, - pin_a: NoPin, - pin_b: NoPin, - } - } - } - impl_operator_helper!($instance: $timer, $signal_a, $signal_b, UnitZero); impl_operator_helper!($instance: $timer, $signal_a, $signal_b, UnitOne); }; @@ -79,21 +73,20 @@ impl_operator!( /// /// Every Motor Control module has three operators. Every operator can generate two output signals called A and B. /// A and B share the same timer and thus frequency and phase but can have induvidual duty set. -pub struct Operator, M: Borrow>, PA: OptionalPin, PB: OptionalPin, D> { +pub struct Operator, PA: OptionalOutputPin, PB: OptionalOutputPin> { handle: mcpwm_operator_t, _instance: O, _pin_a: PA, _pin_b: PB, - deadtime: D + //deadtime: D } -impl Operator +impl Operator where U: Unit, O: HwOperator, - M: Borrow>, PA: OutputPin, PB: OptionalOutputPin, { @@ -108,11 +101,10 @@ where } } -impl Operator +impl Operator where U: Unit, O: HwOperator, - M: Borrow>, PA: OptionalOutputPin, PB: OutputPin, { @@ -134,7 +126,7 @@ pub struct OperatorConfig { duty_mode: DutyMode, - deadtime: Option, + //deadtime: Option, } impl OperatorConfig { @@ -159,26 +151,22 @@ impl OperatorConfig { self } - #[must_use] + /*#[must_use] pub fn deadtime(mut self, deadtime: impl Into>) -> Self { self.deadtime = deadtime.into(); self - } + }*/ } impl Default for OperatorConfig { fn default() -> Self { Self { - frequency: 1000.Hz(), - duty_a: 50.0, - duty_b: 50.0, - - #[cfg(not(esp_idf_version = "4.3"))] - lowest_frequency: 16.Hz(), + duty_a: 0.0, + duty_b: 0.0, duty_mode: DutyMode::ActiveHigh, - deadtime: None, + //deadtime: None, } } } @@ -199,6 +187,13 @@ pub enum DutyMode { ActiveLow, } +pub trait OptionalOperator> {} + +pub struct NoOperator; +impl> OptionalOperator for NoOperator {} + +/* + #[derive(Default, Clone)] struct DutyConfig { on_matches_cmp_a: CountingDirection, @@ -226,23 +221,30 @@ impl Default for GeneratorAction { } } -impl From for DutyConfig { - fn from(val: DutyMode) -> Self { +impl DutyMode { + fn into_duty_cfg(self) -> DutyConfig { match val { DutyMode::ActiveHigh => { let mut duty_config: DutyConfig = Default::default(); duty_config.on_is_empty.counting_up = GeneratorAction::SetHigh; - duty_config.on_matches_cmp_a.counting_up = GeneratorAction::SetLow; - + if G::IS_A { + duty_config.on_matches_cmp_a.counting_up = GeneratorAction::SetLow; + } else { + duty_config.on_matches_cmp_b.counting_up = GeneratorAction::SetLow; + } duty_config }, DutyMode::ActiveLow => { let mut duty_config: DutyConfig = Default::default(); duty_config.on_is_empty.counting_up = GeneratorAction::SetLow; - duty_config.on_matches_cmp_a.counting_up = GeneratorAction::SetHigh; + if G::IS_A { + duty_config.on_matches_cmp_a.counting_up = GeneratorAction::SetHigh; + } else { + duty_config.on_matches_cmp_b.counting_up = GeneratorAction::SetHigh; + } duty_config }, } } -} \ No newline at end of file +} */ \ No newline at end of file diff --git a/src/mcpwm/timer.rs b/src/mcpwm/timer.rs index 1baf98cfaa1..abed247e175 100644 --- a/src/mcpwm/timer.rs +++ b/src/mcpwm/timer.rs @@ -1,3 +1,14 @@ +use std::ptr; + +use esp_idf_sys::{mcpwm_counter_type_t_MCPWM_UP_DOWN_COUNTER, mcpwm_counter_type_t_MCPWM_DOWN_COUNTER, mcpwm_counter_type_t_MCPWM_UP_COUNTER, mcpwm_timer_t, mcpwm_timer_handle_t, mcpwm_timer_enable, mcpwm_timer_t_MCPWM_TIMER_0, mcpwm_timer_t_MCPWM_TIMER_1, mcpwm_timer_t_MCPWM_TIMER_2, mcpwm_counter_type_t}; + +use crate::units::Hertz; +use crate::mcpwm::Unit; + +use super::operator::NoOperator; +use super::timer_connection::TimerConnection; + + #[derive(Clone, Copy, Debug)] struct TimerConfig { frequency: Hertz, @@ -5,9 +16,9 @@ struct TimerConfig { counter_mode: CounterMode, // TODO - // on_full, - // on_empty, - // on_stop, + // on_full: FF, + // on_empty: FE, + // on_stop: FS, } impl TimerConfig { @@ -40,12 +51,12 @@ impl TimerConfig { //} //} -struct Timer> { +pub struct Timer> { handle: mcpwm_timer_handle_t, _timer: T, } -impl Timer { +impl> Timer { pub fn new(timer: T, config: TimerConfig) -> Self { let config = mcpwm_timer_config_t { resolution @@ -71,7 +82,7 @@ impl Timer { } pub fn timer(&self) -> mcpwm_timer_t { - T::timer() + T::ID } pub fn release(self) -> T { @@ -88,7 +99,7 @@ impl Timer { } } -impl Drop for Timer { +impl> Drop for Timer { fn drop(self) { mcpwm_del_timer(self.handle) } @@ -99,8 +110,8 @@ impl Drop for Timer { #[derive(Clone, Copy, Debug)] pub enum CounterMode { /// Timer is frozen or paused - #[cfg(not(esp_idf_version = "4.3"))] - Frozen, + //#[cfg(not(esp_idf_version = "4.3"))] + //Frozen, /// Edge aligned. The counter will start from its lowest value and increment every clock cycle until the period is reached. /// /// The wave form will end up looking something like the following: @@ -158,11 +169,27 @@ pub enum CounterMode { impl From for mcpwm_counter_type_t { fn from(val: CounterMode) -> Self { match val { - #[cfg(not(esp_idf_version = "4.3"))] - CounterMode::Frozen => mcpwm_counter_type_t_MCPWM_FREEZE_COUNTER, + //CounterMode::Frozen => mcpwm_counter_type_t_MCPWM_FREEZE_COUNTER, CounterMode::Up => mcpwm_counter_type_t_MCPWM_UP_COUNTER, CounterMode::Down => mcpwm_counter_type_t_MCPWM_DOWN_COUNTER, CounterMode::UpDown => mcpwm_counter_type_t_MCPWM_UP_DOWN_COUNTER, } } -} \ No newline at end of file +} + +unsafe trait HwTimer { + const ID: mcpwm_timer_t; +} + +macro_rules! impl_timer { + ($t:ident, $id:expr) => { + struct $t; + impl HwTimer for $t { + const ID: mcpwm_timer_t = $id; + } + }; +} + +impl_timer!(TIMER0, mcpwm_timer_t_MCPWM_TIMER_0); +impl_timer!(TIMER1, mcpwm_timer_t_MCPWM_TIMER_1); +impl_timer!(TIMER2, mcpwm_timer_t_MCPWM_TIMER_2); \ No newline at end of file diff --git a/src/mcpwm/timer_connection.rs b/src/mcpwm/timer_connection.rs index ea9a25b5678..02ee3d8daa6 100644 --- a/src/mcpwm/timer_connection.rs +++ b/src/mcpwm/timer_connection.rs @@ -1,15 +1,19 @@ +use crate::{mcpwm::Unit, gpio::OutputPin}; + +use super::operator::{OptionalOperator, OPERATOR0, OperatorConfig, NoOperator, OPERATOR2, OPERATOR1}; + // TODO: How do we want fault module to fit into this? /// Created by `Timer::into_connection()` pub struct TimerConnection, O0, O1, O2> where - O0: OptionalOperator, - O1: OptionalOperator, - O2: OptionalOperator, + O0: OptionalOperator>, + O1: OptionalOperator>, + O2: OptionalOperator>, { timer: Timer, - operator0: O0, - operator1: O1, - operator2: O2 + operator0: O0, + operator1: O1, + operator2: O2 } impl TimerConnection { @@ -38,9 +42,9 @@ impl, O1: OptionalOperator TimerConnection { - fn attatch_operator0>(mut self, operator_cfg: O) -> TimerConnection { + fn attatch_operator0(mut self, operator_handle: OPERATOR0, operator_cfg: OperatorConfig, pin_a: PA, pin_b: PB) -> TimerConnection { let operator = self.init_and_attach_operator(operator_cfg, pin_a, pin_b); TimerConnection { timer: self.timer, @@ -52,7 +56,7 @@ impl TimerConnection { } impl TimerConnection { - fn attatch_operator1>(mut self, operator: O) -> TimerConnection { + fn attatch_operator1(mut self, operator_handle: OPERATOR1, operator_cfg: OperatorConfig, pin_a: PA, pin_b: PB) -> TimerConnection { let operator = self.init_and_attach_operator(operator_cfg, pin_a, pin_b); TimerConnection { timer: self.timer, @@ -64,7 +68,7 @@ impl TimerConnection { } impl TimerConnection { - fn attatch_operator2>(mut self, operator: O) -> TimerConnection { + fn attatch_operator2(mut self, operator_handle: OPERATOR2, operator_cfg: OperatorConfig, pin_a: PA, pin_b: PB) -> TimerConnection { let operator = self.init_and_attach_operator(operator_cfg, pin_a, pin_b); TimerConnection { timer: self.timer, @@ -73,4 +77,8 @@ impl TimerConnection { operator2: operator } } -} \ No newline at end of file +} + +pub struct NoPin; + +pub trait OptionalOutputPin {} \ No newline at end of file