From ad66dc3aabe6ac11dd0f3aa4d9f403e3aac7e8f4 Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Sun, 5 May 2024 21:58:54 -0400 Subject: [PATCH 1/7] create input_capture --- embassy-stm32/src/timer/input_capture.rs | 141 ++++++++++++++++++++++ embassy-stm32/src/timer/mod.rs | 1 + examples/stm32f4/.cargo/config.toml | 12 +- examples/stm32f4/.vscode/README.md | 109 +++++++++++++++++ examples/stm32f4/.vscode/extensions.json | 17 +++ examples/stm32f4/.vscode/launch.json | 33 +++++ examples/stm32f4/.vscode/tasks.json | 43 +++++++ examples/stm32f4/openocd.cfg | 5 + examples/stm32f4/openocd.gdb | 40 ++++++ examples/stm32f4/src/bin/input_capture.rs | 39 ++++++ 10 files changed, 438 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/timer/input_capture.rs create mode 100644 examples/stm32f4/.vscode/README.md create mode 100644 examples/stm32f4/.vscode/extensions.json create mode 100644 examples/stm32f4/.vscode/launch.json create mode 100644 examples/stm32f4/.vscode/tasks.json create mode 100644 examples/stm32f4/openocd.cfg create mode 100644 examples/stm32f4/openocd.gdb create mode 100644 examples/stm32f4/src/bin/input_capture.rs diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs new file mode 100644 index 000000000..6401656c8 --- /dev/null +++ b/embassy-stm32/src/timer/input_capture.rs @@ -0,0 +1,141 @@ +//! Input capture driver. + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::channel; + +use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; +use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; +use crate::gpio::{AFType, AnyPin, Pull}; +use crate::time::Hertz; +use crate::Peripheral; + +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} +/// Channel 3 marker type. +pub enum Ch3 {} +/// Channel 4 marker type. +pub enum Ch4 {} + +/// Capture pin wrapper. +/// +/// This wraps a pin to make it usable with capture. +pub struct CapturePin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd, pull_type: Pull) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + CapturePin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); +channel_impl!(new_ch3, Ch3, Channel3Pin); +channel_impl!(new_ch4, Ch4, Channel4Pin); + +/// Input capture driver. +pub struct InputCapture<'d, T: GeneralInstance4Channel> { + inner: Timer<'d, T>, +} + +impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { + /// Create a new input capture driver. + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>, + _ch2: Option>, + _ch3: Option>, + _ch4: Option>, + freq: Hertz, + counting_mode: CountingMode, + ) -> Self { + Self::new_inner(tim, freq, counting_mode) + } + + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.set_counting_mode(counting_mode); + this.set_tick_freq(freq); + this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details + this.inner.start(); + + [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] + .iter() + .for_each(|&channel| { + this.inner.set_input_capture_mode(channel, InputCaptureMode::Rising); + + this.inner.set_input_ti_selection(channel, InputTISelection::Normal); + }); + + this + } + + /// Enable the given channel. + pub fn enable(&mut self, channel: Channel) { + self.inner.enable_channel(channel, true); + } + + /// Disable the given channel. + pub fn disable(&mut self, channel: Channel) { + 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 tick frequency. + /// + /// Note: when you call this, the max period value changes + pub fn set_tick_freq(&mut self, freq: Hertz) { + let f = freq; + assert!(f.0 > 0); + let timer_f = self.inner.get_clock_frequency(); + + let pclk_ticks_per_timer_period = timer_f / f; + let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into()); + + let regs = self.inner.regs_core(); + regs.psc().write_value(psc); + + // Generate an Update Request + regs.egr().write(|r| r.set_ug(true)); + } + + /// Set the input capture mode for a given channel. + pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { + self.inner.set_input_capture_mode(channel, mode); + } + + /// Set input TI selection. + pub fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { + self.inner.set_input_ti_selection(channel, tisel) + } + + /// Get capture value for a channel. + pub fn get_capture_value(&self, channel: Channel) -> u32 { + self.inner.get_capture_value(channel) + } +} diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 346127005..532d41650 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -5,6 +5,7 @@ pub mod complementary_pwm; pub mod low_level; pub mod qei; pub mod simple_pwm; +pub mod input_capture; use crate::interrupt; use crate::rcc::RccPeripheral; diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml index 16efa8e6f..fdb246a7f 100644 --- a/examples/stm32f4/.cargo/config.toml +++ b/examples/stm32f4/.cargo/config.toml @@ -1,9 +1,17 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32F429ZITx" +# runner = "probe-rs run --chip STM32F429ZITx" +runner = "arm-none-eabi-gdb -q -x openocd.gdb" [build] -target = "thumbv7em-none-eabi" +# Pick ONE of these default compilation targets +# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ +# target = "thumbv7m-none-eabi" # Cortex-M3 +# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) +# target = "thumbv8m.base-none-eabi" # Cortex-M23 +# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU) +# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU) [env] DEFMT_LOG = "trace" diff --git a/examples/stm32f4/.vscode/README.md b/examples/stm32f4/.vscode/README.md new file mode 100644 index 000000000..4d20f43a8 --- /dev/null +++ b/examples/stm32f4/.vscode/README.md @@ -0,0 +1,109 @@ +# VS Code Configuration + +Example configurations for debugging programs in-editor with VS Code. +This directory contains configurations for two platforms: + + - `LM3S6965EVB` on QEMU + - `STM32F303x` via OpenOCD + +## Required Extensions + +If you have the `code` command in your path, you can run the following commands to install the necessary extensions. + +```sh +code --install-extension rust-lang.rust-analyzer +code --install-extension marus25.cortex-debug +``` + +Otherwise, you can use the Extensions view to search for and install them, or go directly to their marketplace pages and click the "Install" button. + +- [Rust Language Server (rust-analyzer)](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) +- [Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) + +## Use + +The quickstart comes with two debug configurations. +Both are configured to build the project, using the default settings from `.cargo/config`, prior to starting a debug session. + +1. QEMU: Starts a debug session using an emulation of the `LM3S6965EVB` mcu. + - This works on a fresh `cargo generate` without modification of any of the settings described above. + - Semihosting output will be written to the Output view `Adapter Output`. + - `ITM` logging does not work with QEMU emulation. + +2. OpenOCD: Starts a debug session for a `STM32F3DISCOVERY` board (or any `STM32F303x` running at 8MHz). + - Follow the instructions above for configuring the build with `.cargo/config` and the `memory.x` linker script. + - `ITM` output will be written to the Output view `SWO: ITM [port: 0, type: console]` output. + +### Git + +Files in the `.vscode/` directory are `.gitignore`d by default because many files that may end up in the `.vscode/` directory should not be committed and shared. +If you would like to save this debug configuration to your repository and share it with your team, you'll need to explicitly `git add` the files to your repository. + +```sh +git add -f .vscode/launch.json +git add -f .vscode/tasks.json +git add -f .vscode/*.svd +``` + +## Customizing for other targets + +For full documentation, see the [Cortex-Debug][cortex-debug] repository. + +### Device + +Some configurations use this to automatically find the SVD file. +Replace this with the part number for your device. + +```json +"device": "STM32F303VCT6", +``` + +### OpenOCD Config Files + +The `configFiles` property specifies a list of files to pass to OpenOCD. + +```json +"configFiles": [ + "interface/stlink-v2-1.cfg", + "target/stm32f3x.cfg" +], +``` + +See the [OpenOCD config docs][openocd-config] for more information and the [OpenOCD repository for available configuration files][openocd-repo]. + +### SVD + +The SVD file is a standard way of describing all registers and peripherals of an ARM Cortex-M mCU. +Cortex-Debug needs this file to display the current register values for the peripherals on the device. + +You can probably find the SVD for your device on the vendor's website. + + +For example, the STM32F3DISCOVERY board uses an mcu from the `STM32F303x` line of processors. +All the SVD files for the STM32F3 series are available on [ST's Website][stm32f3]. +Download the [stm32f3 SVD pack][stm32f3-svd], and copy the `STM32F303.svd` file into `.vscode/`. +This line of the config tells the Cortex-Debug plug in where to find the file. + +```json +"svdFile": "${workspaceRoot}/.vscode/STM32F303.svd", +``` + +For other processors, simply copy the correct `*.svd` file into the project and update the config accordingly. + +### CPU Frequency + +If your device is running at a frequency other than 8MHz, you'll need to modify this line of `launch.json` for the `ITM` output to work correctly. + +```json +"cpuFrequency": 8000000, +``` + +### Other GDB Servers + +For information on setting up GDB servers other than OpenOCD, see the [Cortex-Debug repository][cortex-debug]. + +[cortex-debug]: https://github.com/Marus/cortex-debug +[stm32f3]: https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f3-series.html#resource +[stm32f3-svd]: https://www.st.com/resource/en/svd/stm32f3_svd.zip +[openocd-config]: http://openocd.org/doc/html/Config-File-Guidelines.html +[openocd-repo]: https://sourceforge.net/p/openocd/code/ci/master/tree/tcl/ diff --git a/examples/stm32f4/.vscode/extensions.json b/examples/stm32f4/.vscode/extensions.json new file mode 100644 index 000000000..b7304974e --- /dev/null +++ b/examples/stm32f4/.vscode/extensions.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "rust-lang.rust-analyzer", + "marus25.cortex-debug", + "usernamehw.errorlens", + "tamasfe.even-better-toml", + "serayuzgur.crates" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + + ] +} diff --git a/examples/stm32f4/.vscode/launch.json b/examples/stm32f4/.vscode/launch.json new file mode 100644 index 000000000..20cd4d2e8 --- /dev/null +++ b/examples/stm32f4/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + /* + * Requires the Rust Language Server (rust-analyzer) and Cortex-Debug extensions + * https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer + * https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug + */ + "version": "0.2.0", + "configurations": [ + { + /* Configuration for the STM32F446 Discovery board */ + "type": "cortex-debug", + "request": "launch", + "name": "Debug (OpenOCD)", + "servertype": "openocd", + "cwd": "${workspaceRoot}", + "preLaunchTask": "Cargo Build (debug)", + "runToEntryPoint": "main", + "executable": "./target/thumbv7em-none-eabihf/debug/input_capture", + /* Run `cargo build --example itm` and uncomment this line to run itm example */ + // "executable": "./target/thumbv7em-none-eabihf/debug/examples/itm", + "device": "STM32F446RET6", + "configFiles": [ + "interface/stlink.cfg", + "target/stm32f4x.cfg" + ], + "postLaunchCommands": [ + "monitor arm semihosting enable" + ], + "postRestartCommands": [], + "postResetCommands": [], + } + ] +} \ No newline at end of file diff --git a/examples/stm32f4/.vscode/tasks.json b/examples/stm32f4/.vscode/tasks.json new file mode 100644 index 000000000..9109a6157 --- /dev/null +++ b/examples/stm32f4/.vscode/tasks.json @@ -0,0 +1,43 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + /* + * This is the default cargo build task, + * but we need to provide a label for it, + * so we can invoke it from the debug launcher. + */ + "label": "Cargo Build (debug)", + "type": "process", + "command": "cargo", + "args": ["build", "--bin", "input_capture"], + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Cargo Build (release)", + "type": "process", + "command": "cargo", + "args": ["build", "--release"], + "problemMatcher": [ + "$rustc" + ], + "group": "build" + }, + { + "label": "Cargo Clean", + "type": "process", + "command": "cargo", + "args": ["clean"], + "problemMatcher": [], + "group": "build" + }, + ] +} diff --git a/examples/stm32f4/openocd.cfg b/examples/stm32f4/openocd.cfg new file mode 100644 index 000000000..e41d52b1a --- /dev/null +++ b/examples/stm32f4/openocd.cfg @@ -0,0 +1,5 @@ +# Sample OpenOCD configuration for the STM32F3DISCOVERY development board + +source [find interface/stlink.cfg] + +source [find target/stm32f4x.cfg] diff --git a/examples/stm32f4/openocd.gdb b/examples/stm32f4/openocd.gdb new file mode 100644 index 000000000..7795319fb --- /dev/null +++ b/examples/stm32f4/openocd.gdb @@ -0,0 +1,40 @@ +target extended-remote :3333 + +# print demangled symbols +set print asm-demangle on + +# set backtrace limit to not have infinite backtrace loops +set backtrace limit 32 + +# detect unhandled exceptions, hard faults and panics +break DefaultHandler +break HardFault +break rust_begin_unwind +# # run the next few lines so the panic message is printed immediately +# # the number needs to be adjusted for your panic handler +# commands $bpnum +# next 4 +# end + +# *try* to stop at the user entry point (it might be gone due to inlining) +break main + +monitor arm semihosting enable + +# # send captured ITM to the file itm.fifo +# # (the microcontroller SWO pin must be connected to the programmer SWO pin) +# # 8000000 must match the core clock frequency +# monitor tpiu config internal itm.txt uart off 8000000 + +# # OR: make the microcontroller SWO pin output compatible with UART (8N1) +# # 8000000 must match the core clock frequency +# # 2000000 is the frequency of the SWO pin +# monitor tpiu config external uart off 8000000 2000000 + +# # enable ITM port 0 +# monitor itm port 0 on + +load + +# start the process but immediately halt the processor +stepi diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs new file mode 100644 index 000000000..202f363fc --- /dev/null +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::{ + gpio::{self, Level, Output, Speed}, + time::Hertz, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +use embassy_stm32::timer::{ + input_capture::{CapturePin, InputCapture}, + Channel, +}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PB2, Level::High, Speed::Low); + + let ic = CapturePin::new_ch3(p.PB10, gpio::Pull::None); + let drv = InputCapture::new(p.TIM2, None, None, Some(ic), None, Hertz::mhz(1), Default::default()); + let mut _last: u32; + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + _last = drv.get_capture_value(Channel::Ch1); + } +} From 431a60ca6384a77243d33f5b1bbef878267bea49 Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Sun, 5 May 2024 22:30:16 -0400 Subject: [PATCH 2/7] formatting --- embassy-stm32/src/timer/input_capture.rs | 1 - examples/stm32f4/Cargo.toml | 2 +- examples/stm32f4/src/bin/input_capture.rs | 29 +++++++++++++---------- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 6401656c8..bf26cabc6 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use embassy_sync::channel; use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 64ac50818..5469f0cc6 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f446re", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 202f363fc..714f043b6 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -3,17 +3,14 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::{self, Level, Output, Speed}, - time::Hertz, -}; +use embassy_stm32::gpio::{Level, Output, Pull, Speed}; +use embassy_stm32::time::khz; +use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; +use embassy_stm32::timer::Channel; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -use embassy_stm32::timer::{ - input_capture::{CapturePin, InputCapture}, - Channel, -}; +/// Connect PB2 and PB10 with a 1k Ohm resistor #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -22,9 +19,11 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.PB2, Level::High, Speed::Low); - let ic = CapturePin::new_ch3(p.PB10, gpio::Pull::None); - let drv = InputCapture::new(p.TIM2, None, None, Some(ic), None, Hertz::mhz(1), Default::default()); - let mut _last: u32; + let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); + let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, khz(1000), Default::default()); + ic.enable(Channel::Ch3); + + let mut last = 0; loop { info!("high"); @@ -34,6 +33,12 @@ async fn main(_spawner: Spawner) { info!("low"); led.set_low(); Timer::after_millis(300).await; - _last = drv.get_capture_value(Channel::Ch1); + + // Check for input capture + let cap = ic.get_capture_value(Channel::Ch3); + if cap != last { + info!("New capture!"); + last = cap; + } } } From 29d6fa0a4aa3203e95cf81ada366cb0ccf593af4 Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Sun, 5 May 2024 23:00:48 -0400 Subject: [PATCH 3/7] add get_input_interrupt --- embassy-stm32/src/timer/input_capture.rs | 5 +++ embassy-stm32/src/timer/low_level.rs | 5 +++ examples/stm32f4/src/bin/input_capture.rs | 45 +++++++++++++---------- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index bf26cabc6..bc7614cda 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -137,4 +137,9 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { pub fn get_capture_value(&self, channel: Channel) -> u32 { self.inner.get_capture_value(channel) } + + /// Get input interrupt. + pub fn get_input_interrupt(&self, channel: Channel) -> bool { + self.inner.get_input_interrupt(channel) + } } diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index aa73986ea..7f533b75c 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -448,6 +448,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { self.regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); } + /// Get input interrupt. + pub fn get_input_interrupt(&self, channel: Channel) -> bool { + self.regs_gp16().sr().read().ccif(channel.index()) + } + /// Enable input interrupt. pub fn enable_input_interrupt(&self, channel: Channel, enable: bool) { self.regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 714f043b6..17f65c6b9 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -4,6 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; +use embassy_stm32::peripherals::PB2; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::Channel; @@ -12,18 +13,9 @@ use {defmt_rtt as _, panic_probe as _}; /// Connect PB2 and PB10 with a 1k Ohm resistor -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); - info!("Hello World!"); - - let mut led = Output::new(p.PB2, Level::High, Speed::Low); - - let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); - let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, khz(1000), Default::default()); - ic.enable(Channel::Ch3); - - let mut last = 0; +#[embassy_executor::task] +async fn blinky(led: PB2) { + let mut led = Output::new(led, Level::High, Speed::Low); loop { info!("high"); @@ -33,12 +25,27 @@ async fn main(_spawner: Spawner) { info!("low"); led.set_low(); Timer::after_millis(300).await; - - // Check for input capture - let cap = ic.get_capture_value(Channel::Ch3); - if cap != last { - info!("New capture!"); - last = cap; - } + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + unwrap!(spawner.spawn(blinky(p.PB2))); + + let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); + let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, khz(1000), Default::default()); + ic.enable(Channel::Ch3); + + loop { + // Check for input capture + if ic.get_input_interrupt(Channel::Ch3) { + let capture_value = ic.get_capture_value(Channel::Ch3); + info!("New capture! {}", capture_value); + } + // Wait a little bit + Timer::after_millis(1).await; } } From 7b04b0166b59558322c77eac6683bbf58268b3f1 Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Sun, 5 May 2024 23:05:06 -0400 Subject: [PATCH 4/7] cleanup for PR --- examples/stm32f4/.cargo/config.toml | 12 +-- examples/stm32f4/.vscode/README.md | 109 ----------------------- examples/stm32f4/.vscode/extensions.json | 17 ---- examples/stm32f4/.vscode/launch.json | 33 ------- examples/stm32f4/.vscode/tasks.json | 43 --------- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f4/openocd.cfg | 5 -- examples/stm32f4/openocd.gdb | 40 --------- 8 files changed, 3 insertions(+), 258 deletions(-) delete mode 100644 examples/stm32f4/.vscode/README.md delete mode 100644 examples/stm32f4/.vscode/extensions.json delete mode 100644 examples/stm32f4/.vscode/launch.json delete mode 100644 examples/stm32f4/.vscode/tasks.json delete mode 100644 examples/stm32f4/openocd.cfg delete mode 100644 examples/stm32f4/openocd.gdb diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml index fdb246a7f..16efa8e6f 100644 --- a/examples/stm32f4/.cargo/config.toml +++ b/examples/stm32f4/.cargo/config.toml @@ -1,17 +1,9 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` -# runner = "probe-rs run --chip STM32F429ZITx" -runner = "arm-none-eabi-gdb -q -x openocd.gdb" +runner = "probe-rs run --chip STM32F429ZITx" [build] -# Pick ONE of these default compilation targets -# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ -# target = "thumbv7m-none-eabi" # Cortex-M3 -# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) -target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) -# target = "thumbv8m.base-none-eabi" # Cortex-M23 -# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU) -# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU) +target = "thumbv7em-none-eabi" [env] DEFMT_LOG = "trace" diff --git a/examples/stm32f4/.vscode/README.md b/examples/stm32f4/.vscode/README.md deleted file mode 100644 index 4d20f43a8..000000000 --- a/examples/stm32f4/.vscode/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# VS Code Configuration - -Example configurations for debugging programs in-editor with VS Code. -This directory contains configurations for two platforms: - - - `LM3S6965EVB` on QEMU - - `STM32F303x` via OpenOCD - -## Required Extensions - -If you have the `code` command in your path, you can run the following commands to install the necessary extensions. - -```sh -code --install-extension rust-lang.rust-analyzer -code --install-extension marus25.cortex-debug -``` - -Otherwise, you can use the Extensions view to search for and install them, or go directly to their marketplace pages and click the "Install" button. - -- [Rust Language Server (rust-analyzer)](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) -- [Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) - -## Use - -The quickstart comes with two debug configurations. -Both are configured to build the project, using the default settings from `.cargo/config`, prior to starting a debug session. - -1. QEMU: Starts a debug session using an emulation of the `LM3S6965EVB` mcu. - - This works on a fresh `cargo generate` without modification of any of the settings described above. - - Semihosting output will be written to the Output view `Adapter Output`. - - `ITM` logging does not work with QEMU emulation. - -2. OpenOCD: Starts a debug session for a `STM32F3DISCOVERY` board (or any `STM32F303x` running at 8MHz). - - Follow the instructions above for configuring the build with `.cargo/config` and the `memory.x` linker script. - - `ITM` output will be written to the Output view `SWO: ITM [port: 0, type: console]` output. - -### Git - -Files in the `.vscode/` directory are `.gitignore`d by default because many files that may end up in the `.vscode/` directory should not be committed and shared. -If you would like to save this debug configuration to your repository and share it with your team, you'll need to explicitly `git add` the files to your repository. - -```sh -git add -f .vscode/launch.json -git add -f .vscode/tasks.json -git add -f .vscode/*.svd -``` - -## Customizing for other targets - -For full documentation, see the [Cortex-Debug][cortex-debug] repository. - -### Device - -Some configurations use this to automatically find the SVD file. -Replace this with the part number for your device. - -```json -"device": "STM32F303VCT6", -``` - -### OpenOCD Config Files - -The `configFiles` property specifies a list of files to pass to OpenOCD. - -```json -"configFiles": [ - "interface/stlink-v2-1.cfg", - "target/stm32f3x.cfg" -], -``` - -See the [OpenOCD config docs][openocd-config] for more information and the [OpenOCD repository for available configuration files][openocd-repo]. - -### SVD - -The SVD file is a standard way of describing all registers and peripherals of an ARM Cortex-M mCU. -Cortex-Debug needs this file to display the current register values for the peripherals on the device. - -You can probably find the SVD for your device on the vendor's website. - - -For example, the STM32F3DISCOVERY board uses an mcu from the `STM32F303x` line of processors. -All the SVD files for the STM32F3 series are available on [ST's Website][stm32f3]. -Download the [stm32f3 SVD pack][stm32f3-svd], and copy the `STM32F303.svd` file into `.vscode/`. -This line of the config tells the Cortex-Debug plug in where to find the file. - -```json -"svdFile": "${workspaceRoot}/.vscode/STM32F303.svd", -``` - -For other processors, simply copy the correct `*.svd` file into the project and update the config accordingly. - -### CPU Frequency - -If your device is running at a frequency other than 8MHz, you'll need to modify this line of `launch.json` for the `ITM` output to work correctly. - -```json -"cpuFrequency": 8000000, -``` - -### Other GDB Servers - -For information on setting up GDB servers other than OpenOCD, see the [Cortex-Debug repository][cortex-debug]. - -[cortex-debug]: https://github.com/Marus/cortex-debug -[stm32f3]: https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f3-series.html#resource -[stm32f3-svd]: https://www.st.com/resource/en/svd/stm32f3_svd.zip -[openocd-config]: http://openocd.org/doc/html/Config-File-Guidelines.html -[openocd-repo]: https://sourceforge.net/p/openocd/code/ci/master/tree/tcl/ diff --git a/examples/stm32f4/.vscode/extensions.json b/examples/stm32f4/.vscode/extensions.json deleted file mode 100644 index b7304974e..000000000 --- a/examples/stm32f4/.vscode/extensions.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "rust-lang.rust-analyzer", - "marus25.cortex-debug", - "usernamehw.errorlens", - "tamasfe.even-better-toml", - "serayuzgur.crates" - ], - // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [ - - ] -} diff --git a/examples/stm32f4/.vscode/launch.json b/examples/stm32f4/.vscode/launch.json deleted file mode 100644 index 20cd4d2e8..000000000 --- a/examples/stm32f4/.vscode/launch.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - /* - * Requires the Rust Language Server (rust-analyzer) and Cortex-Debug extensions - * https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer - * https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug - */ - "version": "0.2.0", - "configurations": [ - { - /* Configuration for the STM32F446 Discovery board */ - "type": "cortex-debug", - "request": "launch", - "name": "Debug (OpenOCD)", - "servertype": "openocd", - "cwd": "${workspaceRoot}", - "preLaunchTask": "Cargo Build (debug)", - "runToEntryPoint": "main", - "executable": "./target/thumbv7em-none-eabihf/debug/input_capture", - /* Run `cargo build --example itm` and uncomment this line to run itm example */ - // "executable": "./target/thumbv7em-none-eabihf/debug/examples/itm", - "device": "STM32F446RET6", - "configFiles": [ - "interface/stlink.cfg", - "target/stm32f4x.cfg" - ], - "postLaunchCommands": [ - "monitor arm semihosting enable" - ], - "postRestartCommands": [], - "postResetCommands": [], - } - ] -} \ No newline at end of file diff --git a/examples/stm32f4/.vscode/tasks.json b/examples/stm32f4/.vscode/tasks.json deleted file mode 100644 index 9109a6157..000000000 --- a/examples/stm32f4/.vscode/tasks.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - /* - * This is the default cargo build task, - * but we need to provide a label for it, - * so we can invoke it from the debug launcher. - */ - "label": "Cargo Build (debug)", - "type": "process", - "command": "cargo", - "args": ["build", "--bin", "input_capture"], - "problemMatcher": [ - "$rustc" - ], - "group": { - "kind": "build", - "isDefault": true - } - }, - { - "label": "Cargo Build (release)", - "type": "process", - "command": "cargo", - "args": ["build", "--release"], - "problemMatcher": [ - "$rustc" - ], - "group": "build" - }, - { - "label": "Cargo Clean", - "type": "process", - "command": "cargo", - "args": ["clean"], - "problemMatcher": [], - "group": "build" - }, - ] -} diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 5469f0cc6..64ac50818 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f446re", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f4/openocd.cfg b/examples/stm32f4/openocd.cfg deleted file mode 100644 index e41d52b1a..000000000 --- a/examples/stm32f4/openocd.cfg +++ /dev/null @@ -1,5 +0,0 @@ -# Sample OpenOCD configuration for the STM32F3DISCOVERY development board - -source [find interface/stlink.cfg] - -source [find target/stm32f4x.cfg] diff --git a/examples/stm32f4/openocd.gdb b/examples/stm32f4/openocd.gdb deleted file mode 100644 index 7795319fb..000000000 --- a/examples/stm32f4/openocd.gdb +++ /dev/null @@ -1,40 +0,0 @@ -target extended-remote :3333 - -# print demangled symbols -set print asm-demangle on - -# set backtrace limit to not have infinite backtrace loops -set backtrace limit 32 - -# detect unhandled exceptions, hard faults and panics -break DefaultHandler -break HardFault -break rust_begin_unwind -# # run the next few lines so the panic message is printed immediately -# # the number needs to be adjusted for your panic handler -# commands $bpnum -# next 4 -# end - -# *try* to stop at the user entry point (it might be gone due to inlining) -break main - -monitor arm semihosting enable - -# # send captured ITM to the file itm.fifo -# # (the microcontroller SWO pin must be connected to the programmer SWO pin) -# # 8000000 must match the core clock frequency -# monitor tpiu config internal itm.txt uart off 8000000 - -# # OR: make the microcontroller SWO pin output compatible with UART (8N1) -# # 8000000 must match the core clock frequency -# # 2000000 is the frequency of the SWO pin -# monitor tpiu config external uart off 8000000 2000000 - -# # enable ITM port 0 -# monitor itm port 0 on - -load - -# start the process but immediately halt the processor -stepi From b662dfb1838a72d243e939da9349c68c8fef5bdc Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Sun, 5 May 2024 23:15:00 -0400 Subject: [PATCH 5/7] format timer/mod.rs --- embassy-stm32/src/timer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 532d41650..9a1fbcd61 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,10 +2,10 @@ #[cfg(not(stm32l0))] pub mod complementary_pwm; +pub mod input_capture; pub mod low_level; pub mod qei; pub mod simple_pwm; -pub mod input_capture; use crate::interrupt; use crate::rcc::RccPeripheral; From 55c8d3f4743bc653c1659dc3e961df86afe7d3db Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Mon, 6 May 2024 02:47:42 -0400 Subject: [PATCH 6/7] add async capture --- embassy-stm32/src/timer/input_capture.rs | 100 ++++++++++++++++++++-- embassy-stm32/src/timer/mod.rs | 93 +++++++++++++++++++- examples/stm32f4/src/bin/input_capture.rs | 26 +++--- 3 files changed, 199 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index bc7614cda..e5ec2505a 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -1,12 +1,17 @@ //! Input capture driver. +use core::future::Future; use core::marker::PhantomData; +use core::pin::Pin; +use core::task::{Context, Poll}; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; +use super::CaptureCompareInterruptHandler; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; use crate::gpio::{AFType, AnyPin, Pull}; +use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; use crate::Peripheral; @@ -65,6 +70,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { _ch2: Option>, _ch3: Option>, _ch4: Option>, + _irq: impl Binding> + 'd, freq: Hertz, counting_mode: CountingMode, ) -> Self { @@ -79,13 +85,9 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details this.inner.start(); - [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] - .iter() - .for_each(|&channel| { - this.inner.set_input_capture_mode(channel, InputCaptureMode::Rising); - - this.inner.set_input_ti_selection(channel, InputTISelection::Normal); - }); + // enable NVIC interrupt + T::CaptureCompareInterrupt::unpend(); + unsafe { T::CaptureCompareInterrupt::enable() }; this } @@ -142,4 +144,88 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { pub fn get_input_interrupt(&self, channel: Channel) -> bool { self.inner.get_input_interrupt(channel) } + + fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture { + self.inner.enable_channel(channel, true); + self.inner.set_input_capture_mode(channel, mode); + self.inner.set_input_ti_selection(channel, tisel); + self.inner.clear_input_interrupt(channel); + self.inner.enable_input_interrupt(channel, true); + + InputCaptureFuture { + channel, + phantom: PhantomData, + } + } + + /// Asynchronously wait until the pin sees a rising edge. + pub async fn wait_for_rising_edge(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Normal) + .await + } + + /// Asynchronously wait until the pin sees a falling edge. + pub async fn wait_for_falling_edge(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Normal) + .await + } + + /// Asynchronously wait until the pin sees any edge. + pub async fn wait_for_any_edge(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Normal) + .await + } + + /// Asynchronously wait until the (alternate) pin sees a rising edge. + pub async fn wait_for_rising_edge_alternate(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::Rising, InputTISelection::Alternate) + .await + } + + /// Asynchronously wait until the (alternate) pin sees a falling edge. + pub async fn wait_for_falling_edge_alternate(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::Falling, InputTISelection::Alternate) + .await + } + + /// Asynchronously wait until the (alternate) pin sees any edge. + pub async fn wait_for_any_edge_alternate(&mut self, channel: Channel) -> u32 { + self.new_future(channel, InputCaptureMode::BothEdges, InputTISelection::Alternate) + .await + } +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct InputCaptureFuture { + channel: Channel, + phantom: PhantomData, +} + +impl Drop for InputCaptureFuture { + fn drop(&mut self) { + critical_section::with(|_| { + let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }; + + // disable interrupt enable + regs.dier().modify(|w| w.set_ccie(self.channel.index(), false)); + }); + } +} + +impl Future for InputCaptureFuture { + type Output = u32; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + T::state().cc_waker[self.channel.index()].register(cx.waker()); + + let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }; + + let dier = regs.dier().read(); + if !dier.ccie(self.channel.index()) { + let val = regs.ccr(self.channel.index()).read().0; + Poll::Ready(val) + } else { + Poll::Pending + } + } } diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 9a1fbcd61..4b4929aeb 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,5 +1,8 @@ //! Timers, PWM, quadrature decoder. +use core::marker::PhantomData; +use embassy_sync::waitqueue::AtomicWaker; + #[cfg(not(stm32l0))] pub mod complementary_pwm; pub mod input_capture; @@ -46,8 +49,29 @@ pub enum TimerBits { Bits32, } +struct State { + up_waker: AtomicWaker, + cc_waker: [AtomicWaker; 4], +} + +impl State { + const fn new() -> Self { + const NEW_AW: AtomicWaker = AtomicWaker::new(); + Self { + up_waker: NEW_AW, + cc_waker: [NEW_AW; 4], + } + } +} + +trait SealedInstance: RccPeripheral { + /// Async state for this timer + fn state() -> &'static State; +} + /// Core timer instance. -pub trait CoreInstance: RccPeripheral + 'static { +#[allow(private_bounds)] +pub trait CoreInstance: SealedInstance + 'static { /// Update Interrupt for this timer. type UpdateInterrupt: interrupt::typelevel::Interrupt; @@ -144,6 +168,13 @@ dma_trait!(Ch4Dma, GeneralInstance4Channel); #[allow(unused)] macro_rules! impl_core_timer { ($inst:ident, $bits:expr) => { + impl SealedInstance for crate::peripherals::$inst { + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } + impl CoreInstance for crate::peripherals::$inst { type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; @@ -286,3 +317,63 @@ foreach_interrupt! { impl AdvancedInstance4Channel for crate::peripherals::$inst {} }; } + +/// Update interrupt handler. +pub struct UpdateInterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for UpdateInterruptHandler { + unsafe fn on_interrupt() { + #[cfg(feature = "low-power")] + crate::low_power::on_wakeup_irq(); + + let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); + + // Read TIM interrupt flags. + let sr = regs.sr().read(); + + // Mask relevant interrupts (UIE). + let bits = sr.0 & 0x00000001; + + // Mask all the channels that fired. + regs.dier().modify(|w| w.0 &= !bits); + + // Wake the tasks + if sr.uif() { + T::state().up_waker.wake(); + } + } +} + +/// Capture/Compare interrupt handler. +pub struct CaptureCompareInterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler + for CaptureCompareInterruptHandler +{ + unsafe fn on_interrupt() { + #[cfg(feature = "low-power")] + crate::low_power::on_wakeup_irq(); + + let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); + + // Read TIM interrupt flags. + let sr = regs.sr().read(); + + // Mask relevant interrupts (CCIE). + let bits = sr.0 & 0x0000001E; + + // Mask all the channels that fired. + regs.dier().modify(|w| w.0 &= !bits); + + // Wake the tasks + for ch in 0..4 { + if sr.ccif(ch) { + T::state().cc_waker[ch].wake(); + } + } + } +} diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 17f65c6b9..862a3103b 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -3,18 +3,19 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; -use embassy_stm32::peripherals::PB2; +use embassy_stm32::peripherals; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; -use embassy_stm32::timer::Channel; +use embassy_stm32::timer::{self, Channel}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; /// Connect PB2 and PB10 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: PB2) { +async fn blinky(led: peripherals::PB2) { let mut led = Output::new(led, Level::High, Speed::Low); loop { @@ -28,6 +29,10 @@ async fn blinky(led: PB2) { } } +bind_interrupts!(struct Irqs { + TIM2 => timer::CaptureCompareInterruptHandler; +}); + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); @@ -36,16 +41,13 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB2))); let ch3 = CapturePin::new_ch3(p.PB10, Pull::None); - let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, khz(1000), Default::default()); - ic.enable(Channel::Ch3); + let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default()); loop { - // Check for input capture - if ic.get_input_interrupt(Channel::Ch3) { - let capture_value = ic.get_capture_value(Channel::Ch3); - info!("New capture! {}", capture_value); - } - // Wait a little bit - Timer::after_millis(1).await; + info!("wait for risign edge"); + ic.wait_for_rising_edge(Channel::Ch3).await; + + let capture_value = ic.get_capture_value(Channel::Ch3); + info!("new capture! {}", capture_value); } } From 969933cb7bd8b8e41aed824afeaf12fd094a5056 Mon Sep 17 00:00:00 2001 From: Bruno Bousquet <21108660+brunob45@users.noreply.github.com> Date: Mon, 6 May 2024 02:52:22 -0400 Subject: [PATCH 7/7] fix fmt for ci --- embassy-stm32/src/timer/input_capture.rs | 6 ++++-- embassy-stm32/src/timer/mod.rs | 1 + examples/stm32f4/src/bin/input_capture.rs | 3 +-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index e5ec2505a..a1c1486f9 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -8,8 +8,10 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; -use super::CaptureCompareInterruptHandler; -use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; +use super::{ + CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, + GeneralInstance4Channel, +}; use crate::gpio::{AFType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 4b4929aeb..314b6006b 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,6 +1,7 @@ //! Timers, PWM, quadrature decoder. use core::marker::PhantomData; + use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(stm32l0))] diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 862a3103b..49de33d2b 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -3,12 +3,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::bind_interrupts; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; -use embassy_stm32::peripherals; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _};