impl waveform with TIM Channel
This commit is contained in:
parent
294046cddb
commit
424ddaf3d9
4 changed files with 119 additions and 12 deletions
|
@ -1009,6 +1009,10 @@ fn main() {
|
|||
(("dac", "CH1"), quote!(crate::dac::DacDma1)),
|
||||
(("dac", "CH2"), quote!(crate::dac::DacDma2)),
|
||||
(("timer", "UP"), quote!(crate::timer::UpDma)),
|
||||
(("timer", "CH1"), quote!(crate::timer::Ch1Dma)),
|
||||
(("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
|
||||
(("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
|
||||
(("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
|
||||
]
|
||||
.into();
|
||||
|
||||
|
@ -1024,16 +1028,6 @@ fn main() {
|
|||
}
|
||||
|
||||
if let Some(tr) = signals.get(&(regs.kind, ch.signal)) {
|
||||
// TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state
|
||||
if chip_name.starts_with("stm32f334") && p.name == "TIM6" {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state
|
||||
if chip_name.starts_with("stm32f378") && p.name == "TIM6" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let peri = format_ident!("{}", p.name);
|
||||
|
||||
let channel = if let Some(channel) = &ch.channel {
|
||||
|
|
|
@ -311,6 +311,26 @@ pub(crate) mod sealed {
|
|||
.ccmr_output(channel_index / 2)
|
||||
.modify(|w| w.set_ocpe(channel_index % 2, preload));
|
||||
}
|
||||
|
||||
/// Get capture compare DMA selection
|
||||
fn get_cc_dma_selection(&self) -> super::vals::Ccds {
|
||||
Self::regs_gp16().cr2().read().ccds()
|
||||
}
|
||||
|
||||
/// Set capture compare DMA selection
|
||||
fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) {
|
||||
Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
|
||||
}
|
||||
|
||||
/// Get capture compare DMA enable state
|
||||
fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
|
||||
Self::regs_gp16().dier().read().ccde(channel.index())
|
||||
}
|
||||
|
||||
/// Set capture compare DMA enable state
|
||||
fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) {
|
||||
Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
|
||||
}
|
||||
}
|
||||
|
||||
/// Capture/Compare 16-bit timer instance with complementary pin support.
|
||||
|
@ -705,3 +725,8 @@ foreach_interrupt! {
|
|||
|
||||
// Update Event trigger DMA for every timer
|
||||
dma_trait!(UpDma, Basic16bitInstance);
|
||||
|
||||
dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch3Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch4Dma, CaptureCompare16bitInstance);
|
||||
|
|
|
@ -155,7 +155,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||
///
|
||||
/// Note:
|
||||
/// you will need to provide corresponding TIMx_UP DMA channel to use this method.
|
||||
pub async fn gen_waveform(
|
||||
pub async fn waveform_up(
|
||||
&mut self,
|
||||
dma: impl Peripheral<P = impl super::UpDma<T>>,
|
||||
channel: Channel,
|
||||
|
@ -221,6 +221,94 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_waveform_chx {
|
||||
($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
|
||||
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||
/// Generate a sequence of PWM waveform
|
||||
///
|
||||
/// Note:
|
||||
/// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
|
||||
pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
|
||||
use super::vals::Ccds;
|
||||
|
||||
assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
|
||||
|
||||
into_ref!(dma);
|
||||
|
||||
#[allow(clippy::let_unit_value)] // eg. stm32f334
|
||||
let req = dma.request();
|
||||
|
||||
let cc_channel = super::Channel::$cc_ch;
|
||||
|
||||
let original_duty_state = self.get_duty(cc_channel);
|
||||
let original_enable_state = self.is_enabled(cc_channel);
|
||||
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
|
||||
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
|
||||
|
||||
if original_cc_dma_on_update {
|
||||
self.inner.set_cc_dma_selection(Ccds::ONUPDATE)
|
||||
}
|
||||
|
||||
if !original_cc_dma_enabled {
|
||||
self.inner.set_cc_dma_enable_state(cc_channel, true);
|
||||
}
|
||||
|
||||
if !original_enable_state {
|
||||
self.enable(cc_channel);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
use crate::dma::{Burst, FifoThreshold};
|
||||
use crate::dma::{Transfer, TransferOptions};
|
||||
|
||||
let dma_transfer_option = TransferOptions {
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
fifo_threshold: Some(FifoThreshold::Full),
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
mburst: Burst::Incr8,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Transfer::new_write(
|
||||
&mut dma,
|
||||
req,
|
||||
duty,
|
||||
T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
|
||||
dma_transfer_option,
|
||||
)
|
||||
.await
|
||||
};
|
||||
|
||||
// restore output compare state
|
||||
if !original_enable_state {
|
||||
self.disable(cc_channel);
|
||||
}
|
||||
|
||||
self.set_duty(cc_channel, original_duty_state);
|
||||
|
||||
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
|
||||
// this can almost always trigger a DMA FIFO error.
|
||||
//
|
||||
// optional TODO:
|
||||
// clean FEIF after disable UDE
|
||||
if !original_cc_dma_enabled {
|
||||
self.inner.set_cc_dma_enable_state(cc_channel, false);
|
||||
}
|
||||
|
||||
if !original_cc_dma_on_update {
|
||||
self.inner.set_cc_dma_selection(Ccds::ONCOMPARE)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
|
||||
impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
|
||||
impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
|
||||
impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
|
||||
|
||||
impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
|
||||
type Channel = Channel;
|
||||
type Time = Hertz;
|
||||
|
|
|
@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) {
|
|||
loop {
|
||||
for &color in color_list {
|
||||
// with &mut, we can easily reuse same DMA channel multiple times
|
||||
ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await;
|
||||
ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await;
|
||||
// ws2812 need at least 50 us low level input to confirm the input data and change it's state
|
||||
Timer::after_micros(50).await;
|
||||
// wait until ticker tick
|
||||
|
|
Loading…
Add table
Reference in a new issue