From 6ff7b039f52af582a6859315ff087c3197e50eba Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 9 Dec 2023 14:39:20 +0100 Subject: [PATCH] Switched to rtic Changed pin assigments to make USB usable --- Cargo.toml | 60 ++++----- src/main.rs | 355 +++++++++++++++++++++++++++++----------------------- 2 files changed, 216 insertions(+), 199 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7700bac..39a5e52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,28 +6,18 @@ edition = "2018" version = "0.1.0" [dependencies] -cortex-m = "~0.7.1" -cortex-m-rt = "~0.6.13" -defmt = "~0.2.0" -defmt-rtt = "~0.2.0" -panic-probe = { version = "~0.2.0", features = ["print-defmt"] } -stm32f1xx-hal = { version = "~0.6.1", features = ["stm32f103", "rt"] } -embedded-hal = {version = "~0.2.3"} - -[features] -# set logging levels here -default = [ - "defmt-default", - # "dependency-a/defmt-trace", -] - -# do NOT modify these features -defmt-default = [] -defmt-trace = [] -defmt-debug = [] -defmt-info = [] -defmt-warn = [] -defmt-error = [] +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +defmt = { version = "0.3", features = ["encoding-rzcobs"] } +defmt-brtt = { version = "0.1", default-features = false, features = ["rtt"] } +panic-probe = { version = "0.3", features = ["print-defmt"] } +rtic = { version = "2.0.1", features = [ "thumbv7-backend" ] } +defmt-rtt = "0.4" +embedded-hal = {version = "0.2.3"} +stm32f1xx-hal = { version = "0.10.0", features = ["stm32f103", "rt", "medium"] } +nb = "1.0.0" +arrayvec = {version = "0.7.0", default-features = false} +systick-monotonic = "1.0.0" +rtic-monotonics = {version = "1.4.1", features = ["cortex-m-systick"] } # cargo build/run [profile.dev] @@ -35,8 +25,8 @@ codegen-units = 1 debug = 2 debug-assertions = true # <- incremental = false -opt-level = 3 # <- -overflow-checks = true # <- +opt-level = 'z' # <- +overflow-checks = true # <- # cargo test [profile.test] @@ -44,8 +34,8 @@ codegen-units = 1 debug = 2 debug-assertions = true # <- incremental = false -opt-level = 3 # <- -overflow-checks = true # <- +opt-level = 3 # <- +overflow-checks = true # <- # cargo build/run --release [profile.release] @@ -53,9 +43,9 @@ codegen-units = 1 debug = 2 debug-assertions = false # <- incremental = false -#lto = 'fat' -opt-level = 3 # <- -overflow-checks = false # <- +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- # cargo test --release [profile.bench] @@ -64,13 +54,5 @@ debug = 2 debug-assertions = false # <- incremental = false lto = 'fat' -opt-level = 3 # <- -overflow-checks = false # <- - -# uncomment this to switch from the crates.io version of defmt to its git version -# check app-template's README for instructions -# [patch.crates-io] -# defmt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" } -# defmt-rtt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" } -# defmt-test = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" } -# panic-probe = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" } +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/src/main.rs b/src/main.rs index 722c33b..f02ebe0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,11 @@ -#![deny(unsafe_code)] #![no_std] #![no_main] +#![feature(type_alias_impl_trait)] use defmt_rtt as _; // global logger use panic_probe as _; use stm32f1xx_hal as _; -use core::sync::atomic::{AtomicU32, Ordering}; - -use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; -use stm32f1xx_hal::{ - delay::Delay, - pac, - pac::TIM1, - pac::TIM2, - prelude::*, - rcc::Enable, - rcc::Reset, - timer::{Tim3NoRemap, Timer}, -}; - // same panicking *behavior* as `panic-probe` but doesn't print a panic message // this prevents the panic message being printed *twice* when `defmt::panic` is invoked #[defmt::panic_handler] @@ -28,175 +13,225 @@ fn panic() -> ! { cortex_m::asm::udf() } -static COUNT: AtomicU32 = AtomicU32::new(0); -defmt::timestamp!("{=u32}", COUNT.fetch_add(1, Ordering::Relaxed)); +use rtic::app; -/// Terminates the application and makes `probe-run` exit with exit-code = 0 -pub fn exit() -> ! { - loop { - cortex_m::asm::bkpt(); +#[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [SPI3])] +mod app { + + use rtic_monotonics::systick::*; + + use embedded_hal::digital::v2::OutputPin; + use stm32f1xx_hal::{ + gpio::{self, gpioa, gpioc, Alternate, Output, PushPull}, + pac, + pac::{RCC, TIM2, TIM3, TIM4}, + prelude::*, + rcc::Enable, + rcc::Reset, + timer::{self, Channel, PwmHz, Tim4NoRemap}, + }; + + #[local] + struct Local { + board_led: gpioc::PC13>, + tim2: TIM2, + tim3: TIM3, + pwm: PwmHz, gpio::Pin<'B', 6, Alternate>>, } -} -const target_freq: f64 = 10.0f64; + #[shared] + struct Shared {} -#[entry] -fn main() -> ! { - // Get access to the core peripherals from the cortex-m crate - let cp = cortex_m::Peripherals::take().unwrap(); - // Get access to the device specific peripherals from the peripheral access crate - let dp = pac::Peripherals::take().unwrap(); + const target_freq: f64 = 10.0f64; - // Take ownership over the raw flash and rcc devices and convert them into the corresponding - // HAL structs - let mut flash = dp.FLASH.constrain(); - let mut rcc = dp.RCC.constrain(); + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + let mut rcc = cx.device.RCC.constrain(); + let mut flash = cx.device.FLASH.constrain(); - let clocks = rcc - .cfgr - .use_hse(8.mhz()) - .sysclk(48.mhz()) - .pclk1(24.mhz()) - .freeze(&mut flash.acr); + let clocks = rcc + .cfgr + .use_hse(8.MHz()) + .sysclk(48.MHz()) + .pclk1(24.MHz()) + .freeze(&mut flash.acr); - // Freeze the configuration of all the clocks in the system and store the frozen frequencies in - // `clocks` - //let clocks = rcc.cfgr.freeze(&mut flash.acr); + defmt::info!("Clock Setup done"); - // Acquire the GPIOC peripheral - let mut gpioc = dp.GPIOC.split(&mut rcc.apb2); + // Initialize the systick interrupt & obtain the token to prove that we did + let systick_mono_token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, clocks.sysclk().to_Hz(), systick_mono_token); - // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function - // in order to configure the port. For pins 0-7, crl should be passed instead. - let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); + let mut gpioc = cx.device.GPIOC.split(); - let mut afio = dp.AFIO.constrain(&mut rcc.apb2); - let mut gpioa = dp.GPIOA.split(&mut rcc.apb2); - let pwm_pin = gpioa.pa6.into_alternate_push_pull(&mut gpioa.crl); - let mut pwm = Timer::tim3(dp.TIM3, &clocks, &mut rcc.apb1) - .pwm::(pwm_pin, &mut afio.mapr, 10.khz()) - .split(); + // Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function + // in order to configure the port. For pins 0-7, crl should be passed instead. + let board_led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); - pwm.enable(); + let mut afio = cx.device.AFIO.constrain(); + let mut gpiob = cx.device.GPIOB.split(); + let pwm_pin = gpiob.pb6.into_alternate_push_pull(&mut gpiob.crl); + let mut pwm = + cx.device + .TIM4 + .pwm_hz::(pwm_pin, &mut afio.mapr, 32.kHz(), &clocks); + pwm.enable(Channel::C1); - // Setup timers - let tim1 = dp.TIM1; + defmt::info!("PWM Setup done"); - TIM1::enable(&mut rcc.apb2); - TIM1::reset(&mut rcc.apb2); - // Enable external clocking - tim1.smcr.write(|w| { - w.etf().no_filter(); // No filter for to 10Mhz clock - w.etps().div1(); // No divider - w.etp().not_inverted(); // on rising edege at ETR pin - w.ece().enabled() // mode 2 (use ETR pin) - }); - - tim1.ccmr1_input().write(|w| { - w.cc1s().ti1(); // Input capture using T1 input - w.ic1f().no_filter() // No filter on input capture input - - //w.ic1psc().bits(0) // Disable prescaler, not safely implement by HAL yet - }); - - tim1.ccer.write(|w| { - w.cc1p().set_bit(); // Use rising edge on TI - w.cc1e().set_bit() // Enable input capture - }); - - tim1.cr2.write(|w| { - w.mms().update() // Trigger output on update/overflow - }); - - // Counting up to 10^7 should need 24 bits - // Clock tim2 by tim1s overflow to make a 32bit timer - - let tim2 = dp.TIM2; - - TIM2::enable(&mut rcc.apb1); - TIM2::reset(&mut rcc.apb1); - - tim2.smcr.write(|w| { - w.ts().itr0(); // Trigger from internal trigger 0 - w.sms().ext_clock_mode() // Use trigger as clock - }); - - tim2.ccmr1_input().write(|w| { - w.cc1s().ti1(); // Input capture using T1 input - w.ic1f().no_filter() // No filter on input capture input - - //w.ic1psc().bits(0) // Disable prescaler, not safely implement by HAL yet - }); - - tim2.ccer.write(|w| { - w.cc1p().set_bit(); // Use rising edge on TI - w.cc1e().set_bit() // Enable input capture - }); - - tim1.cr1.write(|w| w.cen().enabled()); - tim2.cr1.write(|w| w.cen().enabled()); - - let mut delay = Delay::new(cp.SYST, clocks); - - let mut last_ic = 0u32; - let mut avg = 10f64; - let max_pwm = pwm.get_max_duty() as u32; - let mut cur_pwm = 3000u32; //max_pwm / 2; - - // Skip the first measurement, it will be garbage - while !tim1.sr.read().cc1if().bit_is_set() || !tim2.sr.read().cc1if().bit_is_set() { - delay.delay_ms(10u16); - } - let ic1 = tim1.ccr1.read().bits(); - let ic2 = tim2.ccr1.read().bits(); - - last_ic = ic2 << 16 | ic1; - - loop { - while !tim1.sr.read().cc1if().bit_is_set() || !tim2.sr.read().cc1if().bit_is_set() { - delay.delay_ms(10u16); + let tim2 = cx.device.TIM2; + unsafe { + let rcc = &*RCC::ptr(); + TIM2::enable(rcc); + TIM2::reset(rcc); } - let ic1 = tim1.ccr1.read().bits(); - let ic2 = tim2.ccr1.read().bits(); + // Enable external clocking + tim2.smcr.write(|w| { + w.etf().no_filter(); // No filter for to 10Mhz clock + w.etps().div1(); // No divider + w.etp().not_inverted(); // on rising edege at ETR pin + w.ece().enabled() // mode 2 (use ETR pin) + }); - let sum_ic = ic2 << 16 | ic1; + tim2.ccmr1_input().write(|w| { + w.cc1s().ti2(); // Input capture using TI2 input + w.ic1f().no_filter() // No filter on input capture input + //w.ic1psc().bits(0) // Disable prescaler, not safely implement by HAL yet + }); - let diff_ic = if sum_ic > last_ic { - sum_ic - last_ic - } else { - u32::MAX - last_ic + sum_ic - }; + tim2.ccer.write(|w| { + w.cc1p().set_bit(); // Use rising edge on TI + w.cc1e().set_bit() // Enable input capture + }); - last_ic = sum_ic; + tim2.cr2.write(|w| { + w.mms().update() // Trigger output on update/overflow + }); - let freq = (diff_ic as f64) / 1_000_000f64; - let diff = freq - avg; + tim2.ccer.write(|w| { + w.cc1p().set_bit(); // Use rising edge on TI + w.cc1e().set_bit() // Enable input capture + }); - led.toggle().unwrap(); + tim2.cr2.write(|w| { + w.mms().update() // Trigger output on update/overflow + }); - if diff > 0.000_100 || diff < -0.000_100 { - continue; + // Counting up to 10^7 should need 24 bits + // Clock tim2 by tim1s overflow to make a 32bit timer + let tim3 = cx.device.TIM3; + unsafe { + let rcc = &*RCC::ptr(); + TIM3::enable(rcc); + TIM3::reset(rcc); } - avg = avg * 0.999 + freq * 0.001; + tim3.smcr.write(|w| { + w.ts().itr1(); // Trigger from internal trigger 1 + w.sms().ext_clock_mode() // Use trigger as clock + }); - cur_pwm = if 10_000_000 >= diff_ic { - cur_pwm + (10_000_000 - diff_ic) - } else { - cur_pwm - (diff_ic - 10_000_000) - }; - cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm }; + tim3.ccmr1_input().write(|w| { + w.cc1s().ti1(); // Input capture using TI1 input + w.ic1f().no_filter() // No filter on input capture input + //w.ic1psc().bits(0) // Disable prescaler, not safely implement by HAL yet + }); - pwm.set_duty(cur_pwm as u16); + tim3.ccer.write(|w| { + w.cc1p().set_bit(); // Use rising edge on TI + w.cc1e().set_bit() // Enable input capture + }); - defmt::info!("ic1:\t{}", ic1); - defmt::info!("ic2:\t{}", ic2); - defmt::info!("sum_ic:\t{}", sum_ic); - defmt::info!("diff_ic:\t{}", diff_ic); - defmt::info!("freq:\t{} MHz", freq); - defmt::info!("avg:\t{} MHz", avg); - defmt::info!("pwm:\t{}", cur_pwm); + tim2.cr1.write(|w| w.cen().enabled()); + tim3.cr1.write(|w| w.cen().enabled()); + + defmt::info!("Timer Setup done"); + + update_pwm::spawn().unwrap(); + + ( + Shared {}, + Local { + board_led, + tim2, + tim3, + pwm, + }, + ) } -} + + #[task(local=[tim2, tim3, pwm, board_led])] + async fn update_pwm(cx: update_pwm::Context) { + defmt::info!("Update Task started"); + + let tim2 = cx.local.tim2; + let tim3 = cx.local.tim3; + let pwm = cx.local.pwm; + let board_led = cx.local.board_led; + + let mut last_ic = 0u32; + let mut avg = 10f64; + let max_pwm = pwm.get_max_duty() as u32; + let mut cur_pwm = 3000u32; //max_pwm / 2; + + // Inialize last_ic + while !tim2.sr.read().cc1if().bit_is_set() || !tim3.sr.read().cc1if().bit_is_set() { + Systick::delay(10.millis()).await; + } + let ic1 = tim2.ccr1().read().bits(); + let ic2 = tim3.ccr1().read().bits(); + + last_ic = ic2 << 16 | ic1; + + loop { + while !tim3.sr.read().cc1if().bit_is_set() || !tim3.sr.read().cc1if().bit_is_set() { + Systick::delay(10.millis()).await; + } + + let ic1 = tim2.ccr1().read().bits(); + let ic2 = tim3.ccr1().read().bits(); + + let sum_ic = ic2 << 16 | ic1; + + let diff_ic = if sum_ic > last_ic { + sum_ic - last_ic + } else { + u32::MAX - last_ic + sum_ic + }; + + last_ic = sum_ic; + + let freq = (diff_ic as f64) / 1_000_000f64; + let diff = freq - avg; + + board_led.toggle(); + + if diff > 0.000_100 || diff < -0.000_100 { + continue; + } + + avg = avg * 0.999 + freq * 0.001; + + cur_pwm = if 10_000_000 >= diff_ic { + cur_pwm + (10_000_000 - diff_ic) + } else { + cur_pwm - (diff_ic - 10_000_000) + }; + cur_pwm = if cur_pwm > max_pwm { max_pwm } else { cur_pwm }; + + pwm.set_duty(Channel::C1, cur_pwm as u16); + + defmt::info!("ic1:\t{}", ic1); + defmt::info!("ic2:\t{}", ic2); + defmt::info!("sum_ic:\t{}", sum_ic); + defmt::info!("diff_ic:\t{}", diff_ic); + defmt::info!("freq:\t{} MHz", freq); + defmt::info!("avg:\t{} MHz", avg); + defmt::info!("pwm:\t{}", cur_pwm); + + Systick::delay(500.millis()).await; + } + } +} \ No newline at end of file