From df9f7420db9f446c034ebf0baab286cc594b92a8 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Sat, 23 Jan 2021 16:24:35 +0100
Subject: [PATCH] ok pwm solotions for now
---
examples/rtt-pwm-sine-task.rs | 17 +--
examples/rtt-pwm-sine-timer-task.rs | 185 ++++++++++++++++++++++++++++
examples/rtt-pwm-sine.rs | 38 +++---
3 files changed, 208 insertions(+), 32 deletions(-)
create mode 100644 examples/rtt-pwm-sine-timer-task.rs
diff --git a/examples/rtt-pwm-sine-task.rs b/examples/rtt-pwm-sine-task.rs
index bb7dd6a..e4d754c 100644
--- a/examples/rtt-pwm-sine-task.rs
+++ b/examples/rtt-pwm-sine-task.rs
@@ -134,19 +134,6 @@ const APP: () = {
rprintln!("here");
tim1.sr.modify(|_, w| w.uif().clear());
- // loop {
- // for i in 0..SINE_BUF_SIZE {
- // // wait until next update event
-
- // while tim1.sr.read().uif().is_clear() {}
- // tim1.sr.modify(|_, w| w.uif().clear());
-
- // tim1.ccr1
- // .write(|w| unsafe { w.ccr().bits(SINE_BUF[i] as u16) });
- // tim1.ccr2
- // .write(|w| unsafe { w.ccr().bits(SINE_BUF[i] as u16) });
- // }
- // }
// pass on late resources
cx.schedule.pwmout(cx.start + PERIOD.cycles()).ok();
init::LateResources { TIM1: tim1 }
@@ -172,7 +159,7 @@ const APP: () = {
tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
- *INDEX = (*INDEX).wrapping_add(25oo);
+ *INDEX = (*INDEX).wrapping_add(25);
cx.schedule.pwmout(cx.scheduled + PERIOD.cycles()).ok();
*LEFT = SINE_BUF[*INDEX as usize] as u16;
@@ -190,4 +177,4 @@ const APP: () = {
// We aim for a sampling rate of 48kHz, assuming that the input filter of the
// sound card used to sample the generated signal has an appropriate input filter
-const PERIOD: u32 = 1000; // 48_000_000 / 48_000;
+const PERIOD: u32 = 2000; // 96_000_000 / 48_000;
diff --git a/examples/rtt-pwm-sine-timer-task.rs b/examples/rtt-pwm-sine-timer-task.rs
new file mode 100644
index 0000000..23b604a
--- /dev/null
+++ b/examples/rtt-pwm-sine-timer-task.rs
@@ -0,0 +1,185 @@
+//! cargo run --examples rtt-pwm-sine-timer-task --release
+
+// #![deny(unsafe_code)]
+// #![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use cortex_m::{asm, peripheral::DWT};
+use panic_rtt_target as _;
+use rtic::cyccnt::{Instant, U32Ext as _};
+use rtt_target::{rprint, rprintln, rtt_init_print};
+
+use stm32f4xx_hal::{
+ gpio::Speed,
+ prelude::*,
+ pwm, stm32,
+ timer::{Event, Timer},
+};
+
+include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs"));
+
+type Timer2 = Timer<stm32::TIM2>;
+
+#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
+const APP: () = {
+ struct Resources {
+ // late resources
+ TIM1: stm32::TIM1,
+ timer2: Timer2,
+ }
+ #[init(schedule = [])]
+ fn init(mut cx: init::Context) -> init::LateResources {
+ rtt_init_print!();
+ rprintln!("init");
+ let dp = cx.device;
+
+ // Initialize (enable) the monotonic timer (CYCCNT)
+ cx.core.DCB.enable_trace();
+ cx.core.DWT.enable_cycle_counter();
+
+ let rcc = dp.RCC.constrain();
+ // Set up the system clock. 48 MHz?
+ let clocks = rcc
+ .cfgr
+ // .use_hse(8.mhz())
+ // .sysclk(48.mhz())
+ .sysclk(96.mhz())
+ .pclk1(24.mhz())
+ .freeze();
+
+ let gpioa = dp.GPIOA.split();
+ // we set the pins to VeryHigh to get the sharpest waveform possible
+ // (rise and fall times should have similar characteristics)
+ let channels = (
+ gpioa.pa8.into_alternate_af1().set_speed(Speed::VeryHigh),
+ gpioa.pa9.into_alternate_af1().set_speed(Speed::VeryHigh),
+ );
+
+ // Setup PWM RAW
+ let tim1 = dp.TIM1;
+ // Here we need unsafe as we are "stealing" the RCC peripheral
+ // At this point it has been contrained into SysConf and used to set clocks
+ let rcc = unsafe { &(*stm32::RCC::ptr()) };
+
+ rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
+ rcc.apb2rstr.modify(|_, w| w.tim1rst().set_bit());
+ rcc.apb2rstr.modify(|_, w| w.tim1rst().clear_bit());
+
+ // Setup chanel 1 and 2 as pwm_mode1
+ tim1.ccmr1_output()
+ .modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1());
+
+ tim1.ccmr1_output()
+ .modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1());
+
+ // The reference manual is a bit ambiguous about when enabling this bit is really
+ // necessary, but since we MUST enable the preload for the output channels then we
+ // might as well enable for the auto-reload too
+ tim1.cr1.modify(|_, w| w.arpe().set_bit());
+
+ let clk = clocks.pclk2().0 * if clocks.ppre2() == 1 { 1 } else { 2 };
+ // check that its actually 48_000_000
+ rprintln!("clk {}", clk);
+
+ // we want maximum performance, thus we set the prescaler to 0
+ let pre = 0;
+ rprintln!("pre {}", pre);
+ tim1.psc.write(|w| w.psc().bits(pre));
+
+ // we want 8 bits of resolution
+ // so our ARR = 2^8 - 1 = 256 - 1 = 255
+ let arr = 255;
+ rprintln!("arr {}", arr);
+ tim1.arr.write(|w| unsafe { w.bits(arr) });
+
+ // Trigger update event to load the registers
+ tim1.cr1.modify(|_, w| w.urs().set_bit());
+ tim1.egr.write(|w| w.ug().set_bit());
+ tim1.cr1.modify(|_, w| w.urs().clear_bit());
+
+ // Set main output enable of all Output Compare (OC) registers
+ tim1.bdtr.modify(|_, w| w.moe().set_bit());
+
+ // Set output enable for channels 1 and 2
+ tim1.ccer.write(|w| w.cc1e().set_bit().cc2e().set_bit());
+
+ // Setup the timer
+ tim1.cr1.write(|w| {
+ w.cms()
+ .bits(0b00) // edge aligned mode
+ .dir() // counter used as upcounter
+ .clear_bit()
+ .opm() // one pulse mode
+ .clear_bit()
+ .cen() // enable counter
+ .set_bit()
+ });
+
+ // Set main output enable of all Output Compare (OC) registers
+ tim1.bdtr.modify(|_, w| w.moe().set_bit());
+
+ // Set duty cycle of Channels
+ tim1.ccr1.write(|w| unsafe { w.ccr().bits(128) });
+ tim1.ccr2.write(|w| unsafe { w.ccr().bits(128) });
+
+ // Set preload for the CCx
+ tim1.cr2.write(|w| w.ccpc().set_bit());
+
+ // Enable update events
+ tim1.dier.write(|w| w.uie().enabled());
+ tim1.sr.modify(|_, w| w.uif().clear());
+
+ // Set divider to 4, (48_000_000/256)/4
+ // tim1.rcr.modify(|_, w| unsafe { w.rep().bits(4) });
+
+ while tim1.sr.read().uif().is_clear() {
+ rprint!("-");
+ }
+ rprintln!("here");
+ tim1.sr.modify(|_, w| w.uif().clear());
+
+ let mut tim2: Timer<stm32::TIM2> = Timer::tim2(dp.TIM2, 48000, clocks);
+ tim2.listen(Event::TimeOut);
+ init::LateResources {
+ TIM1: tim1,
+ timer2: tim2,
+ }
+ }
+
+ #[idle]
+ fn idle(_cx: idle::Context) -> ! {
+ rprintln!("idle");
+ // panic!("panic");
+ loop {
+ rprintln!("-");
+ continue;
+ }
+ }
+
+ #[task(binds = TIM2, resources = [TIM1, timer2])]
+ fn tim2(cx: tim2::Context) {
+ static mut INDEX: u8 = 0;
+ static mut LEFT: u16 = 0;
+ static mut RIGHT: u16 = 0;
+ cx.resources.timer2.clear_interrupt(Event::TimeOut);
+
+ let tim1 = cx.resources.TIM1;
+
+ tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
+ tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
+
+ *INDEX = (*INDEX).wrapping_add(25);
+
+ *LEFT = SINE_BUF[*INDEX as usize] as u16;
+ *RIGHT = SINE_BUF[*INDEX as usize] as u16;
+ }
+
+ extern "C" {
+ fn EXTI0();
+ }
+};
+
+// We aim for a sampling rate of 48kHz, assuming that the input filter of the
+// sound card used to sample the generated signal has an appropriate input filter
+const PERIOD: u32 = 1000; // 48_000_000 / 48_000;
diff --git a/examples/rtt-pwm-sine.rs b/examples/rtt-pwm-sine.rs
index 80c4e3d..726f5cb 100644
--- a/examples/rtt-pwm-sine.rs
+++ b/examples/rtt-pwm-sine.rs
@@ -104,7 +104,6 @@ const APP: () = {
.set_bit()
});
-
// Set main output enable of all Output Compare (OC) registers
tim1.bdtr.modify(|_, w| w.moe().set_bit());
@@ -115,6 +114,7 @@ const APP: () = {
// Set preload for the CCx
tim1.cr2.write(|w| w.ccpc().set_bit());
+ // Enable update events
tim1.dier.write(|w| w.uie().enabled());
tim1.sr.modify(|_, w| w.uif().clear());
@@ -142,22 +142,26 @@ const APP: () = {
}
}
- // [task(resources = [GPIOA], schedule = [toggle])]
- // fn toggle(cx: toggle::Context) {
- // static mut TOGGLE: bool = false;
- // hprintln!("foo @ {:?}", Instant::now()).unwrap();
-
- // if *TOGGLE {
- // cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
- // } else {
- // cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
- // }
-
- // *TOGGLE = !*TOGGLE;
- // cx.schedule
- // .toggle(cx.scheduled + 8_000_000.cycles())
- // .unwrap();
- // }
+ #[task(resources = [GPIOA], schedule = [toggle])]
+ fn toggle(cx: toggle::Context) {
+ static mut TOGGLE: bool = false;
+ hprintln!("foo @ {:?}", Instant::now()).unwrap();
+
+ if *TOGGLE {
+ cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
+ } else {
+ cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
+ }
+
+ *TOGGLE = !*TOGGLE;
+ cx.schedule
+ .toggle(cx.scheduled + 8_000_000.cycles())
+ .unwrap();
+ }
+
+ extern "C" {
+ fn EXTI0();
+ }
#[idle]
fn idle(_cx: idle::Context) -> ! {
--
GitLab