diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-05-01 02:21:06 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-05-01 02:24:45 +0200 |
| commit | fb67fe0a6c155191534955f1230dccaea0e11a94 (patch) | |
| tree | ac01b69047aeee08983a5149409080d137f19cb1 /examples | |
| parent | ecc910b76dbfa2064f42e6917a7b5654a89b81ed (diff) | |
stm32: add support for STM32H7[RS] "bootflash line", add HIL tests.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/stm32h7rs/.cargo/config.toml | 8 | ||||
| -rw-r--r-- | examples/stm32h7rs/Cargo.toml | 73 | ||||
| -rw-r--r-- | examples/stm32h7rs/build.rs | 5 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/blinky.rs | 51 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/button_exti.rs | 25 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/can.rs | 98 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/mco.rs | 29 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/multiprio.rs | 150 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/rng.rs | 26 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/rtc.rs | 36 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/signal.rs | 36 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/spi.rs | 50 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/spi_dma.rs | 46 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/usart.rs | 39 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/usart_dma.rs | 47 | ||||
| -rw-r--r-- | examples/stm32h7rs/src/bin/usart_split.rs | 48 |
16 files changed, 767 insertions, 0 deletions
diff --git a/examples/stm32h7rs/.cargo/config.toml b/examples/stm32h7rs/.cargo/config.toml new file mode 100644 index 000000000..44dbda94f --- /dev/null +++ b/examples/stm32h7rs/.cargo/config.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [target.thumbv7em-none-eabihf] | ||
| 2 | runner = 'probe-rs run --chip STM32H7S3L8Hx' | ||
| 3 | |||
| 4 | [build] | ||
| 5 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) | ||
| 6 | |||
| 7 | [env] | ||
| 8 | DEFMT_LOG = "trace" | ||
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml new file mode 100644 index 000000000..ad661411d --- /dev/null +++ b/examples/stm32h7rs/Cargo.toml | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-stm32h7-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | # Change stm32h743bi to your chip name, if necessary. | ||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | ||
| 10 | embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | ||
| 12 | embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | ||
| 13 | embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | ||
| 14 | embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } | ||
| 15 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | ||
| 16 | |||
| 17 | defmt = "0.3" | ||
| 18 | defmt-rtt = "0.4" | ||
| 19 | |||
| 20 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 21 | cortex-m-rt = "0.7.0" | ||
| 22 | embedded-hal = "0.2.6" | ||
| 23 | embedded-hal-1 = { package = "embedded-hal", version = "1.0" } | ||
| 24 | embedded-hal-async = { version = "1.0" } | ||
| 25 | embedded-nal-async = { version = "0.7.1" } | ||
| 26 | embedded-io-async = { version = "0.6.1" } | ||
| 27 | panic-probe = { version = "0.3", features = ["print-defmt"] } | ||
| 28 | heapless = { version = "0.8", default-features = false } | ||
| 29 | rand_core = "0.6.3" | ||
| 30 | critical-section = "1.1" | ||
| 31 | micromath = "2.0.0" | ||
| 32 | stm32-fmc = "0.3.0" | ||
| 33 | embedded-storage = "0.3.1" | ||
| 34 | static_cell = "2" | ||
| 35 | chrono = { version = "^0.4", default-features = false } | ||
| 36 | |||
| 37 | # cargo build/run | ||
| 38 | [profile.dev] | ||
| 39 | codegen-units = 1 | ||
| 40 | debug = 2 | ||
| 41 | debug-assertions = true # <- | ||
| 42 | incremental = false | ||
| 43 | opt-level = 3 # <- | ||
| 44 | overflow-checks = true # <- | ||
| 45 | |||
| 46 | # cargo test | ||
| 47 | [profile.test] | ||
| 48 | codegen-units = 1 | ||
| 49 | debug = 2 | ||
| 50 | debug-assertions = true # <- | ||
| 51 | incremental = false | ||
| 52 | opt-level = 3 # <- | ||
| 53 | overflow-checks = true # <- | ||
| 54 | |||
| 55 | # cargo build/run --release | ||
| 56 | [profile.release] | ||
| 57 | codegen-units = 1 | ||
| 58 | debug = 2 | ||
| 59 | debug-assertions = false # <- | ||
| 60 | incremental = false | ||
| 61 | lto = 'fat' | ||
| 62 | opt-level = 3 # <- | ||
| 63 | overflow-checks = false # <- | ||
| 64 | |||
| 65 | # cargo test --release | ||
| 66 | [profile.bench] | ||
| 67 | codegen-units = 1 | ||
| 68 | debug = 2 | ||
| 69 | debug-assertions = false # <- | ||
| 70 | incremental = false | ||
| 71 | lto = 'fat' | ||
| 72 | opt-level = 3 # <- | ||
| 73 | overflow-checks = false # <- | ||
diff --git a/examples/stm32h7rs/build.rs b/examples/stm32h7rs/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32h7rs/build.rs | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | fn main() { | ||
| 2 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 3 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 4 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 5 | } | ||
diff --git a/examples/stm32h7rs/src/bin/blinky.rs b/examples/stm32h7rs/src/bin/blinky.rs new file mode 100644 index 000000000..137c585b7 --- /dev/null +++ b/examples/stm32h7rs/src/bin/blinky.rs | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_stm32::time::Hertz; | ||
| 8 | use embassy_stm32::Config; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let mut config = Config::default(); | ||
| 15 | { | ||
| 16 | use embassy_stm32::rcc::*; | ||
| 17 | config.rcc.hse = Some(Hse { | ||
| 18 | freq: Hertz(24_000_000), | ||
| 19 | mode: HseMode::Oscillator, | ||
| 20 | }); | ||
| 21 | config.rcc.pll1 = Some(Pll { | ||
| 22 | source: PllSource::HSE, | ||
| 23 | prediv: PllPreDiv::DIV3, | ||
| 24 | mul: PllMul::MUL150, | ||
| 25 | divp: Some(PllDiv::DIV2), | ||
| 26 | divq: None, | ||
| 27 | divr: None, | ||
| 28 | }); | ||
| 29 | config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz | ||
| 30 | config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz | ||
| 31 | config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 32 | config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 33 | config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 34 | config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz | ||
| 35 | config.rcc.voltage_scale = VoltageScale::HIGH; | ||
| 36 | } | ||
| 37 | let p = embassy_stm32::init(config); | ||
| 38 | info!("Hello World!"); | ||
| 39 | |||
| 40 | let mut led = Output::new(p.PD10, Level::High, Speed::Low); | ||
| 41 | |||
| 42 | loop { | ||
| 43 | info!("high"); | ||
| 44 | led.set_high(); | ||
| 45 | Timer::after_millis(500).await; | ||
| 46 | |||
| 47 | info!("low"); | ||
| 48 | led.set_low(); | ||
| 49 | Timer::after_millis(500).await; | ||
| 50 | } | ||
| 51 | } | ||
diff --git a/examples/stm32h7rs/src/bin/button_exti.rs b/examples/stm32h7rs/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32h7rs/src/bin/button_exti.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::exti::ExtiInput; | ||
| 7 | use embassy_stm32::gpio::Pull; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | #[embassy_executor::main] | ||
| 11 | async fn main(_spawner: Spawner) { | ||
| 12 | let p = embassy_stm32::init(Default::default()); | ||
| 13 | info!("Hello World!"); | ||
| 14 | |||
| 15 | let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); | ||
| 16 | |||
| 17 | info!("Press the USER button..."); | ||
| 18 | |||
| 19 | loop { | ||
| 20 | button.wait_for_falling_edge().await; | ||
| 21 | info!("Pressed!"); | ||
| 22 | button.wait_for_rising_edge().await; | ||
| 23 | info!("Released!"); | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/examples/stm32h7rs/src/bin/can.rs b/examples/stm32h7rs/src/bin/can.rs new file mode 100644 index 000000000..0af11ef3e --- /dev/null +++ b/examples/stm32h7rs/src/bin/can.rs | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::peripherals::*; | ||
| 7 | use embassy_stm32::{bind_interrupts, can, rcc, Config}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | bind_interrupts!(struct Irqs { | ||
| 12 | FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>; | ||
| 13 | FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async fn main(_spawner: Spawner) { | ||
| 18 | let mut config = Config::default(); | ||
| 19 | config.rcc.hse = Some(rcc::Hse { | ||
| 20 | freq: embassy_stm32::time::Hertz(25_000_000), | ||
| 21 | mode: rcc::HseMode::Oscillator, | ||
| 22 | }); | ||
| 23 | config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; | ||
| 24 | |||
| 25 | let peripherals = embassy_stm32::init(config); | ||
| 26 | |||
| 27 | let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); | ||
| 28 | |||
| 29 | // 250k bps | ||
| 30 | can.set_bitrate(250_000); | ||
| 31 | |||
| 32 | //let mut can = can.into_internal_loopback_mode(); | ||
| 33 | let mut can = can.into_normal_mode(); | ||
| 34 | |||
| 35 | info!("CAN Configured"); | ||
| 36 | |||
| 37 | let mut i = 0; | ||
| 38 | let mut last_read_ts = embassy_time::Instant::now(); | ||
| 39 | |||
| 40 | loop { | ||
| 41 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 42 | info!("Writing frame"); | ||
| 43 | _ = can.write(&frame).await; | ||
| 44 | |||
| 45 | match can.read().await { | ||
| 46 | Ok(envelope) => { | ||
| 47 | let (rx_frame, ts) = envelope.parts(); | ||
| 48 | let delta = (ts - last_read_ts).as_millis(); | ||
| 49 | last_read_ts = ts; | ||
| 50 | info!( | ||
| 51 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 52 | rx_frame.data()[0], | ||
| 53 | rx_frame.data()[1], | ||
| 54 | rx_frame.data()[2], | ||
| 55 | rx_frame.data()[3], | ||
| 56 | delta, | ||
| 57 | ) | ||
| 58 | } | ||
| 59 | Err(_err) => error!("Error in frame"), | ||
| 60 | } | ||
| 61 | |||
| 62 | Timer::after_millis(250).await; | ||
| 63 | |||
| 64 | i += 1; | ||
| 65 | if i > 3 { | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | let (mut tx, mut rx, _props) = can.split(); | ||
| 71 | // With split | ||
| 72 | loop { | ||
| 73 | let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); | ||
| 74 | info!("Writing frame"); | ||
| 75 | _ = tx.write(&frame).await; | ||
| 76 | |||
| 77 | match rx.read().await { | ||
| 78 | Ok(envelope) => { | ||
| 79 | let (rx_frame, ts) = envelope.parts(); | ||
| 80 | let delta = (ts - last_read_ts).as_millis(); | ||
| 81 | last_read_ts = ts; | ||
| 82 | info!( | ||
| 83 | "Rx: {:x} {:x} {:x} {:x} --- NEW {}", | ||
| 84 | rx_frame.data()[0], | ||
| 85 | rx_frame.data()[1], | ||
| 86 | rx_frame.data()[2], | ||
| 87 | rx_frame.data()[3], | ||
| 88 | delta, | ||
| 89 | ) | ||
| 90 | } | ||
| 91 | Err(_err) => error!("Error in frame"), | ||
| 92 | } | ||
| 93 | |||
| 94 | Timer::after_millis(250).await; | ||
| 95 | |||
| 96 | i = i.wrapping_add(1); | ||
| 97 | } | ||
| 98 | } | ||
diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs new file mode 100644 index 000000000..a6ee27625 --- /dev/null +++ b/examples/stm32h7rs/src/bin/mco.rs | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 7 | use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::main] | ||
| 12 | async fn main(_spawner: Spawner) { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | info!("Hello World!"); | ||
| 15 | |||
| 16 | let mut led = Output::new(p.PB14, Level::High, Speed::Low); | ||
| 17 | |||
| 18 | let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); | ||
| 19 | |||
| 20 | loop { | ||
| 21 | info!("high"); | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after_millis(500).await; | ||
| 24 | |||
| 25 | info!("low"); | ||
| 26 | led.set_low(); | ||
| 27 | Timer::after_millis(500).await; | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/examples/stm32h7rs/src/bin/multiprio.rs b/examples/stm32h7rs/src/bin/multiprio.rs new file mode 100644 index 000000000..fcbb6c653 --- /dev/null +++ b/examples/stm32h7rs/src/bin/multiprio.rs | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | //! This example showcases how to create multiple Executor instances to run tasks at | ||
| 2 | //! different priority levels. | ||
| 3 | //! | ||
| 4 | //! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling | ||
| 5 | //! there's work in the queue, and `wfe` for waiting for work. | ||
| 6 | //! | ||
| 7 | //! Medium and high priority executors run in two interrupts with different priorities. | ||
| 8 | //! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since | ||
| 9 | //! when there's work the interrupt will trigger and run the executor. | ||
| 10 | //! | ||
| 11 | //! Sample output below. Note that high priority ticks can interrupt everything else, and | ||
| 12 | //! medium priority computations can interrupt low priority computations, making them to appear | ||
| 13 | //! to take significantly longer time. | ||
| 14 | //! | ||
| 15 | //! ```not_rust | ||
| 16 | //! [med] Starting long computation | ||
| 17 | //! [med] done in 992 ms | ||
| 18 | //! [high] tick! | ||
| 19 | //! [low] Starting long computation | ||
| 20 | //! [med] Starting long computation | ||
| 21 | //! [high] tick! | ||
| 22 | //! [high] tick! | ||
| 23 | //! [med] done in 993 ms | ||
| 24 | //! [med] Starting long computation | ||
| 25 | //! [high] tick! | ||
| 26 | //! [high] tick! | ||
| 27 | //! [med] done in 993 ms | ||
| 28 | //! [low] done in 3972 ms | ||
| 29 | //! [med] Starting long computation | ||
| 30 | //! [high] tick! | ||
| 31 | //! [high] tick! | ||
| 32 | //! [med] done in 993 ms | ||
| 33 | //! ``` | ||
| 34 | //! | ||
| 35 | //! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. | ||
| 36 | //! You will get an output like the following. Note that no computation is ever interrupted. | ||
| 37 | //! | ||
| 38 | //! ```not_rust | ||
| 39 | //! [high] tick! | ||
| 40 | //! [med] Starting long computation | ||
| 41 | //! [med] done in 496 ms | ||
| 42 | //! [low] Starting long computation | ||
| 43 | //! [low] done in 992 ms | ||
| 44 | //! [med] Starting long computation | ||
| 45 | //! [med] done in 496 ms | ||
| 46 | //! [high] tick! | ||
| 47 | //! [low] Starting long computation | ||
| 48 | //! [low] done in 992 ms | ||
| 49 | //! [high] tick! | ||
| 50 | //! [med] Starting long computation | ||
| 51 | //! [med] done in 496 ms | ||
| 52 | //! [high] tick! | ||
| 53 | //! ``` | ||
| 54 | //! | ||
| 55 | |||
| 56 | #![no_std] | ||
| 57 | #![no_main] | ||
| 58 | |||
| 59 | use cortex_m_rt::entry; | ||
| 60 | use defmt::*; | ||
| 61 | use embassy_executor::{Executor, InterruptExecutor}; | ||
| 62 | use embassy_stm32::interrupt; | ||
| 63 | use embassy_stm32::interrupt::{InterruptExt, Priority}; | ||
| 64 | use embassy_time::{Instant, Timer}; | ||
| 65 | use static_cell::StaticCell; | ||
| 66 | use {defmt_rtt as _, panic_probe as _}; | ||
| 67 | |||
| 68 | #[embassy_executor::task] | ||
| 69 | async fn run_high() { | ||
| 70 | loop { | ||
| 71 | info!(" [high] tick!"); | ||
| 72 | Timer::after_ticks(27374).await; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | #[embassy_executor::task] | ||
| 77 | async fn run_med() { | ||
| 78 | loop { | ||
| 79 | let start = Instant::now(); | ||
| 80 | info!(" [med] Starting long computation"); | ||
| 81 | |||
| 82 | // Spin-wait to simulate a long CPU computation | ||
| 83 | cortex_m::asm::delay(128_000_000); // ~1 second | ||
| 84 | |||
| 85 | let end = Instant::now(); | ||
| 86 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 87 | info!(" [med] done in {} ms", ms); | ||
| 88 | |||
| 89 | Timer::after_ticks(23421).await; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | #[embassy_executor::task] | ||
| 94 | async fn run_low() { | ||
| 95 | loop { | ||
| 96 | let start = Instant::now(); | ||
| 97 | info!("[low] Starting long computation"); | ||
| 98 | |||
| 99 | // Spin-wait to simulate a long CPU computation | ||
| 100 | cortex_m::asm::delay(256_000_000); // ~2 seconds | ||
| 101 | |||
| 102 | let end = Instant::now(); | ||
| 103 | let ms = end.duration_since(start).as_ticks() / 33; | ||
| 104 | info!("[low] done in {} ms", ms); | ||
| 105 | |||
| 106 | Timer::after_ticks(32983).await; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); | ||
| 111 | static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); | ||
| 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | ||
| 113 | |||
| 114 | #[interrupt] | ||
| 115 | unsafe fn UART4() { | ||
| 116 | EXECUTOR_HIGH.on_interrupt() | ||
| 117 | } | ||
| 118 | |||
| 119 | #[interrupt] | ||
| 120 | unsafe fn UART5() { | ||
| 121 | EXECUTOR_MED.on_interrupt() | ||
| 122 | } | ||
| 123 | |||
| 124 | #[entry] | ||
| 125 | fn main() -> ! { | ||
| 126 | info!("Hello World!"); | ||
| 127 | |||
| 128 | let _p = embassy_stm32::init(Default::default()); | ||
| 129 | |||
| 130 | // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as | ||
| 131 | // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. | ||
| 132 | // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt | ||
| 133 | // vector would work exactly the same. | ||
| 134 | |||
| 135 | // High-priority executor: UART4, priority level 6 | ||
| 136 | interrupt::UART4.set_priority(Priority::P6); | ||
| 137 | let spawner = EXECUTOR_HIGH.start(interrupt::UART4); | ||
| 138 | unwrap!(spawner.spawn(run_high())); | ||
| 139 | |||
| 140 | // Medium-priority executor: UART5, priority level 7 | ||
| 141 | interrupt::UART5.set_priority(Priority::P7); | ||
| 142 | let spawner = EXECUTOR_MED.start(interrupt::UART5); | ||
| 143 | unwrap!(spawner.spawn(run_med())); | ||
| 144 | |||
| 145 | // Low priority executor: runs in thread mode, using WFE/SEV | ||
| 146 | let executor = EXECUTOR_LOW.init(Executor::new()); | ||
| 147 | executor.run(|spawner| { | ||
| 148 | unwrap!(spawner.spawn(run_low())); | ||
| 149 | }); | ||
| 150 | } | ||
diff --git a/examples/stm32h7rs/src/bin/rng.rs b/examples/stm32h7rs/src/bin/rng.rs new file mode 100644 index 000000000..a9ef7200d --- /dev/null +++ b/examples/stm32h7rs/src/bin/rng.rs | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::rng::Rng; | ||
| 7 | use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; | ||
| 8 | use {defmt_rtt as _, panic_probe as _}; | ||
| 9 | |||
| 10 | bind_interrupts!(struct Irqs { | ||
| 11 | RNG => rng::InterruptHandler<peripherals::RNG>; | ||
| 12 | }); | ||
| 13 | |||
| 14 | #[embassy_executor::main] | ||
| 15 | async fn main(_spawner: Spawner) { | ||
| 16 | let mut config = Config::default(); | ||
| 17 | config.rcc.hsi48 = Some(Default::default()); // needed for RNG | ||
| 18 | let p = embassy_stm32::init(config); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let mut rng = Rng::new(p.RNG, Irqs); | ||
| 22 | |||
| 23 | let mut buf = [0u8; 16]; | ||
| 24 | unwrap!(rng.async_fill_bytes(&mut buf).await); | ||
| 25 | info!("random bytes: {:02x}", buf); | ||
| 26 | } | ||
diff --git a/examples/stm32h7rs/src/bin/rtc.rs b/examples/stm32h7rs/src/bin/rtc.rs new file mode 100644 index 000000000..0adb48877 --- /dev/null +++ b/examples/stm32h7rs/src/bin/rtc.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use chrono::{NaiveDate, NaiveDateTime}; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::rcc::LsConfig; | ||
| 8 | use embassy_stm32::rtc::{Rtc, RtcConfig}; | ||
| 9 | use embassy_stm32::Config; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) { | ||
| 15 | let mut config = Config::default(); | ||
| 16 | config.rcc.ls = LsConfig::default_lse(); | ||
| 17 | |||
| 18 | let p = embassy_stm32::init(config); | ||
| 19 | info!("Hello World!"); | ||
| 20 | |||
| 21 | let now = NaiveDate::from_ymd_opt(2020, 5, 15) | ||
| 22 | .unwrap() | ||
| 23 | .and_hms_opt(10, 30, 15) | ||
| 24 | .unwrap(); | ||
| 25 | |||
| 26 | let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); | ||
| 27 | info!("Got RTC! {:?}", now.and_utc().timestamp()); | ||
| 28 | |||
| 29 | rtc.set_datetime(now.into()).expect("datetime not set"); | ||
| 30 | |||
| 31 | // In reality the delay would be much longer | ||
| 32 | Timer::after_millis(20000).await; | ||
| 33 | |||
| 34 | let then: NaiveDateTime = rtc.now().unwrap().into(); | ||
| 35 | info!("Got RTC! {:?}", then.and_utc().timestamp()); | ||
| 36 | } | ||
diff --git a/examples/stm32h7rs/src/bin/signal.rs b/examples/stm32h7rs/src/bin/signal.rs new file mode 100644 index 000000000..b73360f32 --- /dev/null +++ b/examples/stm32h7rs/src/bin/signal.rs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::{info, unwrap}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 7 | use embassy_sync::signal::Signal; | ||
| 8 | use embassy_time::Timer; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | static SIGNAL: Signal<CriticalSectionRawMutex, u32> = Signal::new(); | ||
| 12 | |||
| 13 | #[embassy_executor::task] | ||
| 14 | async fn my_sending_task() { | ||
| 15 | let mut counter: u32 = 0; | ||
| 16 | |||
| 17 | loop { | ||
| 18 | Timer::after_secs(1).await; | ||
| 19 | |||
| 20 | SIGNAL.signal(counter); | ||
| 21 | |||
| 22 | counter = counter.wrapping_add(1); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | #[embassy_executor::main] | ||
| 27 | async fn main(spawner: Spawner) { | ||
| 28 | let _p = embassy_stm32::init(Default::default()); | ||
| 29 | unwrap!(spawner.spawn(my_sending_task())); | ||
| 30 | |||
| 31 | loop { | ||
| 32 | let received_counter = SIGNAL.wait().await; | ||
| 33 | |||
| 34 | info!("signalled, counter: {}", received_counter); | ||
| 35 | } | ||
| 36 | } | ||
diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs new file mode 100644 index 000000000..a7767876d --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi.rs | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | use core::str::from_utf8; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::mode::Blocking; | ||
| 11 | use embassy_stm32::peripherals::SPI3; | ||
| 12 | use embassy_stm32::spi; | ||
| 13 | use embassy_stm32::time::mhz; | ||
| 14 | use heapless::String; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | #[embassy_executor::task] | ||
| 19 | async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { | ||
| 20 | for n in 0u32.. { | ||
| 21 | let mut write: String<128> = String::new(); | ||
| 22 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 23 | unsafe { | ||
| 24 | let result = spi.blocking_transfer_in_place(write.as_bytes_mut()); | ||
| 25 | if let Err(_) = result { | ||
| 26 | defmt::panic!("crap"); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | info!("read via spi: {}", from_utf8(write.as_bytes()).unwrap()); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 34 | |||
| 35 | #[entry] | ||
| 36 | fn main() -> ! { | ||
| 37 | info!("Hello World!"); | ||
| 38 | let p = embassy_stm32::init(Default::default()); | ||
| 39 | |||
| 40 | let mut spi_config = spi::Config::default(); | ||
| 41 | spi_config.frequency = mhz(1); | ||
| 42 | |||
| 43 | let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); | ||
| 44 | |||
| 45 | let executor = EXECUTOR.init(Executor::new()); | ||
| 46 | |||
| 47 | executor.run(|spawner| { | ||
| 48 | unwrap!(spawner.spawn(main_task(spi))); | ||
| 49 | }) | ||
| 50 | } | ||
diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs new file mode 100644 index 000000000..26b5d6751 --- /dev/null +++ b/examples/stm32h7rs/src/bin/spi_dma.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | use core::str::from_utf8; | ||
| 6 | |||
| 7 | use cortex_m_rt::entry; | ||
| 8 | use defmt::*; | ||
| 9 | use embassy_executor::Executor; | ||
| 10 | use embassy_stm32::mode::Async; | ||
| 11 | use embassy_stm32::time::mhz; | ||
| 12 | use embassy_stm32::{peripherals, spi}; | ||
| 13 | use heapless::String; | ||
| 14 | use static_cell::StaticCell; | ||
| 15 | use {defmt_rtt as _, panic_probe as _}; | ||
| 16 | |||
| 17 | #[embassy_executor::task] | ||
| 18 | async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { | ||
| 19 | for n in 0u32.. { | ||
| 20 | let mut write: String<128> = String::new(); | ||
| 21 | let mut read = [0; 128]; | ||
| 22 | core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 23 | // transfer will slice the &mut read down to &write's actual length. | ||
| 24 | spi.transfer(&mut read, write.as_bytes()).await.ok(); | ||
| 25 | info!("read via spi+dma: {}", from_utf8(&read).unwrap()); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 30 | |||
| 31 | #[entry] | ||
| 32 | fn main() -> ! { | ||
| 33 | info!("Hello World!"); | ||
| 34 | let p = embassy_stm32::init(Default::default()); | ||
| 35 | |||
| 36 | let mut spi_config = spi::Config::default(); | ||
| 37 | spi_config.frequency = mhz(1); | ||
| 38 | |||
| 39 | let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, p.GPDMA1_CH0, p.GPDMA1_CH1, spi_config); | ||
| 40 | |||
| 41 | let executor = EXECUTOR.init(Executor::new()); | ||
| 42 | |||
| 43 | executor.run(|spawner| { | ||
| 44 | unwrap!(spawner.spawn(main_task(spi))); | ||
| 45 | }) | ||
| 46 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart.rs b/examples/stm32h7rs/src/bin/usart.rs new file mode 100644 index 000000000..cc49c2fdb --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart.rs | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use cortex_m_rt::entry; | ||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Executor; | ||
| 7 | use embassy_stm32::usart::{Config, Uart}; | ||
| 8 | use static_cell::StaticCell; | ||
| 9 | use {defmt_rtt as _, panic_probe as _}; | ||
| 10 | |||
| 11 | #[embassy_executor::task] | ||
| 12 | async fn main_task() { | ||
| 13 | let p = embassy_stm32::init(Default::default()); | ||
| 14 | |||
| 15 | let config = Config::default(); | ||
| 16 | let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); | ||
| 17 | |||
| 18 | unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); | ||
| 19 | info!("wrote Hello, starting echo"); | ||
| 20 | |||
| 21 | let mut buf = [0u8; 1]; | ||
| 22 | loop { | ||
| 23 | unwrap!(usart.blocking_read(&mut buf)); | ||
| 24 | unwrap!(usart.blocking_write(&buf)); | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 29 | |||
| 30 | #[entry] | ||
| 31 | fn main() -> ! { | ||
| 32 | info!("Hello World!"); | ||
| 33 | |||
| 34 | let executor = EXECUTOR.init(Executor::new()); | ||
| 35 | |||
| 36 | executor.run(|spawner| { | ||
| 37 | unwrap!(spawner.spawn(main_task())); | ||
| 38 | }) | ||
| 39 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart_dma.rs b/examples/stm32h7rs/src/bin/usart_dma.rs new file mode 100644 index 000000000..c644e84bd --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_dma.rs | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use core::fmt::Write; | ||
| 5 | |||
| 6 | use cortex_m_rt::entry; | ||
| 7 | use defmt::*; | ||
| 8 | use embassy_executor::Executor; | ||
| 9 | use embassy_stm32::usart::{Config, Uart}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 11 | use heapless::String; | ||
| 12 | use static_cell::StaticCell; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 17 | }); | ||
| 18 | |||
| 19 | #[embassy_executor::task] | ||
| 20 | async fn main_task() { | ||
| 21 | let p = embassy_stm32::init(Default::default()); | ||
| 22 | |||
| 23 | let config = Config::default(); | ||
| 24 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); | ||
| 25 | |||
| 26 | for n in 0u32.. { | ||
| 27 | let mut s: String<128> = String::new(); | ||
| 28 | core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); | ||
| 29 | |||
| 30 | usart.write(s.as_bytes()).await.ok(); | ||
| 31 | |||
| 32 | info!("wrote DMA"); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | static EXECUTOR: StaticCell<Executor> = StaticCell::new(); | ||
| 37 | |||
| 38 | #[entry] | ||
| 39 | fn main() -> ! { | ||
| 40 | info!("Hello World!"); | ||
| 41 | |||
| 42 | let executor = EXECUTOR.init(Executor::new()); | ||
| 43 | |||
| 44 | executor.run(|spawner| { | ||
| 45 | unwrap!(spawner.spawn(main_task())); | ||
| 46 | }) | ||
| 47 | } | ||
diff --git a/examples/stm32h7rs/src/bin/usart_split.rs b/examples/stm32h7rs/src/bin/usart_split.rs new file mode 100644 index 000000000..77b4caa9e --- /dev/null +++ b/examples/stm32h7rs/src/bin/usart_split.rs | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::mode::Async; | ||
| 7 | use embassy_stm32::peripherals::UART7; | ||
| 8 | use embassy_stm32::usart::{Config, Uart, UartRx}; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, usart}; | ||
| 10 | use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; | ||
| 11 | use embassy_sync::channel::Channel; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | bind_interrupts!(struct Irqs { | ||
| 15 | UART7 => usart::InterruptHandler<peripherals::UART7>; | ||
| 16 | }); | ||
| 17 | |||
| 18 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | ||
| 19 | |||
| 20 | #[embassy_executor::main] | ||
| 21 | async fn main(spawner: Spawner) -> ! { | ||
| 22 | let p = embassy_stm32::init(Default::default()); | ||
| 23 | info!("Hello World!"); | ||
| 24 | |||
| 25 | let config = Config::default(); | ||
| 26 | let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); | ||
| 27 | unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); | ||
| 28 | |||
| 29 | let (mut tx, rx) = usart.split(); | ||
| 30 | |||
| 31 | unwrap!(spawner.spawn(reader(rx))); | ||
| 32 | |||
| 33 | loop { | ||
| 34 | let buf = CHANNEL.receive().await; | ||
| 35 | info!("writing..."); | ||
| 36 | unwrap!(tx.write(&buf).await); | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | #[embassy_executor::task] | ||
| 41 | async fn reader(mut rx: UartRx<'static, UART7, Async>) { | ||
| 42 | let mut buf = [0; 8]; | ||
| 43 | loop { | ||
| 44 | info!("reading..."); | ||
| 45 | unwrap!(rx.read(&mut buf).await); | ||
| 46 | CHANNEL.send(buf).await; | ||
| 47 | } | ||
| 48 | } | ||
