mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 21:00:59 +00:00
MCPWM clusters (#1360)
This commit is contained in:
parent
bd1e1fab1a
commit
9b048f4c99
@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- UART: Rework `change_baud` so it is possible to set baud rate even after instantiation (#1350)
|
||||
- Runtime ISR binding for SHA,ECC and RSA (#1354)
|
||||
- Update `pac`s with removed suffixes in `int` field names. Use `W1TC` for `int_clr`
|
||||
- Update `pac`s with removed suffixes in `int` field names. Use `W1TC` for `int_clr` (#1357) and MCPWM clusters (#1360)
|
||||
|
||||
### Removed
|
||||
|
||||
|
@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true }
|
||||
# IMPORTANT:
|
||||
# Each supported device MUST have its PAC included below along with a
|
||||
# corresponding feature.
|
||||
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "riscv32")'.dependencies]
|
||||
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }
|
||||
|
@ -142,71 +142,6 @@ impl DeadTimeCfg {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp32s3")]
|
||||
fn dt_cfg<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DB0_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.db0_cfg(),
|
||||
1 => unsafe { &*(&block.db1_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.db2_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "esp32s3")]
|
||||
fn dt_fed<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DB0_FED_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.db0_fed_cfg(),
|
||||
1 => unsafe { &*(&block.db1_fed_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.db2_fed_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "esp32s3")]
|
||||
fn dt_red<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DB0_RED_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.db0_red_cfg(),
|
||||
1 => unsafe { &*(&block.db1_red_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.db2_red_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: dt_cfg, dt_fed, dt_red (and similar functions in mcpwm can be made safe
|
||||
// by patching PACS)
|
||||
#[cfg(not(feature = "esp32s3"))]
|
||||
fn dt_cfg<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DT0_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.dt0_cfg(),
|
||||
1 => unsafe { &*(&block.dt1_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.dt2_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "esp32s3"))]
|
||||
fn dt_fed<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DT0_FED_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.dt0_fed_cfg(),
|
||||
1 => unsafe { &*(&block.dt1_fed_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.dt2_fed_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "esp32s3"))]
|
||||
fn dt_red<const OP: u8, PWM: PwmPeripheral>() -> &'static crate::peripherals::mcpwm0::DT0_RED_CFG {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match OP {
|
||||
0 => block.dt0_red_cfg(),
|
||||
1 => unsafe { &*(&block.dt1_red_cfg() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.dt2_red_cfg() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A MCPWM operator
|
||||
///
|
||||
/// The PWM Operator submodule has the following functions:
|
||||
@ -255,9 +190,23 @@ impl<const OP: u8, PWM: PwmPeripheral> Operator<OP, PWM> {
|
||||
|
||||
/// Configures deadtime for this operator
|
||||
pub fn set_deadtime(&mut self, cfg: &DeadTimeCfg) {
|
||||
dt_fed::<OP, PWM>().write(|w| unsafe { w.bits(cfg.falling_edge_delay as u32) });
|
||||
dt_red::<OP, PWM>().write(|w| unsafe { w.bits(cfg.rising_edge_delay as u32) });
|
||||
dt_cfg::<OP, PWM>().write(|w| unsafe { w.bits(cfg.cfg_reg) });
|
||||
let ch = unsafe { &*PWM::block() }.ch(OP as usize);
|
||||
#[cfg(esp32s3)]
|
||||
{
|
||||
ch.db_fed_cfg()
|
||||
.write(|w| unsafe { w.bits(cfg.falling_edge_delay as u32) });
|
||||
ch.db_red_cfg()
|
||||
.write(|w| unsafe { w.bits(cfg.rising_edge_delay as u32) });
|
||||
ch.db_cfg().write(|w| unsafe { w.bits(cfg.cfg_reg) });
|
||||
}
|
||||
#[cfg(not(esp32s3))]
|
||||
{
|
||||
ch.dt_fed_cfg()
|
||||
.write(|w| unsafe { w.bits(cfg.falling_edge_delay as u32) });
|
||||
ch.dt_red_cfg()
|
||||
.write(|w| unsafe { w.bits(cfg.rising_edge_delay as u32) });
|
||||
ch.dt_cfg().write(|w| unsafe { w.bits(cfg.cfg_reg) });
|
||||
}
|
||||
}
|
||||
|
||||
/// Use the A output with the given pin and configuration
|
||||
@ -350,7 +299,11 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
|
||||
/// another pin
|
||||
#[inline]
|
||||
pub fn update_fed(&self, cycles: u16) {
|
||||
dt_fed::<OP, PWM>().write(|w| unsafe { w.bits(cycles as u32) });
|
||||
#[cfg(esp32s3)]
|
||||
let dt_fed = unsafe { Self::ch() }.db_fed_cfg();
|
||||
#[cfg(not(esp32s3))]
|
||||
let dt_fed = unsafe { Self::ch() }.dt_fed_cfg();
|
||||
dt_fed.write(|w| unsafe { w.bits(cycles as u32) });
|
||||
}
|
||||
|
||||
/// Updates dead-time RED register
|
||||
@ -359,251 +312,89 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
|
||||
/// another pin
|
||||
#[inline]
|
||||
pub fn update_red(&self, cycles: u16) {
|
||||
dt_red::<OP, PWM>().write(|w| unsafe { w.bits(cycles as u32) });
|
||||
#[cfg(esp32s3)]
|
||||
let dt_red = unsafe { Self::ch() }.db_red_cfg();
|
||||
#[cfg(not(esp32s3))]
|
||||
let dt_red = unsafe { Self::ch() }.dt_red_cfg();
|
||||
dt_red.write(|w| unsafe { w.bits(cycles as u32) });
|
||||
}
|
||||
|
||||
/// Configure what actions should be taken on timing events
|
||||
pub fn set_actions(&mut self, value: PwmActions<IS_A>) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_x register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
|
||||
let ch = unsafe { Self::ch() };
|
||||
let bits = value.0;
|
||||
|
||||
// SAFETY:
|
||||
// `bits` is a valid bit pattern
|
||||
unsafe {
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block.gen0_a().write(|w| w.bits(bits)),
|
||||
(1, true) => block.gen1_a().write(|w| w.bits(bits)),
|
||||
(2, true) => block.gen2_a().write(|w| w.bits(bits)),
|
||||
(0, false) => block.gen0_b().write(|w| w.bits(bits)),
|
||||
(1, false) => block.gen1_b().write(|w| w.bits(bits)),
|
||||
(2, false) => block.gen2_b().write(|w| w.bits(bits)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ch.gen((!IS_A) as usize).write(|w| unsafe { w.bits(bits) })
|
||||
}
|
||||
|
||||
/// Set how a new timestamp syncs with the timer
|
||||
#[cfg(esp32)]
|
||||
pub fn set_update_method(&mut self, update_method: PwmUpdateMethod) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_x_UPMETHOD register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
let ch = unsafe { Self::ch() };
|
||||
let bits = update_method.0;
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block
|
||||
.gen0_stmp_cfg()
|
||||
.modify(|_, w| w.gen0_a_upmethod().variant(bits)),
|
||||
(1, true) => block
|
||||
.gen1_stmp_cfg()
|
||||
.modify(|_, w| w.gen1_a_upmethod().variant(bits)),
|
||||
(2, true) => block
|
||||
.gen2_stmp_cfg()
|
||||
.modify(|_, w| w.gen2_a_upmethod().variant(bits)),
|
||||
(0, false) => block
|
||||
.gen0_stmp_cfg()
|
||||
.modify(|_, w| w.gen0_b_upmethod().variant(bits)),
|
||||
(1, false) => block
|
||||
.gen1_stmp_cfg()
|
||||
.modify(|_, w| w.gen1_b_upmethod().variant(bits)),
|
||||
(2, false) => block
|
||||
.gen2_stmp_cfg()
|
||||
.modify(|_, w| w.gen2_b_upmethod().variant(bits)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set how a new timestamp syncs with the timer
|
||||
#[cfg(esp32s3)]
|
||||
pub fn set_update_method(&mut self, update_method: PwmUpdateMethod) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_x_UPMETHOD register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
let bits = update_method.0;
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block
|
||||
.cmpr0_cfg()
|
||||
.modify(|_, w| w.cmpr0_a_upmethod().variant(bits)),
|
||||
(1, true) => block
|
||||
.cmpr1_cfg()
|
||||
.modify(|_, w| w.cmpr1_a_upmethod().variant(bits)),
|
||||
(2, true) => block
|
||||
.cmpr2_cfg()
|
||||
.modify(|_, w| w.cmpr2_a_upmethod().variant(bits)),
|
||||
(0, false) => block
|
||||
.cmpr0_cfg()
|
||||
.modify(|_, w| w.cmpr0_b_upmethod().variant(bits)),
|
||||
(1, false) => block
|
||||
.cmpr1_cfg()
|
||||
.modify(|_, w| w.cmpr1_b_upmethod().variant(bits)),
|
||||
(2, false) => block
|
||||
.cmpr2_cfg()
|
||||
.modify(|_, w| w.cmpr2_b_upmethod().variant(bits)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(esp32s3)]
|
||||
let cfg = ch.cmpr_cfg();
|
||||
#[cfg(any(esp32, esp32c6, esp32h2))]
|
||||
let cfg = ch.gen_stmp_cfg();
|
||||
|
||||
/// Set how a new timestamp syncs with the timer
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
pub fn set_update_method(&mut self, update_method: PwmUpdateMethod) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_x_UPMETHOD register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
let bits = update_method.0;
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block
|
||||
.gen0_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr0_a_upmethod().variant(bits)),
|
||||
(1, true) => block
|
||||
.gen1_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr1_a_upmethod().variant(bits)),
|
||||
(2, true) => block
|
||||
.gen2_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr2_a_upmethod().variant(bits)),
|
||||
(0, false) => block
|
||||
.gen0_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr0_b_upmethod().variant(bits)),
|
||||
(1, false) => block
|
||||
.gen1_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr1_b_upmethod().variant(bits)),
|
||||
(2, false) => block
|
||||
.gen2_stmp_cfg()
|
||||
.modify(|_, w| w.cmpr2_b_upmethod().variant(bits)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
cfg.modify(|_, w| unsafe {
|
||||
if IS_A {
|
||||
w.a_upmethod().bits(bits)
|
||||
} else {
|
||||
w.b_upmethod().bits(bits)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Write a new timestamp.
|
||||
/// The written value will take effect according to the set
|
||||
/// [`PwmUpdateMethod`].
|
||||
#[cfg(esp32)]
|
||||
pub fn set_timestamp(&mut self, value: u16) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_TSTMP_x register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block.gen0_tstmp_a().write(|w| w.gen0_a().variant(value)),
|
||||
(1, true) => block.gen1_tstmp_a().write(|w| w.gen1_a().variant(value)),
|
||||
(2, true) => block.gen2_tstmp_a().write(|w| w.gen2_a().variant(value)),
|
||||
(0, false) => block.gen0_tstmp_b().write(|w| w.gen0_b().variant(value)),
|
||||
(1, false) => block.gen1_tstmp_b().write(|w| w.gen1_b().variant(value)),
|
||||
(2, false) => block.gen2_tstmp_b().write(|w| w.gen2_b().variant(value)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
let ch = unsafe { Self::ch() };
|
||||
|
||||
#[cfg(esp32s3)]
|
||||
if IS_A {
|
||||
ch.cmpr_value0().write(|w| unsafe { w.a().bits(value) })
|
||||
} else {
|
||||
ch.cmpr_value1().write(|w| unsafe { w.b().bits(value) })
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32c6, esp32h2))]
|
||||
if IS_A {
|
||||
ch.gen_tstmp_a().write(|w| unsafe { w.a().bits(value) })
|
||||
} else {
|
||||
ch.gen_tstmp_b().write(|w| unsafe { w.b().bits(value) })
|
||||
}
|
||||
}
|
||||
|
||||
/// 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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
let ch = unsafe { Self::ch() };
|
||||
|
||||
/// Write a new timestamp.
|
||||
/// The written value will take effect according to the set
|
||||
/// [`PwmUpdateMethod`].
|
||||
#[cfg(esp32s3)]
|
||||
pub fn set_timestamp(&mut self, value: u16) {
|
||||
// SAFETY:
|
||||
// We only write to our CMPRx_VALUEx register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block.cmpr0_value0().write(|w| w.cmpr0_a().variant(value)),
|
||||
(1, true) => block.cmpr1_value0().write(|w| w.cmpr1_a().variant(value)),
|
||||
(2, true) => block.cmpr2_value0().write(|w| w.cmpr2_a().variant(value)),
|
||||
(0, false) => block.cmpr0_value1().write(|w| w.cmpr0_b().variant(value)),
|
||||
(1, false) => block.cmpr1_value1().write(|w| w.cmpr1_b().variant(value)),
|
||||
(2, false) => block.cmpr2_value1().write(|w| w.cmpr2_b().variant(value)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
#[cfg(esp32s3)]
|
||||
if IS_A {
|
||||
ch.cmpr_value0().read().a().bits()
|
||||
} else {
|
||||
ch.cmpr_value1().read().b().bits()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// The written value will take effect according to the set
|
||||
/// [`PwmUpdateMethod`].
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
pub fn set_timestamp(&mut self, value: u16) {
|
||||
// SAFETY:
|
||||
// We only write to our GENx_TSTMP_x register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
match (OP, IS_A) {
|
||||
(0, true) => block.gen0_tstmp_a().write(|w| w.cmpr0_a().variant(value)),
|
||||
(1, true) => block.gen1_tstmp_a().write(|w| w.cmpr1_a().variant(value)),
|
||||
(2, true) => block.gen2_tstmp_a().write(|w| w.cmpr2_a().variant(value)),
|
||||
(0, false) => block.gen0_tstmp_b().write(|w| w.cmpr0_b().variant(value)),
|
||||
(1, false) => block.gen1_tstmp_b().write(|w| w.cmpr1_b().variant(value)),
|
||||
(2, false) => block.gen2_tstmp_b().write(|w| w.cmpr2_b().variant(value)),
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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!()
|
||||
}
|
||||
#[cfg(any(esp32, esp32c6, esp32h2))]
|
||||
if IS_A {
|
||||
ch.gen_tstmp_a().read().a().bits()
|
||||
} else {
|
||||
ch.gen_tstmp_b().read().b().bits()
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,15 +417,12 @@ impl<'d, Pin: OutputPin, PWM: PwmPeripheral, const OP: u8, const IS_A: bool>
|
||||
// SAFETY:
|
||||
// The CFG0 registers are identical for all timers so we can pretend they're
|
||||
// TIMER0_CFG0
|
||||
let timer0_cfg = &block.timer0_cfg0();
|
||||
let timer0_cfg = match tim {
|
||||
0 => timer0_cfg,
|
||||
1 => unsafe { &*(&block.timer1_cfg0() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.timer2_cfg0() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
block.timer(tim as usize).cfg0().read().period().bits()
|
||||
}
|
||||
|
||||
timer0_cfg.read().timer0_period().bits()
|
||||
unsafe fn ch() -> &'static crate::peripherals::mcpwm0::CH {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
block.ch(OP as usize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ use fugit::HertzU32;
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
mcpwm::{FrequencyError, PeripheralClockConfig, PwmPeripheral},
|
||||
peripherals::mcpwm0::{TIMER0_CFG0, TIMER0_CFG1},
|
||||
};
|
||||
|
||||
/// A MCPWM timer
|
||||
@ -46,136 +45,63 @@ impl<const TIM: u8, PWM: PwmPeripheral> Timer<TIM, PWM> {
|
||||
/// events but this HAL does not expose these for now.
|
||||
pub fn start(&mut self, timer_config: TimerClockConfig) {
|
||||
// write prescaler and period with immediate update method
|
||||
self.cfg0().write(|w| {
|
||||
w.timer0_prescale()
|
||||
.variant(timer_config.prescaler)
|
||||
.timer0_period()
|
||||
.variant(timer_config.period)
|
||||
.timer0_period_upmethod()
|
||||
.variant(0)
|
||||
self.cfg0().write(|w| unsafe {
|
||||
w.prescale().bits(timer_config.prescaler);
|
||||
w.period().bits(timer_config.period);
|
||||
w.period_upmethod().bits(0)
|
||||
});
|
||||
|
||||
// set timer to continuously run and set the timer working mode
|
||||
self.cfg1().write(|w| {
|
||||
w.timer0_start()
|
||||
.variant(2)
|
||||
.timer0_mod()
|
||||
.variant(timer_config.mode as u8)
|
||||
self.cfg1().write(|w| unsafe {
|
||||
w.start().bits(2);
|
||||
w.mod_().bits(timer_config.mode as u8)
|
||||
});
|
||||
}
|
||||
|
||||
/// Stop the timer in its current state
|
||||
pub fn stop(&mut self) {
|
||||
// freeze the timer
|
||||
self.cfg1().write(|w| w.timer0_mod().variant(0));
|
||||
self.cfg1().write(|w| unsafe { w.mod_().bits(0) });
|
||||
}
|
||||
|
||||
/// Set the timer counter to the provided value
|
||||
pub fn set_counter(&mut self, phase: u16, direction: CounterDirection) {
|
||||
// SAFETY:
|
||||
// We only write to our TIMERx_SYNC register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
|
||||
match TIM {
|
||||
0 => {
|
||||
let sw = block.timer0_sync().read().sw().bit_is_set();
|
||||
block.timer0_sync().write(|w| {
|
||||
w.timer0_phase_direction()
|
||||
.variant(direction as u8 != 0)
|
||||
.timer0_phase()
|
||||
.variant(phase)
|
||||
.sw()
|
||||
.variant(!sw)
|
||||
});
|
||||
let tmr = unsafe { Self::tmr() };
|
||||
let sw = tmr.sync().read().sw().bit_is_set();
|
||||
tmr.sync().write(|w| {
|
||||
w.phase_direction().bit(direction as u8 != 0);
|
||||
unsafe {
|
||||
w.phase().bits(phase);
|
||||
}
|
||||
1 => {
|
||||
let sw = block.timer1_sync().read().sw().bit_is_set();
|
||||
block.timer1_sync().write(|w| {
|
||||
w.timer1_phase_direction()
|
||||
.variant(direction as u8 != 0)
|
||||
.timer1_phase()
|
||||
.variant(phase)
|
||||
.sw()
|
||||
.variant(!sw)
|
||||
});
|
||||
}
|
||||
2 => {
|
||||
let sw = block.timer2_sync().read().sw().bit_is_set();
|
||||
block.timer2_sync().write(|w| {
|
||||
w.timer2_phase_direction()
|
||||
.variant(direction as u8 != 0)
|
||||
.timer2_phase()
|
||||
.variant(phase)
|
||||
.sw()
|
||||
.variant(!sw)
|
||||
});
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
w.sw().bit(!sw)
|
||||
});
|
||||
}
|
||||
|
||||
/// Read the counter value and counter direction of the timer
|
||||
pub fn status(&self) -> (u16, CounterDirection) {
|
||||
// SAFETY:
|
||||
// We only read from our TIMERx_STATUS register
|
||||
let block = unsafe { &*PWM::block() };
|
||||
|
||||
match TIM {
|
||||
0 => {
|
||||
let reg = block.timer0_status().read();
|
||||
(
|
||||
reg.timer0_value().bits(),
|
||||
reg.timer0_direction().bit_is_set().into(),
|
||||
)
|
||||
}
|
||||
1 => {
|
||||
let reg = block.timer1_status().read();
|
||||
(
|
||||
reg.timer1_value().bits(),
|
||||
reg.timer1_direction().bit_is_set().into(),
|
||||
)
|
||||
}
|
||||
2 => {
|
||||
let reg = block.timer2_status().read();
|
||||
(
|
||||
reg.timer2_value().bits(),
|
||||
reg.timer2_direction().bit_is_set().into(),
|
||||
)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
let reg = unsafe { Self::tmr() }.status().read();
|
||||
(reg.value().bits(), reg.direction().bit_is_set().into())
|
||||
}
|
||||
|
||||
fn cfg0(&mut self) -> &TIMER0_CFG0 {
|
||||
fn cfg0(&mut self) -> &crate::peripherals::mcpwm0::timer::CFG0 {
|
||||
// SAFETY:
|
||||
// We only grant access to our CFG0 register with the lifetime of &mut self
|
||||
let block = unsafe { &*PWM::block() };
|
||||
|
||||
// SAFETY:
|
||||
// The CFG0 registers are identical for all timers so we can pretend they're
|
||||
// TIMER0_CFG0
|
||||
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!(),
|
||||
}
|
||||
unsafe { Self::tmr() }.cfg0()
|
||||
}
|
||||
|
||||
fn cfg1(&mut self) -> &TIMER0_CFG1 {
|
||||
fn cfg1(&mut self) -> &crate::peripherals::mcpwm0::timer::CFG1 {
|
||||
// SAFETY:
|
||||
// We only grant access to our CFG1 register with the lifetime of &mut self
|
||||
let block = unsafe { &*PWM::block() };
|
||||
// We only grant access to our CFG0 register with the lifetime of &mut self
|
||||
unsafe { Self::tmr() }.cfg1()
|
||||
}
|
||||
|
||||
// SAFETY:
|
||||
// The CFG1 registers are identical for all timers so we can pretend they're
|
||||
// TIMER0_CFG1
|
||||
match TIM {
|
||||
0 => block.timer0_cfg1(),
|
||||
1 => unsafe { &*(&block.timer1_cfg1() as *const _ as *const _) },
|
||||
2 => unsafe { &*(&block.timer2_cfg1() as *const _ as *const _) },
|
||||
_ => unreachable!(),
|
||||
}
|
||||
unsafe fn tmr() -> &'static crate::peripherals::mcpwm0::TIMER {
|
||||
let block = unsafe { &*PWM::block() };
|
||||
block.timer(TIM as usize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ categories = [
|
||||
cfg-if = "1.0.0"
|
||||
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", optional = true, features = ["unproven"] }
|
||||
embedded-hal-1 = { version = "1.0.0", package = "embedded-hal", optional = true }
|
||||
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "1a96602", features = ["critical-section"], optional = true }
|
||||
esp32c6-lp = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32s2-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
esp32s3-ulp = { git = "https://github.com/esp-rs/esp-pacs", rev = "bc355d6", features = ["critical-section"], optional = true }
|
||||
nb = { version = "1.1.0", optional = true }
|
||||
paste = { version = "1.0.14", optional = true }
|
||||
procmacros = { package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
|
||||
|
Loading…
x
Reference in New Issue
Block a user