record&restore TIM OC to it's earlier state
This commit is contained in:
parent
8c2a6df03b
commit
24f569821c
2 changed files with 60 additions and 15 deletions
embassy-stm32/src/timer
|
@ -99,6 +99,11 @@ pub(crate) mod sealed {
|
||||||
Self::regs().dier().modify(|r| r.set_ude(enable));
|
Self::regs().dier().modify(|r| r.set_ude(enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the update dma enable/disable state.
|
||||||
|
fn get_update_dma_state(&self) -> bool {
|
||||||
|
Self::regs().dier().read().ude()
|
||||||
|
}
|
||||||
|
|
||||||
/// Enable/disable autoreload preload.
|
/// Enable/disable autoreload preload.
|
||||||
fn set_autoreload_preload(&mut self, enable: bool) {
|
fn set_autoreload_preload(&mut self, enable: bool) {
|
||||||
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
Self::regs().cr1().modify(|r| r.set_arpe(enable));
|
||||||
|
@ -274,6 +279,11 @@ pub(crate) mod sealed {
|
||||||
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
|
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get enable/disable state of a channel
|
||||||
|
fn get_channel_enable_state(&self, channel: Channel) -> bool {
|
||||||
|
Self::regs_gp16().ccer().read().cce(channel.index())
|
||||||
|
}
|
||||||
|
|
||||||
/// Set compare value for a channel.
|
/// Set compare value for a channel.
|
||||||
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
fn set_compare_value(&mut self, channel: Channel, value: u16) {
|
||||||
Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
|
Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
|
||||||
|
|
|
@ -62,6 +62,12 @@ pub struct SimplePwm<'d, T, Dma> {
|
||||||
|
|
||||||
impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
|
impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
|
||||||
/// Create a new simple PWM driver.
|
/// Create a new simple PWM driver.
|
||||||
|
///
|
||||||
|
/// Note:
|
||||||
|
/// If you want to use [`Self::gen_waveform()`], you need to provide corresponding TIMx_UP DMA channel.
|
||||||
|
/// Otherwise you can just put a [`dma::NoDma`](crate::dma::NoDma)
|
||||||
|
/// Currently, you can only use one channel at a time to generate waveform with [`Self::gen_waveform()`].
|
||||||
|
/// But you can always use multiple TIM to generate multiple waveform simultaneously.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
tim: impl Peripheral<P = T> + 'd,
|
tim: impl Peripheral<P = T> + 'd,
|
||||||
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
||||||
|
@ -113,6 +119,11 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
|
||||||
self.inner.enable_channel(channel, false);
|
self.inner.enable_channel(channel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether given channel is enabled
|
||||||
|
pub fn is_enabled(&self, channel: Channel) -> bool {
|
||||||
|
self.inner.get_channel_enable_state(channel)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set PWM frequency.
|
/// Set PWM frequency.
|
||||||
///
|
///
|
||||||
/// Note: when you call this, the max duty value changes, so you will have to
|
/// Note: when you call this, the max duty value changes, so you will have to
|
||||||
|
@ -141,6 +152,13 @@ impl<'d, T: CaptureCompare16bitInstance, Dma> SimplePwm<'d, T, Dma> {
|
||||||
self.inner.set_compare_value(channel, duty)
|
self.inner.set_compare_value(channel, duty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the duty for a given channel.
|
||||||
|
///
|
||||||
|
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
|
||||||
|
pub fn get_duty(&self, channel: Channel) -> u16 {
|
||||||
|
self.inner.get_compare_value(channel)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the output polarity for a given channel.
|
/// Set the output polarity for a given channel.
|
||||||
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
|
||||||
self.inner.set_output_polarity(channel, polarity);
|
self.inner.set_output_polarity(channel, polarity);
|
||||||
|
@ -153,26 +171,38 @@ where
|
||||||
{
|
{
|
||||||
/// Generate a sequence of PWM waveform
|
/// Generate a sequence of PWM waveform
|
||||||
pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) {
|
pub async fn gen_waveform(&mut self, channel: Channel, duty: &[u16]) {
|
||||||
duty.iter().all(|v| v.le(&self.get_max_duty()));
|
assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
|
||||||
|
|
||||||
self.inner.enable_update_dma(true);
|
|
||||||
|
|
||||||
#[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))]
|
#[cfg_attr(any(stm32f334, stm32f378), allow(clippy::let_unit_value))]
|
||||||
let req = self.dma.request();
|
let req = self.dma.request();
|
||||||
|
|
||||||
self.enable(channel);
|
|
||||||
|
|
||||||
#[cfg(not(any(bdma, gpdma)))]
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
let dma_regs = self.dma.regs();
|
let dma_regs = self.dma.regs();
|
||||||
#[cfg(not(any(bdma, gpdma)))]
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
let isr_num = self.dma.num() / 4;
|
let isr_num = self.dma.num() / 4;
|
||||||
#[cfg(not(any(bdma, gpdma)))]
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
let isr_bit = self.dma.num() % 4;
|
let isr_bit = self.dma.num() % 4;
|
||||||
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
let isr_reg = dma_regs.isr(isr_num);
|
||||||
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
let ifcr_reg = dma_regs.ifcr(isr_num);
|
||||||
|
|
||||||
#[cfg(not(any(bdma, gpdma)))]
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
// clean DMA FIFO error before a transfer
|
// clean DMA FIFO error before a transfer
|
||||||
if dma_regs.isr(isr_num).read().feif(isr_bit) {
|
if isr_reg.read().feif(isr_bit) {
|
||||||
dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true));
|
ifcr_reg.write(|v| v.set_feif(isr_bit, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
let original_duty_state = self.get_duty(channel);
|
||||||
|
let original_enable_state = self.is_enabled(channel);
|
||||||
|
let original_update_dma_state = self.inner.get_update_dma_state();
|
||||||
|
|
||||||
|
if !original_update_dma_state {
|
||||||
|
self.inner.enable_update_dma(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !original_enable_state {
|
||||||
|
self.enable(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -198,15 +228,20 @@ where
|
||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
||||||
self.disable(channel);
|
// restore output compare state
|
||||||
|
if !original_enable_state {
|
||||||
|
self.disable(channel);
|
||||||
|
}
|
||||||
|
self.set_duty(channel, original_duty_state);
|
||||||
|
if !original_update_dma_state {
|
||||||
|
self.inner.enable_update_dma(false);
|
||||||
|
|
||||||
self.inner.enable_update_dma(false);
|
#[cfg(not(any(bdma, gpdma)))]
|
||||||
|
// Since DMA could be closed before timer update event trigger DMA is turn off, this can almost always trigger a DMA FIFO error.
|
||||||
#[cfg(not(any(bdma, gpdma)))]
|
// Thus, we will try clean DMA FEIF after each transfer
|
||||||
// Since DMA is closed before timer update event trigger DMA is turn off, it will almost always trigger a DMA FIFO error.
|
if isr_reg.read().feif(isr_bit) {
|
||||||
// Thus, we will always clean DMA FEIF after each transfer
|
ifcr_reg.write(|v| v.set_feif(isr_bit, true));
|
||||||
if dma_regs.isr(isr_num).read().feif(isr_bit) {
|
}
|
||||||
dma_regs.ifcr(isr_num).write(|v| v.set_feif(isr_bit, true));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue