From fd901fc7e052cdf1b48327140d78712b1e076220 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 10 Apr 2024 10:49:42 +0300 Subject: stm32: update adc examples --- examples/stm32f0/src/bin/adc.rs | 6 +++--- examples/stm32f1/src/bin/adc.rs | 6 +++--- examples/stm32f334/src/bin/adc.rs | 6 +++--- examples/stm32f334/src/bin/opamp.rs | 6 +++--- examples/stm32f4/src/bin/adc.rs | 2 +- examples/stm32f7/src/bin/adc.rs | 4 ++-- examples/stm32g4/src/bin/adc.rs | 4 ++-- examples/stm32h7/src/bin/adc.rs | 4 ++-- examples/stm32l0/src/bin/adc.rs | 6 +++--- examples/stm32l4/src/bin/adc.rs | 3 +-- 10 files changed, 23 insertions(+), 24 deletions(-) (limited to 'examples') diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index c2fb143cd..a5a4186ea 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC, Irqs); adc.set_sample_time(SampleTime::CYCLES71_5); let mut pin = p.PA1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 1440460a9..541ff159e 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::peripherals::ADC1; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PB1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/CD00161566.pdf diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index bd126ce68..0528a9637 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! { info!("create adc..."); - let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC1, Irqs); adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); loop { diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index a5c710aa2..2dbf1bdab 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::peripherals::ADC2; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! { info!("create adc..."); - let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC2, Irqs); let mut opamp = OpAmp::new(p.OPAMP2); adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 699c29c05..9473b7b7f 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut delay = Delay; - let mut adc = Adc::new(p.ADC1, &mut delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PC1; let mut vrefint = adc.enable_vrefint(); diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index f8d7b691f..641157960 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PA3; let mut vrefint = adc.enable_vrefint(); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index ae64bc8e4..68b54e406 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(config); info!("Hello World!"); - let mut adc = Adc::new(p.ADC2, &mut Delay); + let mut adc = Adc::new(p.ADC2); adc.set_sample_time(SampleTime::CYCLES32_5); loop { diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index a5594d10c..0009103d1 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut adc = Adc::new(p.ADC3, &mut Delay); + let mut adc = Adc::new(p.ADC3); adc.set_sample_time(SampleTime::CYCLES32_5); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 97d41ca4b..507c3204a 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC, Irqs); adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index a9f4604aa..7a89334e0 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; -use embassy_time::Delay; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -18,7 +17,7 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); //adc.enable_vref(); adc.set_resolution(Resolution::BITS8); let mut channel = p.PC0; -- cgit From 9053b6b5b3a09e48ed5e2476a5f712c9796828d5 Mon Sep 17 00:00:00 2001 From: Vega Deftwing Date: Thu, 11 Apr 2024 19:45:38 +0000 Subject: Fix spelling and white space mistakes --- examples/boot/bootloader/stm32-dual-bank/README.md | 8 ++++---- examples/stm32f4/src/bin/ws2812_spi.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md index 3de3171cd..cd6c0bc84 100644 --- a/examples/boot/bootloader/stm32-dual-bank/README.md +++ b/examples/boot/bootloader/stm32-dual-bank/README.md @@ -2,16 +2,16 @@ ## Overview -This bootloader leverages `embassy-boot` to interact with the flash. -This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. +This bootloader leverages `embassy-boot` to interact with the flash. +This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. ## Memory Configuration -In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. -For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. +In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. +For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. ### Symbol Definitions diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index a280a3b77..56ccb67b8 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -8,7 +8,7 @@ // If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. // // Warning: -// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. +// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. #![no_std] #![no_main] -- cgit From 52bd24499c0e164fd3525a02514af50e3fc35424 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 03:30:30 +0200 Subject: stm32/adc: update g4 for new pac. --- examples/stm32g4/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 68b54e406..3de38cbd6 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC2); - adc.set_sample_time(SampleTime::CYCLES32_5); + adc.set_sample_time(SampleTime::CYCLES24_5); loop { let measured = adc.read(&mut p.PA7); -- cgit From ec6ff217ca0f895898ecc8e2cf84d503f71c988c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 02:13:41 +0200 Subject: Add stm32u0 support. --- examples/stm32u0/.cargo/config.toml | 9 +++++++++ examples/stm32u0/Cargo.toml | 25 +++++++++++++++++++++++++ examples/stm32u0/build.rs | 5 +++++ examples/stm32u0/src/bin/blinky.rs | 26 ++++++++++++++++++++++++++ examples/stm32u0/src/bin/button.rs | 24 ++++++++++++++++++++++++ examples/stm32u0/src/bin/button_exti.rs | 25 +++++++++++++++++++++++++ 6 files changed, 114 insertions(+) create mode 100644 examples/stm32u0/.cargo/config.toml create mode 100644 examples/stm32u0/Cargo.toml create mode 100644 examples/stm32u0/build.rs create mode 100644 examples/stm32u0/src/bin/blinky.rs create mode 100644 examples/stm32u0/src/bin/button.rs create mode 100644 examples/stm32u0/src/bin/button_exti.rs (limited to 'examples') diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml new file mode 100644 index 000000000..c8022ae39 --- /dev/null +++ b/examples/stm32u0/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --speed 100 --chip STM32u083rctx" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml new file mode 100644 index 000000000..af3d7ff61 --- /dev/null +++ b/examples/stm32u0/Cargo.toml @@ -0,0 +1,25 @@ +[package] +edition = "2021" +name = "embassy-stm32u0-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32c031c6 to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.8", default-features = false } + +[profile.release] +debug = 2 diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32u0/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs new file mode 100644 index 000000000..90e479aae --- /dev/null +++ b/examples/stm32u0/src/bin/blinky.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PA5, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + } +} diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs new file mode 100644 index 000000000..8017f0274 --- /dev/null +++ b/examples/stm32u0/src/bin/button.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PC13, Pull::Up); + + loop { + if button.is_high() { + info!("high"); + } else { + info!("low"); + } + } +} diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32u0/src/bin/button_exti.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} -- cgit From af03e1653a711e12566ee7cac2d018e94b1d267b Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 13 Apr 2024 14:07:01 +0200 Subject: Disable the speed limitation --- examples/stm32u0/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml index c8022ae39..28b8af96e 100644 --- a/examples/stm32u0/.cargo/config.toml +++ b/examples/stm32u0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --speed 100 --chip STM32u083rctx" +runner = "probe-rs run --chip STM32u083rctx" [build] target = "thumbv6m-none-eabi" -- cgit From 5f23e3905226551a001da9bf4051c6efb552f636 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sat, 13 Apr 2024 18:40:46 +0200 Subject: Add some examples. - usart works - dac works - rng gets stuck on while loop - usb_serial works, but cannot test due to lack of user usb port - adc needs work and does not work yet --- examples/stm32u0/Cargo.toml | 3 + examples/stm32u0/src/bin/adc.rs | 33 ++++++++++ examples/stm32u0/src/bin/dac.rs | 35 +++++++++++ examples/stm32u0/src/bin/rng.rs | 41 +++++++++++++ examples/stm32u0/src/bin/usart.rs | 31 ++++++++++ examples/stm32u0/src/bin/usb_serial.rs | 109 +++++++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+) create mode 100644 examples/stm32u0/src/bin/adc.rs create mode 100644 examples/stm32u0/src/bin/dac.rs create mode 100644 examples/stm32u0/src/bin/rng.rs create mode 100644 examples/stm32u0/src/bin/usart.rs create mode 100644 examples/stm32u0/src/bin/usb_serial.rs (limited to 'examples') diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index af3d7ff61..8219cb038 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -10,6 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" @@ -21,5 +22,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } +micromath = "2.0.0" + [profile.release] debug = 2 diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs new file mode 100644 index 000000000..f7145b85d --- /dev/null +++ b/examples/stm32u0/src/bin/adc.rs @@ -0,0 +1,33 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::adc::{Adc, Resolution}; +use embassy_stm32::Config; +use embassy_time::Duration; +use {defmt_rtt as _, panic_probe as _}; + +#[cortex_m_rt::entry] +fn main() -> ! { + info!("Hello World!"); + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.mux.adcsel = mux::Adcsel::SYS; + } + let p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + let mut temp = adc.enable_temperature(); + adc.set_resolution(Resolution::BITS8); + let mut channel = p.PC0; + + loop { + let v = adc.read(&mut channel); + info!("--> {}", v); + let v = adc.read(&mut temp); + info!("Temp: --> {}", v); + embassy_time::block_for(Duration::from_millis(1000)); + } +} diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs new file mode 100644 index 000000000..fdbf1d374 --- /dev/null +++ b/examples/stm32u0/src/bin/dac.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::dac::{DacCh1, Value}; +use embassy_stm32::dma::NoDma; +use {defmt_rtt as _, panic_probe as _}; + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + + loop { + for v in 0..=255 { + dac.set(Value::Bit8(to_sine_wave(v))); + } + } +} + +use micromath::F32Ext; + +fn to_sine_wave(v: u8) -> u8 { + if v >= 128 { + // top half + let r = 3.14 * ((v - 128) as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } else { + // bottom half + let r = 3.14 + 3.14 * (v as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } +} diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs new file mode 100644 index 000000000..9b4c2537e --- /dev/null +++ b/examples/stm32u0/src/bin/rng.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RNG_CRYP => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL7, // 16 * 7 = 112 MHz + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz + }); + config.rcc.sys = Sysclk::PLL1_R; + } + + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut rng = Rng::new(p.RNG, Irqs); + info!("Hello World 2!"); + + let mut buf = [0u8; 16]; + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); +} diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs new file mode 100644 index 000000000..1fcf0029a --- /dev/null +++ b/examples/stm32u0/src/bin/usart.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::dma::NoDma; +use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USART2_LPUART2 => usart::InterruptHandler; +}); + +#[cortex_m_rt::entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.USART2, p.PA3, p.PA2, Irqs, NoDma, NoDma, config).unwrap(); + + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs new file mode 100644 index 000000000..9b38fd5dc --- /dev/null +++ b/examples/stm32u0/src/bin/usb_serial.rs @@ -0,0 +1,109 @@ +#![no_std] +#![no_main] + +use defmt::{panic, *}; +use defmt_rtt as _; // global logger +use embassy_executor::Spawner; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use futures::future::join; +use panic_probe as _; + +bind_interrupts!(struct Irqs { + USB_DRD_FS => usb::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL7, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), // 56 MHz + }); + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.clk48sel = mux::Clk48sel::HSI48; // USB uses ICLK + } + + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); + + // Create embassy-usb Config + let config = embassy_usb::Config::new(0xc0de, 0xcafe); + //config.max_packet_size_0 = 64; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 7]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} -- cgit From b659e3d529e427cfc2fb38f514825b60eded784f Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sun, 14 Apr 2024 00:04:13 +0200 Subject: Add ADC --- examples/stm32u0/src/bin/adc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index f7145b85d..c63c4a428 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -26,8 +26,6 @@ fn main() -> ! { loop { let v = adc.read(&mut channel); info!("--> {}", v); - let v = adc.read(&mut temp); - info!("Temp: --> {}", v); - embassy_time::block_for(Duration::from_millis(1000)); + embassy_time::block_for(Duration::from_millis(200)); } } -- cgit From 0a785585bcc268ca1eb5341b1bcc54113cf96298 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sun, 14 Apr 2024 00:08:06 +0200 Subject: Remove temp variable --- examples/stm32u0/src/bin/adc.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/adc.rs b/examples/stm32u0/src/bin/adc.rs index c63c4a428..4410448f1 100644 --- a/examples/stm32u0/src/bin/adc.rs +++ b/examples/stm32u0/src/bin/adc.rs @@ -19,7 +19,6 @@ fn main() -> ! { let p = embassy_stm32::init(config); let mut adc = Adc::new(p.ADC1); - let mut temp = adc.enable_temperature(); adc.set_resolution(Resolution::BITS8); let mut channel = p.PC0; -- cgit From ca84be80bcbfb4459212fa02e75cfafc85d6df51 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sun, 14 Apr 2024 00:45:53 +0200 Subject: Add wdt and flash --- examples/stm32u0/src/bin/flash.rs | 43 +++++++++++++++++++++++++++++++++++++++ examples/stm32u0/src/bin/wdt.rs | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 examples/stm32u0/src/bin/flash.rs create mode 100644 examples/stm32u0/src/bin/wdt.rs (limited to 'examples') diff --git a/examples/stm32u0/src/bin/flash.rs b/examples/stm32u0/src/bin/flash.rs new file mode 100644 index 000000000..01b80a76b --- /dev/null +++ b/examples/stm32u0/src/bin/flash.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::flash::Flash; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let addr: u32 = 0x40000 - 2 * 1024; + + let mut f = Flash::new_blocking(p.FLASH).into_blocking_regions().bank1_region; + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(addr, &mut buf)); + info!("Read: {=[u8]:x}", buf); + info!("Erasing..."); + unwrap!(f.blocking_erase(addr, addr + 2 * 1024)); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(addr, &mut buf)); + info!("Read after erase: {=[u8]:x}", buf); + + info!("Writing..."); + unwrap!(f.blocking_write( + addr, + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32 + ] + )); + + info!("Reading..."); + let mut buf = [0u8; 32]; + unwrap!(f.blocking_read(addr, &mut buf)); + info!("Read: {=[u8]:x}", buf); +} diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs new file mode 100644 index 000000000..f6276e2e9 --- /dev/null +++ b/examples/stm32u0/src/bin/wdt.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::wdg::IndependentWatchdog; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PA5, Level::High, Speed::Low); + + let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); + wdt.unleash(); + + let mut i = 0; + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + + // Pet watchdog for 5 iterations and then stop. + // MCU should restart in 1 second after the last pet. + if i < 5 { + info!("Petting watchdog"); + wdt.pet(); + } + + i += 1; + } +} -- cgit From e224e6cef4e0508f14bb9ffd1d9d0fc9220c07d8 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Sun, 14 Apr 2024 01:10:20 +0200 Subject: Add CRC --- examples/stm32u0/src/bin/crc.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/stm32u0/src/bin/crc.rs (limited to 'examples') diff --git a/examples/stm32u0/src/bin/crc.rs b/examples/stm32u0/src/bin/crc.rs new file mode 100644 index 000000000..d1b545d5b --- /dev/null +++ b/examples/stm32u0/src/bin/crc.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0 + let mut crc = Crc::new( + p.CRC, + unwrap!(Config::new( + InputReverseConfig::Byte, + true, + PolySize::Width32, + 0xFFFFFFFF, + 0x04C11DB7 + )), + ); + + let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF; + + defmt::assert_eq!(output, 0x33F0E26B); + + cortex_m::asm::bkpt(); +} -- cgit From 4079a8acf8d0d33dc1ca815475492cbf33407464 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 03:30:30 +0200 Subject: stm32/adc: update g4 for new pac. --- examples/stm32g4/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 68b54e406..3de38cbd6 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC2); - adc.set_sample_time(SampleTime::CYCLES32_5); + adc.set_sample_time(SampleTime::CYCLES24_5); loop { let measured = adc.read(&mut p.PA7); -- cgit From 65c085ce910f50903bc5c41ca82eda989810f855 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 02:13:41 +0200 Subject: Add stm32u0 support. --- examples/stm32u0/.cargo/config.toml | 9 +++++++++ examples/stm32u0/Cargo.toml | 25 +++++++++++++++++++++++++ examples/stm32u0/build.rs | 5 +++++ examples/stm32u0/src/bin/blinky.rs | 26 ++++++++++++++++++++++++++ examples/stm32u0/src/bin/button.rs | 24 ++++++++++++++++++++++++ examples/stm32u0/src/bin/button_exti.rs | 25 +++++++++++++++++++++++++ 6 files changed, 114 insertions(+) create mode 100644 examples/stm32u0/.cargo/config.toml create mode 100644 examples/stm32u0/Cargo.toml create mode 100644 examples/stm32u0/build.rs create mode 100644 examples/stm32u0/src/bin/blinky.rs create mode 100644 examples/stm32u0/src/bin/button.rs create mode 100644 examples/stm32u0/src/bin/button_exti.rs (limited to 'examples') diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml new file mode 100644 index 000000000..688347084 --- /dev/null +++ b/examples/stm32u0/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace stm32u083rctx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip stm32u083rctx" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml new file mode 100644 index 000000000..495be3e75 --- /dev/null +++ b/examples/stm32u0/Cargo.toml @@ -0,0 +1,25 @@ +[package] +edition = "2021" +name = "embassy-stm32u0-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32u083rc to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.8", default-features = false } + +[profile.release] +debug = 2 diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32u0/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs new file mode 100644 index 000000000..90e479aae --- /dev/null +++ b/examples/stm32u0/src/bin/blinky.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PA5, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + } +} diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs new file mode 100644 index 000000000..8017f0274 --- /dev/null +++ b/examples/stm32u0/src/bin/button.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PC13, Pull::Up); + + loop { + if button.is_high() { + info!("high"); + } else { + info!("low"); + } + } +} diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32u0/src/bin/button_exti.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} -- cgit From 9341ef3b47f67b549b3d202974a2d4a0d62587f1 Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Sun, 14 Apr 2024 16:06:21 +0200 Subject: examples: request_handler is mutable --- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 8 ++++---- examples/nrf52840/src/bin/usb_hid_mouse.rs | 6 +++--- examples/rp/src/bin/usb_hid_keyboard.rs | 8 ++++---- examples/rp/src/bin/usb_hid_mouse.rs | 8 ++++---- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 8 ++++---- examples/stm32f4/src/bin/usb_hid_mouse.rs | 6 +++--- examples/stm32l5/src/bin/usb_hid_mouse.rs | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) (limited to 'examples') diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 52f081487..39b39dcd0 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut device_handler = MyDeviceHandler::new(); let mut state = State::new(); @@ -73,7 +73,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: KeyboardReport::desc(), - request_handler: Some(&request_handler), + request_handler: None, poll_ms: 60, max_packet_size: 64, }; @@ -137,7 +137,7 @@ async fn main(_spawner: Spawner) { }; let out_fut = async { - reader.run(false, &request_handler).await; + reader.run(false, &mut request_handler).await; }; // Run everything concurrently. @@ -153,7 +153,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 5d2837793..d86e96270 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { let mut bos_descriptor = [0; 256]; let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut state = State::new(); @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: MouseReport::desc(), - request_handler: Some(&request_handler), + request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, }; @@ -110,7 +110,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index 710be8d13..53385e929 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -41,7 +41,7 @@ async fn main(_spawner: Spawner) { // You can also add a Microsoft OS descriptor. let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut device_handler = MyDeviceHandler::new(); let mut state = State::new(); @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: KeyboardReport::desc(), - request_handler: Some(&request_handler), + request_handler: None, poll_ms: 60, max_packet_size: 64, }; @@ -114,7 +114,7 @@ async fn main(_spawner: Spawner) { }; let out_fut = async { - reader.run(false, &request_handler).await; + reader.run(false, &mut request_handler).await; }; // Run everything concurrently. @@ -130,7 +130,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index e8b399cb1..3c911511e 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { // You can also add a Microsoft OS descriptor. let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut device_handler = MyDeviceHandler::new(); let mut state = State::new(); @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: MouseReport::desc(), - request_handler: Some(&request_handler), + request_handler: None, poll_ms: 60, max_packet_size: 64, }; @@ -106,7 +106,7 @@ async fn main(_spawner: Spawner) { }; let out_fut = async { - reader.run(false, &request_handler).await; + reader.run(false, &mut request_handler).await; }; // Run everything concurrently. @@ -122,7 +122,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index d6e0be5ea..709f3dccc 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -76,7 +76,7 @@ async fn main(_spawner: Spawner) { let mut msos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut device_handler = MyDeviceHandler::new(); let mut state = State::new(); @@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: KeyboardReport::desc(), - request_handler: Some(&request_handler), + request_handler: None, poll_ms: 60, max_packet_size: 8, }; @@ -148,7 +148,7 @@ async fn main(_spawner: Spawner) { }; let out_fut = async { - reader.run(false, &request_handler).await; + reader.run(false, &mut request_handler).await; }; // Run everything concurrently. @@ -164,7 +164,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 0bc236119..0d08d34a2 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -68,7 +68,7 @@ async fn main(_spawner: Spawner) { let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut state = State::new(); @@ -84,7 +84,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: MouseReport::desc(), - request_handler: Some(&request_handler), + request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, }; @@ -131,7 +131,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 9d30205bb..b340c5df5 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let request_handler = MyRequestHandler {}; + let mut request_handler = MyRequestHandler {}; let mut state = State::new(); @@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) { // Create classes on the builder. let config = embassy_usb::class::hid::Config { report_descriptor: MouseReport::desc(), - request_handler: Some(&request_handler), + request_handler: Some(&mut request_handler), poll_ms: 60, max_packet_size: 8, }; @@ -117,7 +117,7 @@ impl RequestHandler for MyRequestHandler { None } - fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse { + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { info!("Set report for {:?}: {=[u8]}", id, data); OutResponse::Accepted } -- cgit From ae4fb433aef33cfc7993516f880de85d87fa37d8 Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Mon, 15 Apr 2024 19:53:46 +0200 Subject: usb-hid: all the RequestHandler method accept &mut self --- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 6 +++--- examples/nrf52840/src/bin/usb_hid_mouse.rs | 6 +++--- examples/rp/src/bin/usb_hid_keyboard.rs | 6 +++--- examples/rp/src/bin/usb_hid_mouse.rs | 6 +++--- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 6 +++--- examples/stm32f4/src/bin/usb_hid_mouse.rs | 6 +++--- examples/stm32l5/src/bin/usb_hid_mouse.rs | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) (limited to 'examples') diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 39b39dcd0..e33ee5866 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -148,7 +148,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -158,11 +158,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index d86e96270..8076ac283 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -105,7 +105,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -115,11 +115,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index 53385e929..a7cb322d8 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -125,7 +125,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -135,11 +135,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index 3c911511e..cce344fb0 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -117,7 +117,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -127,11 +127,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 709f3dccc..f6d1395e8 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -159,7 +159,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -169,11 +169,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 0d08d34a2..2cff9294a 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -126,7 +126,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -136,11 +136,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index b340c5df5..3f8c52b82 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -112,7 +112,7 @@ async fn main(_spawner: Spawner) { struct MyRequestHandler {} impl RequestHandler for MyRequestHandler { - fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { info!("Get report for {:?}", id); None } @@ -122,11 +122,11 @@ impl RequestHandler for MyRequestHandler { OutResponse::Accepted } - fn set_idle_ms(&self, id: Option, dur: u32) { + fn set_idle_ms(&mut self, id: Option, dur: u32) { info!("Set idle rate for {:?} to {:?}", id, dur); } - fn get_idle_ms(&self, id: Option) -> Option { + fn get_idle_ms(&mut self, id: Option) -> Option { info!("Get idle rate for {:?}", id); None } -- cgit From be087e5d43326178878878bebae96f3b51a3b184 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 15 Apr 2024 21:19:17 +0200 Subject: stm32/spi: remove DMA generic params. --- examples/stm32f4/src/bin/spi.rs | 3 +-- examples/stm32f4/src/bin/ws2812_spi.rs | 4 ++-- examples/stm32g0/src/bin/spi_neopixel.rs | 3 +-- examples/stm32h7/src/bin/spi.rs | 6 +++--- examples/stm32h7/src/bin/spi_dma.rs | 6 +++--- examples/stm32l0/src/bin/spi.rs | 3 +-- examples/stm32l1/src/bin/spi.rs | 3 +-- .../stm32l4/src/bin/spe_adin1110_http_server.rs | 24 ++++++++++------------ examples/stm32l4/src/bin/spi.rs | 3 +-- examples/stm32l4/src/bin/spi_blocking_async.rs | 3 +-- 10 files changed, 25 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs index dc9141c62..970d819fc 100644 --- a/examples/stm32f4/src/bin/spi.rs +++ b/examples/stm32f4/src/bin/spi.rs @@ -3,7 +3,6 @@ use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; @@ -18,7 +17,7 @@ fn main() -> ! { let mut spi_config = Config::default(); spi_config.frequency = Hertz(1_000_000); - let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); + let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index 56ccb67b8..e00d14327 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -13,8 +13,8 @@ #![no_std] #![no_main] +use embassy_stm32::spi; use embassy_stm32::time::khz; -use embassy_stm32::{dma, spi}; use embassy_time::{Duration, Ticker, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -78,7 +78,7 @@ async fn main(_spawner: embassy_executor::Spawner) { spi_config.frequency = khz(12_800); // Since we only output waveform, then the Rx and Sck and RxDma it is not considered - let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, dma::NoDma, spi_config); + let mut ws2812_spi = spi::Spi::new_txonly_nosck(dp.SPI1, dp.PB5, dp.DMA2_CH3, spi_config); // flip color at 2 Hz let mut ticker = Ticker::every(Duration::from_millis(500)); diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs index c5ea51721..2deee271d 100644 --- a/examples/stm32g0/src/bin/spi_neopixel.rs +++ b/examples/stm32g0/src/bin/spi_neopixel.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::word::U5; -use embassy_stm32::dma::NoDma; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; use embassy_time::Timer; @@ -77,7 +76,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.frequency = Hertz(4_000_000); - let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, NoDma, config); + let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config); let mut neopixels = Ws2812::new(); diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index aed27723a..aaebdc346 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -7,7 +7,7 @@ use core::str::from_utf8; use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::dma::NoDma; +use embassy_stm32::mode::Blocking; use embassy_stm32::peripherals::SPI3; use embassy_stm32::time::mhz; use embassy_stm32::{spi, Config}; @@ -16,7 +16,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, NoDma, NoDma>) { +async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); @@ -62,7 +62,7 @@ fn main() -> ! { let mut spi_config = spi::Config::default(); spi_config.frequency = mhz(1); - let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, NoDma, NoDma, spi_config); + let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); let executor = EXECUTOR.init(Executor::new()); diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 54d4d7656..3d3c724eb 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -7,15 +7,15 @@ use core::str::from_utf8; use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::peripherals::{DMA1_CH3, DMA1_CH4, SPI3}; +use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{spi, Config}; +use embassy_stm32::{peripherals, spi, Config}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, DMA1_CH3, DMA1_CH4>) { +async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32l0/src/bin/spi.rs b/examples/stm32l0/src/bin/spi.rs index f23a537b8..8e0cfdedb 100644 --- a/examples/stm32l0/src/bin/spi.rs +++ b/examples/stm32l0/src/bin/spi.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; @@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) { let mut spi_config = Config::default(); spi_config.frequency = Hertz(1_000_000); - let mut spi = Spi::new(p.SPI1, p.PB3, p.PA7, p.PA6, NoDma, NoDma, spi_config); + let mut spi = Spi::new_blocking(p.SPI1, p.PB3, p.PA7, p.PA6, spi_config); let mut cs = Output::new(p.PA15, Level::High, Speed::VeryHigh); diff --git a/examples/stm32l1/src/bin/spi.rs b/examples/stm32l1/src/bin/spi.rs index 8be686c5a..eabf1bac2 100644 --- a/examples/stm32l1/src/bin/spi.rs +++ b/examples/stm32l1/src/bin/spi.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; @@ -17,7 +16,7 @@ async fn main(_spawner: Spawner) { let mut spi_config = Config::default(); spi_config.frequency = Hertz(1_000_000); - let mut spi = Spi::new(p.SPI1, p.PA5, p.PA7, p.PA6, NoDma, NoDma, spi_config); + let mut spi = Spi::new_blocking(p.SPI1, p.PA5, p.PA7, p.PA6, spi_config); let mut cs = Output::new(p.PA4, Level::High, Speed::VeryHigh); diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 77aa929ab..a99d08924 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -23,18 +23,23 @@ use embassy_futures::select::{select, Either}; use embassy_futures::yield_now; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources, StaticConfigV4}; +use embassy_net_adin1110::{Device, Runner, ADIN1110}; +use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; +use embassy_stm32::i2c::{self, Config as I2C_Config, I2c}; +use embassy_stm32::mode::Async; +use embassy_stm32::rng::{self, Rng}; +use embassy_stm32::spi::{Config as SPI_Config, Spi}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, exti, pac, peripherals}; use embassy_time::{Delay, Duration, Ticker, Timer}; use embedded_hal_async::i2c::I2c as I2cBus; +use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io::Write as bWrite; use embedded_io_async::Write; -use hal::gpio::{Input, Level, Output, Speed}; -use hal::i2c::{self, I2c}; -use hal::rng::{self, Rng}; -use hal::{bind_interrupts, exti, pac, peripherals}; use heapless::Vec; +use panic_probe as _; use rand::RngCore; use static_cell::StaticCell; -use {embassy_stm32 as hal, panic_probe as _}; bind_interrupts!(struct Irqs { I2C3_EV => i2c::EventInterruptHandler; @@ -42,13 +47,6 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -use embassy_net_adin1110::{Device, Runner, ADIN1110}; -use embedded_hal_bus::spi::ExclusiveDevice; -use hal::gpio::Pull; -use hal::i2c::Config as I2C_Config; -use hal::spi::{Config as SPI_Config, Spi}; -use hal::time::Hertz; - // Basic settings // MAC-address used by the adin1110 const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; @@ -57,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); // Listen port for the webserver const HTTP_LISTEN_PORT: u16 = 80; -pub type SpeSpi = Spi<'static, peripherals::SPI2, peripherals::DMA1_CH1, peripherals::DMA1_CH2>; +pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>; pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; diff --git a/examples/stm32l4/src/bin/spi.rs b/examples/stm32l4/src/bin/spi.rs index 6653e4516..5693a3765 100644 --- a/examples/stm32l4/src/bin/spi.rs +++ b/examples/stm32l4/src/bin/spi.rs @@ -2,7 +2,6 @@ #![no_main] use defmt::*; -use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; @@ -17,7 +16,7 @@ fn main() -> ! { let mut spi_config = Config::default(); spi_config.frequency = Hertz(1_000_000); - let mut spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); + let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); diff --git a/examples/stm32l4/src/bin/spi_blocking_async.rs b/examples/stm32l4/src/bin/spi_blocking_async.rs index 68dbb70ad..1f1089101 100644 --- a/examples/stm32l4/src/bin/spi_blocking_async.rs +++ b/examples/stm32l4/src/bin/spi_blocking_async.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::spi::{Config, Spi}; use embassy_stm32::time::Hertz; @@ -19,7 +18,7 @@ async fn main(_spawner: Spawner) { let mut spi_config = Config::default(); spi_config.frequency = Hertz(1_000_000); - let spi = Spi::new(p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, spi_config); + let spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); let mut spi = BlockingAsync::new(spi); -- cgit From 913bb19a34b88e996972c6666679b2b99ae01ce0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 15 Apr 2024 23:40:12 +0200 Subject: stm32/i2c: remove DMA generic params. --- examples/stm32f4/src/bin/i2c.rs | 18 +----------------- examples/stm32l4/src/bin/i2c.rs | 18 +----------------- examples/stm32l4/src/bin/i2c_blocking_async.rs | 18 +----------------- examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 2 +- examples/stm32u5/src/bin/i2c.rs | 18 +----------------- 5 files changed, 5 insertions(+), 69 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index 4b5da774d..4a96357a4 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs @@ -3,35 +3,19 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::{Error, I2c}; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; -bind_interrupts!(struct Irqs { - I2C2_EV => i2c::EventInterruptHandler; - I2C2_ER => i2c::ErrorInterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); - let mut i2c = I2c::new( - p.I2C2, - p.PB10, - p.PB11, - Irqs, - NoDma, - NoDma, - Hertz(100_000), - Default::default(), - ); + let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); let mut data = [0u8; 1]; diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs index f553deb82..2861bc091 100644 --- a/examples/stm32l4/src/bin/i2c.rs +++ b/examples/stm32l4/src/bin/i2c.rs @@ -3,33 +3,17 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::I2c; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; -bind_interrupts!(struct Irqs { - I2C2_EV => i2c::EventInterruptHandler; - I2C2_ER => i2c::ErrorInterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut i2c = I2c::new( - p.I2C2, - p.PB10, - p.PB11, - Irqs, - NoDma, - NoDma, - Hertz(100_000), - Default::default(), - ); + let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); let mut data = [0u8; 1]; unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index 1b8652bcc..a014b23e0 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs @@ -4,34 +4,18 @@ use defmt::*; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::I2c; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embedded_hal_async::i2c::I2c as I2cTrait; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; -bind_interrupts!(struct Irqs { - I2C2_EV => i2c::EventInterruptHandler; - I2C2_ER => i2c::ErrorInterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let i2c = I2c::new( - p.I2C2, - p.PB10, - p.PB11, - Irqs, - NoDma, - NoDma, - Hertz(100_000), - Default::default(), - ); + let i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); let mut i2c = BlockingAsync::new(i2c); let mut data = [0u8; 1]; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index a99d08924..694629ede 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -60,7 +60,7 @@ pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; pub type Adin1110T = ADIN1110; -pub type TempSensI2c = I2c<'static, peripherals::I2C3, peripherals::DMA1_CH6, peripherals::DMA1_CH7>; +pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>; static TEMP: AtomicI32 = AtomicI32::new(0); diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs index e376c6bc8..19a78eac9 100644 --- a/examples/stm32u5/src/bin/i2c.rs +++ b/examples/stm32u5/src/bin/i2c.rs @@ -3,33 +3,17 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::i2c::I2c; use embassy_stm32::time::Hertz; -use embassy_stm32::{bind_interrupts, i2c, peripherals}; use {defmt_rtt as _, panic_probe as _}; const HTS221_ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; -bind_interrupts!(struct Irqs { - I2C2_EV => i2c::EventInterruptHandler; - I2C2_ER => i2c::ErrorInterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut i2c = I2c::new( - p.I2C2, - p.PH4, - p.PH5, - Irqs, - NoDma, - NoDma, - Hertz(100_000), - Default::default(), - ); + let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default()); let mut data = [0u8; 1]; unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); -- cgit From c5119c6318f72a69f1bdfb91e7987dff954d6c1e Mon Sep 17 00:00:00 2001 From: Warren Campbell Date: Mon, 15 Apr 2024 17:32:44 -0400 Subject: Add support for using secure registers --- examples/stm32u5/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'examples') diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 03294339d..01320b88d 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -24,5 +24,9 @@ heapless = { version = "0.8", default-features = false } micromath = "2.0.0" +[features] +## Use secure registers when TrustZone is enabled +trustzone-secure = ["embassy-stm32/trustzone-secure"] + [profile.release] debug = 2 -- cgit From d6b1233f16407e3501efcd1885460645a75ed57b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 16 Apr 2024 02:00:43 +0200 Subject: stm32/usart: remove DMA generic params. --- examples/stm32f3/src/bin/usart_dma.rs | 3 +-- examples/stm32f4/src/bin/usart.rs | 3 +-- examples/stm32f4/src/bin/usart_dma.rs | 3 +-- examples/stm32f7/src/bin/usart_dma.rs | 3 +-- examples/stm32h5/src/bin/usart.rs | 8 +------- examples/stm32h5/src/bin/usart_dma.rs | 3 +-- examples/stm32h5/src/bin/usart_split.rs | 18 +++--------------- examples/stm32h7/src/bin/usart.rs | 8 +------- examples/stm32h7/src/bin/usart_dma.rs | 3 +-- examples/stm32h7/src/bin/usart_split.rs | 18 +++--------------- examples/stm32l4/src/bin/usart.rs | 3 +-- examples/stm32l4/src/bin/usart_dma.rs | 3 +-- 12 files changed, 16 insertions(+), 60 deletions(-) (limited to 'examples') diff --git a/examples/stm32f3/src/bin/usart_dma.rs b/examples/stm32f3/src/bin/usart_dma.rs index 5234e53b9..573a49f19 100644 --- a/examples/stm32f3/src/bin/usart_dma.rs +++ b/examples/stm32f3/src/bin/usart_dma.rs @@ -5,7 +5,6 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, NoDma, config).unwrap(); + let mut usart = Uart::new(p.USART1, p.PE1, p.PE0, Irqs, p.DMA1_CH4, p.DMA1_CH5, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs index 40d9d70f1..991bf6673 100644 --- a/examples/stm32f4/src/bin/usart.rs +++ b/examples/stm32f4/src/bin/usart.rs @@ -3,7 +3,6 @@ use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +18,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, NoDma, NoDma, config).unwrap(); + let mut usart = Uart::new_blocking(p.USART3, p.PD9, p.PD8, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs index dd6de599c..aaf8d6c4f 100644 --- a/examples/stm32f4/src/bin/usart_dma.rs +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -5,7 +5,6 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, Irqs, p.DMA1_CH3, p.DMA1_CH1, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32f7/src/bin/usart_dma.rs b/examples/stm32f7/src/bin/usart_dma.rs index fb604b34f..47456adf2 100644 --- a/examples/stm32f7/src/bin/usart_dma.rs +++ b/examples/stm32f7/src/bin/usart_dma.rs @@ -5,7 +5,6 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -19,7 +18,7 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, NoDma, config).unwrap(); + let mut usart = Uart::new(p.UART7, p.PA8, p.PA15, Irqs, p.DMA1_CH1, p.DMA1_CH3, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h5/src/bin/usart.rs b/examples/stm32h5/src/bin/usart.rs index f9cbad6af..cc49c2fdb 100644 --- a/examples/stm32h5/src/bin/usart.rs +++ b/examples/stm32h5/src/bin/usart.rs @@ -4,22 +4,16 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { - UART7 => usart::InterruptHandler; -}); - #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); + let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h5/src/bin/usart_dma.rs b/examples/stm32h5/src/bin/usart_dma.rs index caae0dd18..c644e84bd 100644 --- a/examples/stm32h5/src/bin/usart_dma.rs +++ b/examples/stm32h5/src/bin/usart_dma.rs @@ -6,7 +6,6 @@ use core::fmt::Write; use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -22,7 +21,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, NoDma, config).unwrap(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index 92047de8d..77b4caa9e 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; -use embassy_stm32::peripherals::{GPDMA1_CH1, UART7}; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::UART7; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs { UART7 => usart::InterruptHandler; }); -#[embassy_executor::task] -async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { - unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); - info!("wrote Hello, starting echo"); - - let mut buf = [0u8; 1]; - loop { - unwrap!(usart.blocking_read(&mut buf)); - unwrap!(usart.blocking_write(&buf)); - } -} - static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] @@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART7, GPDMA1_CH1>) { +async fn reader(mut rx: UartRx<'static, UART7, Async>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/stm32h7/src/bin/usart.rs b/examples/stm32h7/src/bin/usart.rs index f9cbad6af..cc49c2fdb 100644 --- a/examples/stm32h7/src/bin/usart.rs +++ b/examples/stm32h7/src/bin/usart.rs @@ -4,22 +4,16 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { - UART7 => usart::InterruptHandler; -}); - #[embassy_executor::task] async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, NoDma, NoDma, config).unwrap(); + let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32h7/src/bin/usart_dma.rs b/examples/stm32h7/src/bin/usart_dma.rs index ae1f3a2e9..6f340d40a 100644 --- a/examples/stm32h7/src/bin/usart_dma.rs +++ b/examples/stm32h7/src/bin/usart_dma.rs @@ -6,7 +6,6 @@ use core::fmt::Write; use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -22,7 +21,7 @@ async fn main_task() { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, NoDma, config).unwrap(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.DMA1_CH0, p.DMA1_CH1, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index b98c40877..4ad8e77ce 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -3,8 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; -use embassy_stm32::peripherals::{DMA1_CH1, UART7}; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::UART7; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -15,18 +15,6 @@ bind_interrupts!(struct Irqs { UART7 => usart::InterruptHandler; }); -#[embassy_executor::task] -async fn writer(mut usart: Uart<'static, UART7, NoDma, NoDma>) { - unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); - info!("wrote Hello, starting echo"); - - let mut buf = [0u8; 1]; - loop { - unwrap!(usart.blocking_read(&mut buf)); - unwrap!(usart.blocking_write(&buf)); - } -} - static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] @@ -50,7 +38,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART7, DMA1_CH1>) { +async fn reader(mut rx: UartRx<'static, UART7, Async>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/stm32l4/src/bin/usart.rs b/examples/stm32l4/src/bin/usart.rs index 7bab23950..d9b388026 100644 --- a/examples/stm32l4/src/bin/usart.rs +++ b/examples/stm32l4/src/bin/usart.rs @@ -2,7 +2,6 @@ #![no_main] use defmt::*; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; @@ -18,7 +17,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, NoDma, NoDma, config).unwrap(); + let mut usart = Uart::new_blocking(p.UART4, p.PA1, p.PA0, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l4/src/bin/usart_dma.rs b/examples/stm32l4/src/bin/usart_dma.rs index 031888f70..b4f7a1643 100644 --- a/examples/stm32l4/src/bin/usart_dma.rs +++ b/examples/stm32l4/src/bin/usart_dma.rs @@ -5,7 +5,6 @@ use core::fmt::Write; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use heapless::String; @@ -21,7 +20,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let config = Config::default(); - let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, NoDma, config).unwrap(); + let mut usart = Uart::new(p.UART4, p.PA1, p.PA0, Irqs, p.DMA1_CH3, p.DMA1_CH4, config).unwrap(); for n in 0u32.. { let mut s: String<128> = String::new(); -- cgit From 53cb84d3d65b96b5f92f434b113cffe62810c0ad Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 16 Apr 2024 15:24:20 +0200 Subject: Added RTC example --- examples/stm32u0/Cargo.toml | 3 ++- examples/stm32u0/src/bin/rtc.rs | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 examples/stm32u0/src/bin/rtc.rs (limited to 'examples') diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 64fd837a2..5868372dd 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } @@ -23,6 +23,7 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.8", default-features = false } micromath = "2.0.0" +chrono = { version = "0.4.38", default-features = false } [profile.release] debug = 2 diff --git a/examples/stm32u0/src/bin/rtc.rs b/examples/stm32u0/src/bin/rtc.rs new file mode 100644 index 000000000..72fa0fde4 --- /dev/null +++ b/examples/stm32u0/src/bin/rtc.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use chrono::{NaiveDate, NaiveDateTime}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.hsi = true; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, + mul: PllMul::MUL7, // 16 * 7 = 112 MHz + divp: None, + divq: None, + divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz + }); + config.rcc.ls = LsConfig::default(); + } + + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + // In reality the delay would be much longer + Timer::after_millis(20000).await; + + let then: NaiveDateTime = rtc.now().unwrap().into(); + info!("Got RTC! {:?}", then.and_utc().timestamp()); +} -- cgit From a5f754238b77a8ef9ec8c6ad4c59af8fa5d5b374 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 16 Apr 2024 15:33:23 +0200 Subject: Add spi, i2c and fix usart --- examples/stm32u0/src/bin/i2c.rs | 21 +++++++++++++++++++++ examples/stm32u0/src/bin/spi.rs | 30 ++++++++++++++++++++++++++++++ examples/stm32u0/src/bin/usart.rs | 8 +------- 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 examples/stm32u0/src/bin/i2c.rs create mode 100644 examples/stm32u0/src/bin/spi.rs (limited to 'examples') diff --git a/examples/stm32u0/src/bin/i2c.rs b/examples/stm32u0/src/bin/i2c.rs new file mode 100644 index 000000000..2861bc091 --- /dev/null +++ b/examples/stm32u0/src/bin/i2c.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::I2c; +use embassy_stm32::time::Hertz; +use {defmt_rtt as _, panic_probe as _}; + +const ADDRESS: u8 = 0x5F; +const WHOAMI: u8 = 0x0F; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + let mut i2c = I2c::new_blocking(p.I2C2, p.PB10, p.PB11, Hertz(100_000), Default::default()); + + let mut data = [0u8; 1]; + unwrap!(i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data)); + info!("Whoami: {}", data[0]); +} diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs new file mode 100644 index 000000000..5693a3765 --- /dev/null +++ b/examples/stm32u0/src/bin/spi.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::spi::{Config, Spi}; +use embassy_stm32::time::Hertz; +use {defmt_rtt as _, panic_probe as _}; + +#[cortex_m_rt::entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let mut spi_config = Config::default(); + spi_config.frequency = Hertz(1_000_000); + + let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); + + let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); + + loop { + let mut buf = [0x0Au8; 4]; + cs.set_low(); + unwrap!(spi.blocking_transfer_in_place(&mut buf)); + cs.set_high(); + info!("xfer {=[u8]:x}", buf); + } +} diff --git a/examples/stm32u0/src/bin/usart.rs b/examples/stm32u0/src/bin/usart.rs index 1fcf0029a..037a5c833 100644 --- a/examples/stm32u0/src/bin/usart.rs +++ b/examples/stm32u0/src/bin/usart.rs @@ -2,15 +2,9 @@ #![no_main] use defmt::*; -use embassy_stm32::dma::NoDma; use embassy_stm32::usart::{Config, Uart}; -use embassy_stm32::{bind_interrupts, peripherals, usart}; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { - USART2_LPUART2 => usart::InterruptHandler; -}); - #[cortex_m_rt::entry] fn main() -> ! { info!("Hello World!"); @@ -18,7 +12,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); let config = Config::default(); - let mut usart = Uart::new(p.USART2, p.PA3, p.PA2, Irqs, NoDma, NoDma, config).unwrap(); + let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap(); unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); info!("wrote Hello, starting echo"); -- cgit From 90f1d29c2470d51337a3666cde2efacad3e054e5 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 16 Apr 2024 16:36:10 +0200 Subject: Fix rng clock --- examples/stm32u0/src/bin/rng.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/rng.rs b/examples/stm32u0/src/bin/rng.rs index 9b4c2537e..89445b042 100644 --- a/examples/stm32u0/src/bin/rng.rs +++ b/examples/stm32u0/src/bin/rng.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::rcc::mux::Clk48sel; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -26,6 +27,8 @@ async fn main(_spawner: Spawner) { divr: Some(PllRDiv::DIV2), // 112 / 2 = 56 MHz }); config.rcc.sys = Sysclk::PLL1_R; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: false }); // needed for RNG + config.rcc.mux.clk48sel = Clk48sel::HSI48; // needed for RNG (or use MSI or PLLQ if you want) } let p = embassy_stm32::init(config); @@ -33,7 +36,6 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut rng = Rng::new(p.RNG, Irqs); - info!("Hello World 2!"); let mut buf = [0u8; 16]; unwrap!(rng.async_fill_bytes(&mut buf).await); -- cgit From 4202dac8a6cc3a8ef32696d7f551025bf19cca4b Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 16 Apr 2024 17:03:44 +0200 Subject: L4 Example: probe-run to probe-rs Reverts some change made in https://github.com/embassy-rs/embassy/pull/1792 --- examples/stm32l4/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index db3a7ceff..83fc6d6f8 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -2,7 +2,7 @@ # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` #runner = "probe-rs run --chip STM32L475VGT6" #runner = "probe-rs run --chip STM32L475VG" -runner = "probe-run --chip STM32L4S5QI" +runner = "probe-rs run --chip STM32L4S5QI" [build] target = "thumbv7em-none-eabi" -- cgit From bd13b5c0604787a52322308353bec9996f9a199d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 16 Apr 2024 17:07:13 +0200 Subject: More probe-run -> probe-rs run. --- examples/stm32f334/.cargo/config.toml | 2 +- examples/stm32wb/.cargo/config.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml index caf947be6..f38c90a31 100644 --- a/examples/stm32f334/.cargo/config.toml +++ b/examples/stm32f334/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-run --chip STM32F334R8" +runner = "probe-rs run --chip STM32F334R8" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml index 51c499ee7..8b6d6d754 100644 --- a/examples/stm32wb/.cargo/config.toml +++ b/examples/stm32wb/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` -# runner = "probe-run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" +# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" runner = "teleprobe local run --chip STM32WB55RG --elf" [build] -- cgit From 0a2d58ec5b8d1d7663108ebb4add02083222874b Mon Sep 17 00:00:00 2001 From: Bjorn <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Sat, 20 Apr 2024 22:12:24 -0700 Subject: Added PIO pwm examples for rp Two additionally `rp` examples, `pio_pwm.rs`, which is a baremetal example of how to do pwm with pio, and `pio_servo.rs`, which is a more extended example of pwm and pio with servos. --- examples/rp/src/bin/pio_pwm.rs | 118 ++++++++++++++++++++++ examples/rp/src/bin/pio_servo.rs | 208 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 examples/rp/src/bin/pio_pwm.rs create mode 100644 examples/rp/src/bin/pio_servo.rs (limited to 'examples') diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs new file mode 100644 index 000000000..e14f243aa --- /dev/null +++ b/examples/rp/src/bin/pio_pwm.rs @@ -0,0 +1,118 @@ +//! This example shows how to create a pwm using the PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use core::time::Duration; + +use embassy_executor::Spawner; +use embassy_rp::gpio::Level; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; +use embassy_rp::{bind_interrupts, clocks}; +use embassy_time::Timer; +use pio::InstructionOperands; +use {defmt_rtt as _, panic_probe as _}; + +const REFRESH_INTERVAL: u64 = 20000; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub fn to_pio_cycles(duration: Duration) -> u32 { + (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow +} + +pub struct PwmPio<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { + pub fn attach(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 1 opt" + "pull noblock side 0" + "mov x, osr" + "mov y, isr" + "countloop:" + "jmp x!=y noset" + "jmp skip side 1" + "noset:" + "nop" + "skip:" + "jmp y-- countloop" + ); + + pio.load_program(&prg.program); + let pin = pio.make_pio_pin(pin); + sm.set_pins(Level::High, &[&pin]); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[&pin]); + + sm.set_config(&cfg); + + Self { sm } + } + + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + pub fn set_period(&mut self, duration: Duration) { + let is_enabled = self.sm.is_enabled(); + while !self.sm.tx().empty() {} // Make sure that the queue is empty + self.sm.set_enable(false); + self.sm.tx().push(to_pio_cycles(duration)); + unsafe { + self.sm.exec_instr( + InstructionOperands::PULL { + if_empty: false, + block: false, + } + .encode(), + ); + self.sm.exec_instr( + InstructionOperands::OUT { + destination: ::pio::OutDestination::ISR, + bit_count: 32, + } + .encode(), + ); + }; + if is_enabled { + self.sm.set_enable(true) // Enable if previously enabled + } + } + + pub fn set_level(&mut self, level: u32) { + self.sm.tx().push(level); + } + + pub fn write(&mut self, duration: Duration) { + self.set_level(to_pio_cycles(duration)); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + // Note that PIN_25 is the led pin on the Pico + let mut pwm_pio = PwmPio::attach(&mut common, sm0, p.PIN_25); + pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); + pwm_pio.start(); + + let mut duration = 0; + loop { + duration = (duration + 1) % 1000; + pwm_pio.write(Duration::from_micros(duration)); + Timer::after_millis(1).await; + } +} diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs new file mode 100644 index 000000000..47c3121fc --- /dev/null +++ b/examples/rp/src/bin/pio_servo.rs @@ -0,0 +1,208 @@ +//! This example shows how to create a pwm using the PIO module in the RP2040 chip. + +#![no_std] +#![no_main] +use core::time::Duration; + +use embassy_executor::Spawner; +use embassy_rp::gpio::Level; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; +use embassy_rp::{bind_interrupts, clocks}; +use embassy_time::Timer; +use pio::InstructionOperands; +use {defmt_rtt as _, panic_probe as _}; + +const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo +const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo +const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical +const REFRESH_INTERVAL: u64 = 20000; // The period of each cycle + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub fn to_pio_cycles(duration: Duration) -> u32 { + (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow +} + +pub struct PwmPio<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { + pub fn attach(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 1 opt" + "pull noblock side 0" + "mov x, osr" + "mov y, isr" + "countloop:" + "jmp x!=y noset" + "jmp skip side 1" + "noset:" + "nop" + "skip:" + "jmp y-- countloop" + ); + + pio.load_program(&prg.program); + let pin = pio.make_pio_pin(pin); + sm.set_pins(Level::High, &[&pin]); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&prg.program), &[&pin]); + + sm.set_config(&cfg); + + Self { sm } + } + + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + pub fn set_period(&mut self, duration: Duration) { + let is_enabled = self.sm.is_enabled(); + while !self.sm.tx().empty() {} // Make sure that the queue is empty + self.sm.set_enable(false); + self.sm.tx().push(to_pio_cycles(duration)); + unsafe { + self.sm.exec_instr( + InstructionOperands::PULL { + if_empty: false, + block: false, + } + .encode(), + ); + self.sm.exec_instr( + InstructionOperands::OUT { + destination: ::pio::OutDestination::ISR, + bit_count: 32, + } + .encode(), + ); + }; + if is_enabled { + self.sm.set_enable(true) // Enable if previously enabled + } + } + + pub fn set_level(&mut self, level: u32) { + self.sm.tx().push(level); + } + + pub fn write(&mut self, duration: Duration) { + self.set_level(to_pio_cycles(duration)); + } +} + +pub struct ServoBuilder<'d, T: Instance, const SM: usize> { + pwm: PwmPio<'d, T, SM>, + period: Duration, + min_pulse_width: Duration, + max_pulse_width: Duration, + max_degree_rotation: u64, +} + +impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { + pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + Self { + pwm, + period: Duration::from_micros(REFRESH_INTERVAL), + min_pulse_width: Duration::from_micros(DEFAULT_MIN_PULSE_WIDTH), + max_pulse_width: Duration::from_micros(DEFAULT_MAX_PULSE_WIDTH), + max_degree_rotation: DEFAULT_MAX_DEGREE_ROTATION, + } + } + + pub fn set_period(mut self, duration: Duration) -> Self { + self.period = duration; + self + } + + pub fn set_min_pulse_width(mut self, duration: Duration) -> Self { + self.min_pulse_width = duration; + self + } + + pub fn set_max_pulse_width(mut self, duration: Duration) -> Self { + self.max_pulse_width = duration; + self + } + + pub fn set_max_degree_rotation(mut self, degree: u64) -> Self { + self.max_degree_rotation = degree; + self + } + + pub fn build(mut self) -> Servo<'d, T, SM> { + self.pwm.set_period(self.period); + Servo { + pwm: self.pwm, + min_pulse_width: self.min_pulse_width, + max_pulse_width: self.max_pulse_width, + max_degree_rotation: self.max_degree_rotation, + } + } +} + +pub struct Servo<'d, T: Instance, const SM: usize> { + pwm: PwmPio<'d, T, SM>, + min_pulse_width: Duration, + max_pulse_width: Duration, + max_degree_rotation: u64, +} + +impl<'d, T: Instance, const SM: usize> Servo<'d, T, SM> { + pub fn start(&mut self) { + self.pwm.start(); + } + + pub fn stop(&mut self) { + self.pwm.stop(); + } + + pub fn write_time(&mut self, duration: Duration) { + self.pwm.write(duration); + } + + pub fn rotate(&mut self, degree: u64) { + let degree_per_nano_second = (self.max_pulse_width.as_nanos() as u64 - self.min_pulse_width.as_nanos() as u64) + / self.max_degree_rotation; + let mut duration = + Duration::from_nanos(degree * degree_per_nano_second + self.min_pulse_width.as_nanos() as u64); + if self.max_pulse_width < duration { + duration = self.max_pulse_width; + } + + self.pwm.write(duration); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let pwm_pio = PwmPio::attach(&mut common, sm0, p.PIN_1); + let mut servo = ServoBuilder::new(pwm_pio) + .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo + .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. + .set_max_pulse_width(Duration::from_micros(2600)) // Along with this value. + .build(); + + servo.start(); + + let mut degree = 0; + loop { + degree = (degree + 1) % 120; + servo.rotate(degree); + Timer::after_millis(50).await; + } +} -- cgit From d2ba751c06725c62a576da9a27be301666118955 Mon Sep 17 00:00:00 2001 From: Bjorn <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Sun, 21 Apr 2024 10:00:57 -0700 Subject: Changed attach to new --- examples/rp/src/bin/pio_pwm.rs | 4 ++-- examples/rp/src/bin/pio_servo.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs index e14f243aa..23d63d435 100644 --- a/examples/rp/src/bin/pio_pwm.rs +++ b/examples/rp/src/bin/pio_pwm.rs @@ -28,7 +28,7 @@ pub struct PwmPio<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn attach(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { let prg = pio_proc::pio_asm!( ".side_set 1 opt" "pull noblock side 0" @@ -105,7 +105,7 @@ async fn main(_spawner: Spawner) { let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); // Note that PIN_25 is the led pin on the Pico - let mut pwm_pio = PwmPio::attach(&mut common, sm0, p.PIN_25); + let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); pwm_pio.start(); diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs index 47c3121fc..a79540479 100644 --- a/examples/rp/src/bin/pio_servo.rs +++ b/examples/rp/src/bin/pio_servo.rs @@ -31,7 +31,7 @@ pub struct PwmPio<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn attach(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { + pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { let prg = pio_proc::pio_asm!( ".side_set 1 opt" "pull noblock side 0" @@ -190,7 +190,7 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - let pwm_pio = PwmPio::attach(&mut common, sm0, p.PIN_1); + let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); let mut servo = ServoBuilder::new(pwm_pio) .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. -- cgit From 896d0e7cd846971eb472555eb13ebe28e0b2d536 Mon Sep 17 00:00:00 2001 From: Joël Schulz-Ansres Date: Mon, 22 Apr 2024 00:52:37 +0200 Subject: Add comment on vbus_detection to all USB examples --- examples/stm32f4/src/bin/usb_ethernet.rs | 13 +++++++++++++ examples/stm32f4/src/bin/usb_hid_keyboard.rs | 14 +++++++++++++- examples/stm32f4/src/bin/usb_hid_mouse.rs | 13 +++++++++++++ examples/stm32f4/src/bin/usb_raw.rs | 13 +++++++++++++ examples/stm32f4/src/bin/usb_serial.rs | 13 +++++++++++++ examples/stm32f7/src/bin/usb_serial.rs | 13 +++++++++++++ examples/stm32h7/src/bin/usb_serial.rs | 13 +++++++++++++ examples/stm32l4/src/bin/usb_serial.rs | 13 +++++++++++++ 8 files changed, 104 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index d2cbeea1b..284c74564 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -40,6 +40,11 @@ bind_interrupts!(struct Irqs { HASH_RNG => rng::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(spawner: Spawner) { info!("Hello World!"); @@ -71,7 +76,15 @@ async fn main(spawner: Spawner) { static OUTPUT_BUFFER: StaticCell<[u8; 256]> = StaticCell::new(); let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index d6e0be5ea..4d9086156 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -21,6 +21,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -49,8 +54,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // If the board you’re using doesn’t have the VBUS pin wired up correctly for detecting the USB bus voltage (e.g. on the f4 blackpill board), set this to false + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 0bc236119..2b8e2f147 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -18,6 +18,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); @@ -46,7 +51,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index 4e583aeb8..00fdff2bf 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -69,6 +69,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -99,7 +104,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index f3a375d31..94c6a4301 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -16,6 +16,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -46,7 +51,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 39a5512f4..bb42f4cc8 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -16,6 +16,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -46,7 +51,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 576506ad3..725c9bb02 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -15,6 +15,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -47,7 +52,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 198504b59..58229d0be 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -16,6 +16,11 @@ bind_interrupts!(struct Irqs { OTG_FS => usb::InterruptHandler; }); +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. #[embassy_executor::main] async fn main(_spawner: Spawner) { info!("Hello World!"); @@ -41,7 +46,15 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + + // Enable vbus_detection + // Note: some boards don't have this wired up and might not require it, + // as they are powered through usb! + // If you hang on boot, try setting this to "false"! + // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure + // for more information config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config -- cgit From 01b36a44348dc8c065fdeb8787ac5a97ca8197f3 Mon Sep 17 00:00:00 2001 From: Joël Schulz-Ansres Date: Mon, 22 Apr 2024 01:06:59 +0200 Subject: rustfmt usb examples --- examples/stm32f4/src/bin/usb_ethernet.rs | 2 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 4 ++-- examples/stm32f4/src/bin/usb_hid_mouse.rs | 2 +- examples/stm32f4/src/bin/usb_raw.rs | 4 ++-- examples/stm32f4/src/bin/usb_serial.rs | 4 ++-- examples/stm32f7/src/bin/usb_serial.rs | 4 ++-- examples/stm32h7/src/bin/usb_serial.rs | 4 ++-- examples/stm32l4/src/bin/usb_serial.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 284c74564..34e58f282 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -79,7 +79,7 @@ async fn main(spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 4d9086156..7067d15a3 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -57,12 +57,12 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information config.vbus_detection = true; - + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 2b8e2f147..0d04d2a9c 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index 00fdff2bf..d058abdd0 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -107,12 +107,12 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information config.vbus_detection = true; - + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 94c6a4301..25806dd85 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -54,12 +54,12 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information config.vbus_detection = true; - + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index bb42f4cc8..2fee561c7 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -54,12 +54,12 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information config.vbus_detection = true; - + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 725c9bb02..872ff815c 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -55,12 +55,12 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information config.vbus_detection = true; - + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 58229d0be..b905fc66f 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) { // Enable vbus_detection // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! + // as they are powered through usb! // If you hang on boot, try setting this to "false"! // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure // for more information -- cgit From 846abfae2b8a24715542d57d4e6ea4386607d845 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 19 Apr 2024 15:20:04 +0100 Subject: examples: stm32: can: fix build --- examples/stm32g4/src/bin/can.rs | 4 ++-- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 2ed632a93..7836334af 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) { let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); - can.set_extended_filter( + can.properties().set_extended_filter( can::filter::ExtendedFilterSlot::_0, can::filter::ExtendedFilter::accept_all_into_fifo1(), ); @@ -128,7 +128,7 @@ async fn main(_spawner: Spawner) { } } i = 0; - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index dd625c90a..dc77ec3bf 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { } } - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index 22cb27481..a889d5860 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) { } } - let (mut tx, mut rx) = can.split(); + let (mut tx, mut rx, _props) = can.split(); // With split loop { let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); -- cgit From 0d0d8e14e2b0e81307ff70c5a31e300785da19f9 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 23 Apr 2024 19:48:16 +0200 Subject: Update dependent versions --- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) (limited to 'examples') diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 0bdf94331..84d6d04c1 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -11,7 +11,7 @@ embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } -embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb" } +embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 854f94d85..27b6b46df 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -18,7 +18,7 @@ embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } -embassy-usb = { version = "0.1.0", path = "../../../../embassy-usb", default-features = false } +embassy-usb = { version = "0.2.0", path = "../../../../embassy-usb", default-features = false } embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } [features] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 4ab5c7b7c..f0553a92d 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 24aa560d5..1d994d925 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } defmt = "0.3" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 0f58f143c..d5263deb8 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de 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"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 4f282f326..712ce246d 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 64bb2e560..5b457a5ae 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["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"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 3e5a7cc8c..b8b06afa2 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["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"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 512158bef..e6a9141e7 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" 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"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt" ] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 305816a2b..0a217e9ad 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 6ce3418e5..ccc5143aa 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 64c749b9b..2d702aeb5 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.7.0" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index c9f08d24e..ea5cca80f 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 84a89b378..05c284fc0 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de 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"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 322c41262..5ec1ee5db 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index d42e69578..dd7292f7f 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 5bcee178f..9f3b28cbe 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ 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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.7.0" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 5868372dd..6e16eb478 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 01320b88d..3cbce74a7 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" 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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" -- cgit From 597315873dbef394ae4cefe0af740fcb1bb951e0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Apr 2024 22:59:50 +0200 Subject: Remove leftover `cargo new` boilerplate. --- examples/stm32f0/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index c74980dc4..cabeca687 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] # Change stm32f091rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } -- cgit From 5732ee7ca975c0dd1afa83ade1667a2599d20985 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 26 Apr 2024 23:18:28 +0200 Subject: Reduce use of the full `futures` crate. --- examples/nrf-rtos-trace/Cargo.toml | 1 - examples/nrf52840-rtic/Cargo.toml | 1 - examples/nrf52840/Cargo.toml | 1 - examples/nrf52840/src/bin/gpiote_channel.rs | 2 +- examples/nrf5340/Cargo.toml | 1 - examples/nrf5340/src/bin/gpiote_channel.rs | 2 +- examples/rp/Cargo.toml | 1 - examples/stm32c0/Cargo.toml | 1 - examples/stm32f1/Cargo.toml | 1 - examples/stm32f2/Cargo.toml | 1 - examples/stm32f3/Cargo.toml | 1 - examples/stm32f334/Cargo.toml | 1 - examples/stm32f4/Cargo.toml | 3 ++- examples/stm32f4/src/bin/i2c_comparison.rs | 2 +- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 2 +- examples/stm32f4/src/bin/usb_hid_mouse.rs | 2 +- examples/stm32f4/src/bin/usb_serial.rs | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32f7/src/bin/usb_serial.rs | 2 +- examples/stm32g0/Cargo.toml | 1 - examples/stm32g4/Cargo.toml | 1 - examples/stm32g4/src/bin/usb_serial.rs | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h5/src/bin/usb_serial.rs | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7/src/bin/usb_serial.rs | 2 +- examples/stm32l0/Cargo.toml | 1 - examples/stm32l1/Cargo.toml | 2 +- examples/stm32l1/src/bin/usb_serial.rs | 2 +- examples/stm32l4/Cargo.toml | 1 - examples/stm32l4/src/bin/usb_serial.rs | 2 +- examples/stm32l5/Cargo.toml | 1 - examples/stm32u0/Cargo.toml | 2 +- examples/stm32u0/src/bin/usb_serial.rs | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32u5/src/bin/usb_serial.rs | 2 +- examples/stm32wb/Cargo.toml | 1 - examples/stm32wba/Cargo.toml | 1 - examples/stm32wl/Cargo.toml | 1 - 39 files changed, 22 insertions(+), 39 deletions(-) (limited to 'examples') diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 17210994b..f3a3f64af 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -23,7 +23,6 @@ embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf5 cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3" } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } serde = { version = "1.0.136", default-features = false } rtos-trace = "0.1.3" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index d91f58d0e..a0687fa1e 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -18,7 +18,6 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } [profile.release] debug = 2 diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index f0553a92d..d693c5a02 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -25,7 +25,6 @@ static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.7.0" diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs index e254d613d..dcfe7723a 100644 --- a/examples/nrf52840/src/bin/gpiote_channel.rs +++ b/examples/nrf52840/src/bin/gpiote_channel.rs @@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) { } }; - futures::join!(button1, button2, button3, button4); + embassy_futures::join::join4(button1, button2, button3, button4).await; } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 1d994d925..0d3e39fe5 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -21,7 +21,6 @@ static_cell = "2" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.7.0" diff --git a/examples/nrf5340/src/bin/gpiote_channel.rs b/examples/nrf5340/src/bin/gpiote_channel.rs index c0a55142f..23f6fca98 100644 --- a/examples/nrf5340/src/bin/gpiote_channel.rs +++ b/examples/nrf5340/src/bin/gpiote_channel.rs @@ -61,5 +61,5 @@ async fn main(_spawner: Spawner) { } }; - futures::join!(button1, button2, button3, button4); + embassy_futures::join::join4(button1, button2, button3, button4).await; } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d5263deb8..ae6746dce 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -28,7 +28,6 @@ fixed-macro = "1.2" cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } display-interface-spi = "0.4.1" embedded-graphics = "0.7.1" st7789 = "0.6.1" diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 7a3e03b75..aaca857ae 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } [profile.release] diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 712ce246d..55051703b 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" static_cell = "2.0.0" diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 4cbf1dc84..86921580a 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 5b457a5ae..2cfb19c42 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index b8b06afa2..7c067e140 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -19,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index e6a9141e7..64ac50818 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -12,6 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -22,7 +23,7 @@ embedded-hal = "0.2.6" embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +futures-util = { version = "0.3.30", default-features = false } heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" diff --git a/examples/stm32f4/src/bin/i2c_comparison.rs b/examples/stm32f4/src/bin/i2c_comparison.rs index 30cfbdf57..55c4891e3 100644 --- a/examples/stm32f4/src/bin/i2c_comparison.rs +++ b/examples/stm32f4/src/bin/i2c_comparison.rs @@ -13,7 +13,7 @@ use embassy_stm32::i2c::I2c; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, i2c, peripherals}; use embassy_time::Instant; -use futures::future::try_join3; +use futures_util::future::try_join3; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 96; diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index d48ae4a17..de9b692b1 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -5,6 +5,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use defmt::*; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::exti::ExtiInput; use embassy_stm32::gpio::Pull; use embassy_stm32::time::Hertz; @@ -13,7 +14,6 @@ use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::{Builder, Handler}; -use futures::future::join; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index c35f4b002..d15ad52dc 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -3,6 +3,7 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; @@ -10,7 +11,6 @@ use embassy_time::Timer; use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; use embassy_usb::control::OutResponse; use embassy_usb::Builder; -use futures::future::join; use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 25806dd85..91cfae87b 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -3,13 +3,13 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 0a217e9ad..37bec1bfa 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -13,6 +13,7 @@ embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["de embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -21,7 +22,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" rand_core = "0.6.3" diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 2fee561c7..02ab4d1f2 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -3,13 +3,13 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index ccc5143aa..803d0ae0e 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 2d702aeb5..7f51631c0 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -22,7 +22,6 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-can = { version = "0.4" } panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } static_cell = "2.0.0" diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index dbe8f27c1..ed2ac7fac 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -3,13 +3,13 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index ea5cca80f..4527f4bcb 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -12,6 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -24,7 +25,6 @@ embedded-hal-async = { version = "1.0" } embedded-io-async = { version = "0.6.1" } embedded-nal-async = { version = "0.7.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } rand_core = "0.6.3" critical-section = "1.1" diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index 4f86bb342..fbcbdb5f9 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -3,13 +3,13 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 05c284fc0..a09af4b97 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -12,6 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -24,7 +25,6 @@ embedded-hal-async = { version = "1.0" } embedded-nal-async = { version = "0.7.1" } embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } rand_core = "0.6.3" critical-section = "1.1" diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 872ff815c..71d0c0a25 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -3,12 +3,12 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index dd9097c9b..8831f9aaf 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -21,7 +21,6 @@ embedded-io-async = { version = "0.6.1" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } embedded-hal = "0.2.6" static_cell = { version = "2" } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 5ec1ee5db..24d61043d 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -10,6 +10,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -18,7 +19,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } embedded-storage = "0.3.1" diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index 653bbd6d2..837f7fa57 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -3,12 +3,12 @@ use defmt::{panic, *}; use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index dd7292f7f..a8c6aa0e9 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -28,7 +28,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } rand = { version = "0.8.5", default-features = false } diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index b905fc66f..a378cdc6b 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -4,12 +4,12 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 9f3b28cbe..2c6c125dc 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -22,7 +22,6 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } rand_core = { version = "0.6.3", default-features = false } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 6e16eb478..e9a215589 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -11,6 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -19,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } micromath = "2.0.0" diff --git a/examples/stm32u0/src/bin/usb_serial.rs b/examples/stm32u0/src/bin/usb_serial.rs index 9b38fd5dc..273f40643 100644 --- a/examples/stm32u0/src/bin/usb_serial.rs +++ b/examples/stm32u0/src/bin/usb_serial.rs @@ -4,12 +4,12 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 3cbce74a7..93127bcb7 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -11,6 +11,7 @@ embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" defmt-rtt = "0.4" @@ -19,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } micromath = "2.0.0" diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 6a313efb0..f107928a9 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -4,12 +4,12 @@ use defmt::{panic, *}; use defmt_rtt as _; // global logger use embassy_executor::Spawner; +use embassy_futures::join::join; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; -use futures::future::join; use panic_probe as _; bind_interrupts!(struct Irqs { diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 94a5141f5..82419ed10 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -20,7 +20,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } static_cell = "2" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 47279a012..ca55cbe92 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -18,7 +18,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } static_cell = "2" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 4cb55930b..b467b97a9 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -20,7 +20,6 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-storage = "0.3.1" panic-probe = { version = "0.3", features = ["print-defmt"] } -futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } -- cgit From d9e59e8e42ea009e365bb893b91d81fe47fe927d Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Sat, 27 Apr 2024 21:37:58 +0800 Subject: low power for h5 --- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h5/src/bin/stop.rs | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 examples/stm32h5/src/bin/stop.rs (limited to 'examples') diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 4527f4bcb..82760db64 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } 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", "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/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs new file mode 100644 index 000000000..0d14c0668 --- /dev/null +++ b/examples/stm32h5/src/bin/stop.rs @@ -0,0 +1,71 @@ +// Notice: +// the MCU might need an extra reset to make the code actually running + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; +use embassy_stm32::low_power::Executor; +use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::Config; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[cortex_m_rt::entry] +fn main() -> ! { + Executor::take().run(|spawner| { + unwrap!(spawner.spawn(async_main(spawner))); + }) +} + +#[embassy_executor::task] +async fn async_main(spawner: Spawner) { + defmt::info!("Program Start"); + + let mut config = Config::default(); + + // System Clock seems need to be equal or lower than 16 MHz + config.rcc.hsi = Some(HSIPrescaler::DIV4); + + config.rcc.ls = LsConfig::default_lsi(); + // when enabled the power-consumption is much higher during stop, but debugging and RTT is working + // if you wan't to measure the power-consumption, or for production: uncomment this line + // config.enable_debug_during_sleep = false; + let p = embassy_stm32::init(config); + + // give the RTC to the executor... + let rtc = Rtc::new(p.RTC, RtcConfig::default()); + static RTC: StaticCell = StaticCell::new(); + let rtc = RTC.init(rtc); + embassy_stm32::low_power::stop_with_rtc(rtc); + + unwrap!(spawner.spawn(blinky(p.PB4.into()))); + unwrap!(spawner.spawn(timeout())); +} + +#[embassy_executor::task] +async fn blinky(led: AnyPin) { + let mut led = Output::new(led, Level::Low, Speed::Low); + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + } +} + +// when enable_debug_during_sleep is false, it is more difficult to reprogram the MCU +// therefore we block the MCU after 30s to be able to reprogram it easily +#[embassy_executor::task] +async fn timeout() -> ! { + Timer::after_secs(30).await; + #[allow(clippy::empty_loop)] + loop {} +} -- cgit From 095af927910b06f7af291f76c5236e0da8322402 Mon Sep 17 00:00:00 2001 From: Chris Maniewski Date: Mon, 22 Apr 2024 01:37:24 +0200 Subject: feature: WebUSB capability implementation This adds the WebUSB implementation as per https://wicg.github.io/webusb/, using one in-endpoint and one out-endpoint as well as an example for the RP2040 to illustrate this capability. --- examples/rp/src/bin/usb_webusb.rs | 137 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 examples/rp/src/bin/usb_webusb.rs (limited to 'examples') diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs new file mode 100644 index 000000000..09f2c1cfd --- /dev/null +++ b/examples/rp/src/bin/usb_webusb.rs @@ -0,0 +1,137 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates a WebUSB capable device that echoes data back to the host. +//! +//! To test this in the browser (ideally host this on localhost:8080, to test the landing page +//! feature): +//! ```js +//! (async () => { +//! const device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0xf569 }] }); +//! await device.open(); +//! await device.claimInterface(1); +//! device.transferIn(1, 64).then(data => console.log(data)); +//! await device.transferOut(1, new Uint8Array([1,2,3])); +//! })(); +//! ``` + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; +use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; +use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; +use embassy_usb::{Builder, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + // Create the driver, from the HAL. + let driver = UsbDriver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xf569, 0x0001); + config.manufacturer = Some("Embassy"); + config.product = Some("WebUSB example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xff; + config.device_sub_class = 0x00; + config.device_protocol = 0x00; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let webusb_config = WebUsbConfig { + max_packet_size: 64, + vendor_code: 1, + // If defined, shows a landing page which the device manufacturer would like the user to visit in order to control their device. Suggest the user to navigate to this URL when the device is connected. + landing_url: Some(Url::new("http://localhost:8080")), + }; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything) + WebUsb::configure(&mut builder, &mut state, &webusb_config); + // Create some USB bulk endpoints for testing. + let mut endpoints = WebEndpoints::new(&mut builder, &webusb_config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do some WebUSB transfers. + let webusb_fut = async { + loop { + endpoints.wait_connected().await; + info!("Connected"); + endpoints.echo().await; + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, webusb_fut).await; +} + +struct WebEndpoints<'d, D: Driver<'d>> { + write_ep: D::EndpointIn, + read_ep: D::EndpointOut, +} + +impl<'d, D: Driver<'d>> WebEndpoints<'d, D> { + fn new(builder: &mut Builder<'d, D>, config: &'d WebUsbConfig<'d>) -> Self { + let mut func = builder.function(0xff, 0x00, 0x00); + let mut iface = func.interface(); + let mut alt = iface.alt_setting(0xff, 0x00, 0x00, None); + + let write_ep = alt.endpoint_bulk_in(config.max_packet_size); + let read_ep = alt.endpoint_bulk_out(config.max_packet_size); + + WebEndpoints { write_ep, read_ep } + } + + // Wait until the device's endpoints are enabled. + async fn wait_connected(&mut self) { + self.read_ep.wait_enabled().await + } + + // Echo data back to the host. + async fn echo(&mut self) { + let mut buf = [0; 64]; + loop { + let n = self.read_ep.read(&mut buf).await.unwrap(); + let data = &buf[..n]; + info!("Data read: {:x}", data); + self.write_ep.write(data).await.unwrap(); + } + } +} -- cgit From 6f44d7a9dfbb1dfe503c978e2277cfc5b1b6d486 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 29 Apr 2024 20:52:27 +0200 Subject: stm32: update metapac. Adds U5 LPDMA, fixes ADC_COMMONs. --- examples/stm32f0/src/bin/adc.rs | 6 +++--- examples/stm32f4/src/bin/dac.rs | 2 +- examples/stm32l0/src/bin/adc.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index a5a4186ea..8825e2687 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -4,13 +4,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::peripherals::ADC; +use embassy_stm32::peripherals::ADC1; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - ADC1_COMP => adc::InterruptHandler; + ADC1_COMP => adc::InterruptHandler; }); #[embassy_executor::main] @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs); + let mut adc = Adc::new(p.ADC1, Irqs); adc.set_sample_time(SampleTime::CYCLES71_5); let mut pin = p.PA1; diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index 9c7754c4f..dd2a45718 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs @@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World, dude!"); - let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4); + let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 507c3204a..9dd09bc45 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -4,13 +4,13 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::peripherals::ADC; +use embassy_stm32::peripherals::ADC1; use embassy_stm32::{adc, bind_interrupts}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - ADC1_COMP => adc::InterruptHandler; + ADC1_COMP => adc::InterruptHandler; }); #[embassy_executor::main] @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs); + let mut adc = Adc::new(p.ADC1, Irqs); adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; -- cgit From b6f9dbfb5b66190cd8d798ec0f99a7f3cdeb8ea0 Mon Sep 17 00:00:00 2001 From: Peter Kövesdi Date: Mon, 29 Apr 2024 22:31:16 +0200 Subject: fixed: example loops crashing after 256 passes --- examples/stm32f1/src/bin/can.rs | 4 ++-- examples/stm32f4/src/bin/can.rs | 2 +- examples/stm32f4/src/bin/wdt.rs | 2 +- examples/stm32g4/src/bin/can.rs | 4 ++-- examples/stm32h5/src/bin/can.rs | 2 +- examples/stm32h7/src/bin/can.rs | 2 +- examples/stm32u0/src/bin/wdt.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/stm32f1/src/bin/can.rs b/examples/stm32f1/src/bin/can.rs index 1c13d623d..ad0c8a5a5 100644 --- a/examples/stm32f1/src/bin/can.rs +++ b/examples/stm32f1/src/bin/can.rs @@ -85,7 +85,7 @@ async fn main(_spawner: Spawner) { defmt::println!("Error {}", err); } } - i += 1; + i = i.wrapping_add(1); } */ @@ -135,6 +135,6 @@ async fn main(_spawner: Spawner) { defmt::println!("Error {}", err); } } - i += 1; + i = i.wrapping_add(1); } } diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index cedc057a7..8e3beee24 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -63,6 +63,6 @@ async fn main(_spawner: Spawner) { envelope.frame.data()[0], latency.as_micros() ); - i += 1; + i = i.wrapping_add(1); } } diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index ea27ebce0..430898b40 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs @@ -36,6 +36,6 @@ async fn main(_spawner: Spawner) { wdt.pet(); } - i += 1; + i = i.wrapping_add(1); } } diff --git a/examples/stm32g4/src/bin/can.rs b/examples/stm32g4/src/bin/can.rs index 7836334af..90004f874 100644 --- a/examples/stm32g4/src/bin/can.rs +++ b/examples/stm32g4/src/bin/can.rs @@ -192,7 +192,7 @@ async fn main(_spawner: Spawner) { Timer::after_millis(250).await; - i += 1; + i = i.wrapping_add(1); } } else { static TX_BUF: StaticCell> = StaticCell::new(); @@ -228,7 +228,7 @@ async fn main(_spawner: Spawner) { Timer::after_millis(250).await; - i += 1; + i = i.wrapping_add(1); } } } diff --git a/examples/stm32h5/src/bin/can.rs b/examples/stm32h5/src/bin/can.rs index dc77ec3bf..194239d47 100644 --- a/examples/stm32h5/src/bin/can.rs +++ b/examples/stm32h5/src/bin/can.rs @@ -93,6 +93,6 @@ async fn main(_spawner: Spawner) { Timer::after_millis(250).await; - i += 1; + i = i.wrapping_add(1); } } diff --git a/examples/stm32h7/src/bin/can.rs b/examples/stm32h7/src/bin/can.rs index a889d5860..0af11ef3e 100644 --- a/examples/stm32h7/src/bin/can.rs +++ b/examples/stm32h7/src/bin/can.rs @@ -93,6 +93,6 @@ async fn main(_spawner: Spawner) { Timer::after_millis(250).await; - i += 1; + i = i.wrapping_add(1); } } diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs index f6276e2e9..8f9ea516d 100644 --- a/examples/stm32u0/src/bin/wdt.rs +++ b/examples/stm32u0/src/bin/wdt.rs @@ -36,6 +36,6 @@ async fn main(_spawner: Spawner) { wdt.pet(); } - i += 1; + i = i.wrapping_add(1); } } -- cgit From 5df703cf4b22f2fef2c2bed9fc6ceaca98d8ddfb Mon Sep 17 00:00:00 2001 From: pkoevesdi <33196971+pkoevesdi@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:38:58 +0200 Subject: Update wdt.rs: added missing type --- examples/stm32u0/src/bin/wdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs index 8f9ea516d..c0db89b22 100644 --- a/examples/stm32u0/src/bin/wdt.rs +++ b/examples/stm32u0/src/bin/wdt.rs @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); wdt.unleash(); - let mut i = 0; + let mut i:u8 = 0; loop { info!("high"); -- cgit From a2ea307114cbfade6793819e30d8438a34b0b201 Mon Sep 17 00:00:00 2001 From: pkoevesdi <33196971+pkoevesdi@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:42:46 +0200 Subject: Update wdt.rs: reverted changes, probably unneccesary --- examples/stm32u0/src/bin/wdt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32u0/src/bin/wdt.rs b/examples/stm32u0/src/bin/wdt.rs index c0db89b22..f6276e2e9 100644 --- a/examples/stm32u0/src/bin/wdt.rs +++ b/examples/stm32u0/src/bin/wdt.rs @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { let mut wdt = IndependentWatchdog::new(p.IWDG, 1_000_000); wdt.unleash(); - let mut i:u8 = 0; + let mut i = 0; loop { info!("high"); @@ -36,6 +36,6 @@ async fn main(_spawner: Spawner) { wdt.pet(); } - i = i.wrapping_add(1); + i += 1; } } -- cgit From 56b4d39df903d4dc235300dbe0fe57345c1e6fc1 Mon Sep 17 00:00:00 2001 From: pkoevesdi <33196971+pkoevesdi@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:45:02 +0200 Subject: Update wdt.rs: reverted change, probably unneccesary here --- examples/stm32f4/src/bin/wdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/wdt.rs b/examples/stm32f4/src/bin/wdt.rs index 430898b40..ea27ebce0 100644 --- a/examples/stm32f4/src/bin/wdt.rs +++ b/examples/stm32f4/src/bin/wdt.rs @@ -36,6 +36,6 @@ async fn main(_spawner: Spawner) { wdt.pet(); } - i = i.wrapping_add(1); + i += 1; } } -- cgit From 7896e8aba7d08b46700b370def152de2b03feaad Mon Sep 17 00:00:00 2001 From: kalkyl Date: Tue, 30 Apr 2024 09:59:06 +0200 Subject: rp: WebUSB example - add Windows compatibility --- examples/rp/src/bin/usb_webusb.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs index 09f2c1cfd..e73938ac9 100644 --- a/examples/rp/src/bin/usb_webusb.rs +++ b/examples/rp/src/bin/usb_webusb.rs @@ -25,6 +25,7 @@ use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; use embassy_usb::driver::{Driver, Endpoint, EndpointIn, EndpointOut}; +use embassy_usb::msos::{self, windows_version}; use embassy_usb::{Builder, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -32,6 +33,9 @@ bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); +// This is a randomly generated GUID to allow clients on Windows to find our device +const DEVICE_INTERFACE_GUIDS: &[&str] = &["{AFB9A6FB-30BA-44BC-9232-806CFC875321}"]; + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -58,6 +62,7 @@ async fn main(_spawner: Spawner) { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; + let mut msos_descriptor = [0; 256]; let webusb_config = WebUsbConfig { max_packet_size: 64, @@ -73,10 +78,23 @@ async fn main(_spawner: Spawner) { config, &mut config_descriptor, &mut bos_descriptor, - &mut [], // no msos descriptors + &mut msos_descriptor, &mut control_buf, ); + // Add the Microsoft OS Descriptor (MSOS/MOD) descriptor. + // We tell Windows that this entire device is compatible with the "WINUSB" feature, + // which causes it to use the built-in WinUSB driver automatically, which in turn + // can be used by libusb/rusb software without needing a custom driver or INF file. + // In principle you might want to call msos_feature() just on a specific function, + // if your device also has other functions that still use standard class drivers. + builder.msos_descriptor(windows_version::WIN8_1, 0); + builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + // Create classes on the builder (WebUSB just needs some setup, but doesn't return anything) WebUsb::configure(&mut builder, &mut state, &webusb_config); // Create some USB bulk endpoints for testing. -- cgit From fb67fe0a6c155191534955f1230dccaea0e11a94 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 1 May 2024 02:21:06 +0200 Subject: stm32: add support for STM32H7[RS] "bootflash line", add HIL tests. --- examples/stm32h7rs/.cargo/config.toml | 8 ++ examples/stm32h7rs/Cargo.toml | 73 +++++++++++++++ examples/stm32h7rs/build.rs | 5 + examples/stm32h7rs/src/bin/blinky.rs | 51 ++++++++++ examples/stm32h7rs/src/bin/button_exti.rs | 25 +++++ examples/stm32h7rs/src/bin/can.rs | 98 +++++++++++++++++++ examples/stm32h7rs/src/bin/mco.rs | 29 ++++++ examples/stm32h7rs/src/bin/multiprio.rs | 150 ++++++++++++++++++++++++++++++ examples/stm32h7rs/src/bin/rng.rs | 26 ++++++ examples/stm32h7rs/src/bin/rtc.rs | 36 +++++++ examples/stm32h7rs/src/bin/signal.rs | 36 +++++++ examples/stm32h7rs/src/bin/spi.rs | 50 ++++++++++ examples/stm32h7rs/src/bin/spi_dma.rs | 46 +++++++++ examples/stm32h7rs/src/bin/usart.rs | 39 ++++++++ examples/stm32h7rs/src/bin/usart_dma.rs | 47 ++++++++++ examples/stm32h7rs/src/bin/usart_split.rs | 48 ++++++++++ 16 files changed, 767 insertions(+) create mode 100644 examples/stm32h7rs/.cargo/config.toml create mode 100644 examples/stm32h7rs/Cargo.toml create mode 100644 examples/stm32h7rs/build.rs create mode 100644 examples/stm32h7rs/src/bin/blinky.rs create mode 100644 examples/stm32h7rs/src/bin/button_exti.rs create mode 100644 examples/stm32h7rs/src/bin/can.rs create mode 100644 examples/stm32h7rs/src/bin/mco.rs create mode 100644 examples/stm32h7rs/src/bin/multiprio.rs create mode 100644 examples/stm32h7rs/src/bin/rng.rs create mode 100644 examples/stm32h7rs/src/bin/rtc.rs create mode 100644 examples/stm32h7rs/src/bin/signal.rs create mode 100644 examples/stm32h7rs/src/bin/spi.rs create mode 100644 examples/stm32h7rs/src/bin/spi_dma.rs create mode 100644 examples/stm32h7rs/src/bin/usart.rs create mode 100644 examples/stm32h7rs/src/bin/usart_dma.rs create mode 100644 examples/stm32h7rs/src/bin/usart_split.rs (limited to 'examples') 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 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H7S3L8Hx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +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 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32h743bi to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "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"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = { version = "0.7.1" } +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +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 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV3, + mul: PllMul::MUL150, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.voltage_scale = VoltageScale::HIGH; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut led = Output::new(p.PD10, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::peripherals::*; +use embassy_stm32::{bind_interrupts, can, rcc, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FDCAN1_IT0 => can::IT0InterruptHandler; + FDCAN1_IT1 => can::IT1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.hse = Some(rcc::Hse { + freq: embassy_stm32::time::Hertz(25_000_000), + mode: rcc::HseMode::Oscillator, + }); + config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE; + + let peripherals = embassy_stm32::init(config); + + let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs); + + // 250k bps + can.set_bitrate(250_000); + + //let mut can = can.into_internal_loopback_mode(); + let mut can = can.into_normal_mode(); + + info!("CAN Configured"); + + let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + + loop { + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = can.write(&frame).await; + + match can.read().await { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 3 { + break; + } + } + + let (mut tx, mut rx, _props) = can.split(); + // With split + loop { + let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + _ = tx.write(&frame).await; + + match rx.read().await { + Ok(envelope) => { + let (rx_frame, ts) = envelope.parts(); + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {:x} {:x} {:x} {:x} --- NEW {}", + rx_frame.data()[0], + rx_frame.data()[1], + rx_frame.data()[2], + rx_frame.data()[3], + delta, + ) + } + Err(_err) => error!("Error in frame"), + } + + Timer::after_millis(250).await; + + i = i.wrapping_add(1); + } +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PB14, Level::High, Speed::Low); + + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(500).await; + + info!("low"); + led.set_low(); + Timer::after_millis(500).await; + } +} 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 @@ +//! This example showcases how to create multiple Executor instances to run tasks at +//! different priority levels. +//! +//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling +//! there's work in the queue, and `wfe` for waiting for work. +//! +//! Medium and high priority executors run in two interrupts with different priorities. +//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since +//! when there's work the interrupt will trigger and run the executor. +//! +//! Sample output below. Note that high priority ticks can interrupt everything else, and +//! medium priority computations can interrupt low priority computations, making them to appear +//! to take significantly longer time. +//! +//! ```not_rust +//! [med] Starting long computation +//! [med] done in 992 ms +//! [high] tick! +//! [low] Starting long computation +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [low] done in 3972 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! ``` +//! +//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. +//! You will get an output like the following. Note that no computation is ever interrupted. +//! +//! ```not_rust +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [low] Starting long computation +//! [low] done in 992 ms +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! [low] Starting long computation +//! [low] done in 992 ms +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! ``` +//! + +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::{Executor, InterruptExecutor}; +use embassy_stm32::interrupt; +use embassy_stm32::interrupt::{InterruptExt, Priority}; +use embassy_time::{Instant, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn run_high() { + loop { + info!(" [high] tick!"); + Timer::after_ticks(27374).await; + } +} + +#[embassy_executor::task] +async fn run_med() { + loop { + let start = Instant::now(); + info!(" [med] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(128_000_000); // ~1 second + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!(" [med] done in {} ms", ms); + + Timer::after_ticks(23421).await; + } +} + +#[embassy_executor::task] +async fn run_low() { + loop { + let start = Instant::now(); + info!("[low] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(256_000_000); // ~2 seconds + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!("[low] done in {} ms", ms); + + Timer::after_ticks(32983).await; + } +} + +static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); +static EXECUTOR_LOW: StaticCell = StaticCell::new(); + +#[interrupt] +unsafe fn UART4() { + EXECUTOR_HIGH.on_interrupt() +} + +#[interrupt] +unsafe fn UART5() { + EXECUTOR_MED.on_interrupt() +} + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let _p = embassy_stm32::init(Default::default()); + + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. + + // High-priority executor: UART4, priority level 6 + interrupt::UART4.set_priority(Priority::P6); + let spawner = EXECUTOR_HIGH.start(interrupt::UART4); + unwrap!(spawner.spawn(run_high())); + + // Medium-priority executor: UART5, priority level 7 + interrupt::UART5.set_priority(Priority::P7); + let spawner = EXECUTOR_MED.start(interrupt::UART5); + unwrap!(spawner.spawn(run_med())); + + // Low priority executor: runs in thread mode, using WFE/SEV + let executor = EXECUTOR_LOW.init(Executor::new()); + executor.run(|spawner| { + unwrap!(spawner.spawn(run_low())); + }); +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut rng = Rng::new(p.RNG, Irqs); + + let mut buf = [0u8; 16]; + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); +} 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 @@ +#![no_std] +#![no_main] + +use chrono::{NaiveDate, NaiveDateTime}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::rcc::LsConfig; +use embassy_stm32::rtc::{Rtc, RtcConfig}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.rcc.ls = LsConfig::default_lse(); + + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let now = NaiveDate::from_ymd_opt(2020, 5, 15) + .unwrap() + .and_hms_opt(10, 30, 15) + .unwrap(); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + info!("Got RTC! {:?}", now.and_utc().timestamp()); + + rtc.set_datetime(now.into()).expect("datetime not set"); + + // In reality the delay would be much longer + Timer::after_millis(20000).await; + + let then: NaiveDateTime = rtc.now().unwrap().into(); + info!("Got RTC! {:?}", then.and_utc().timestamp()); +} 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 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::signal::Signal; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +static SIGNAL: Signal = Signal::new(); + +#[embassy_executor::task] +async fn my_sending_task() { + let mut counter: u32 = 0; + + loop { + Timer::after_secs(1).await; + + SIGNAL.signal(counter); + + counter = counter.wrapping_add(1); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let _p = embassy_stm32::init(Default::default()); + unwrap!(spawner.spawn(my_sending_task())); + + loop { + let received_counter = SIGNAL.wait().await; + + info!("signalled, counter: {}", received_counter); + } +} 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 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::str::from_utf8; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::mode::Blocking; +use embassy_stm32::peripherals::SPI3; +use embassy_stm32::spi; +use embassy_stm32::time::mhz; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { + for n in 0u32.. { + let mut write: String<128> = String::new(); + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + unsafe { + let result = spi.blocking_transfer_in_place(write.as_bytes_mut()); + if let Err(_) = result { + defmt::panic!("crap"); + } + } + info!("read via spi: {}", from_utf8(write.as_bytes()).unwrap()); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + let p = embassy_stm32::init(Default::default()); + + let mut spi_config = spi::Config::default(); + spi_config.frequency = mhz(1); + + let spi = spi::Spi::new_blocking(p.SPI3, p.PB3, p.PB5, p.PB4, spi_config); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spi))); + }) +} 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 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::str::from_utf8; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::mode::Async; +use embassy_stm32::time::mhz; +use embassy_stm32::{peripherals, spi}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { + for n in 0u32.. { + let mut write: String<128> = String::new(); + let mut read = [0; 128]; + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + // transfer will slice the &mut read down to &write's actual length. + spi.transfer(&mut read, write.as_bytes()).await.ok(); + info!("read via spi+dma: {}", from_utf8(&read).unwrap()); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + let p = embassy_stm32::init(Default::default()); + + let mut spi_config = spi::Config::default(); + spi_config.frequency = mhz(1); + + let spi = spi::Spi::new(p.SPI3, p.PB3, p.PB5, p.PB4, p.GPDMA1_CH0, p.GPDMA1_CH1, spi_config); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spi))); + }) +} 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 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::usart::{Config, Uart}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new_blocking(p.UART7, p.PF6, p.PF7, config).unwrap(); + + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} 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 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + +#[embassy_executor::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + usart.write(s.as_bytes()).await.ok(); + + info!("wrote DMA"); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} 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 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::UART7; +use embassy_stm32::usart::{Config, Uart, UartRx}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; +use embassy_sync::channel::Channel; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UART7 => usart::InterruptHandler; +}); + +static CHANNEL: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let config = Config::default(); + let mut usart = Uart::new(p.UART7, p.PF6, p.PF7, Irqs, p.GPDMA1_CH0, p.GPDMA1_CH1, config).unwrap(); + unwrap!(usart.blocking_write(b"Type 8 chars to echo!\r\n")); + + let (mut tx, rx) = usart.split(); + + unwrap!(spawner.spawn(reader(rx))); + + loop { + let buf = CHANNEL.receive().await; + info!("writing..."); + unwrap!(tx.write(&buf).await); + } +} + +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART7, Async>) { + let mut buf = [0; 8]; + loop { + info!("reading..."); + unwrap!(rx.read(&mut buf).await); + CHANNEL.send(buf).await; + } +} -- cgit From c24805b83dbbca091eaf11a00c171da641f7107e Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Mon, 29 Apr 2024 12:45:08 +0100 Subject: Added PIO UART examples for rp to talk to an R503 fingerprint scanner. --- examples/rp/src/bin/uart_r503.rs | 113 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 examples/rp/src/bin/uart_r503.rs (limited to 'examples') diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs new file mode 100644 index 000000000..f8a9d8a9f --- /dev/null +++ b/examples/rp/src/bin/uart_r503.rs @@ -0,0 +1,113 @@ +#![no_std] +#![no_main] + +use defmt::{debug, info, unwrap}; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::UART0; +use embassy_rp::uart::{Async, Config, DataBits, InterruptHandler as UARTInterruptHandler, StopBits, Uart, UartRx}; +use embassy_time::Timer; +use heapless::Vec; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(pub struct Irqs { + UART0_IRQ => UARTInterruptHandler; // Fingerprint scanner (TX) +}); + +const ADDRESS: u32 = 0xFFFFFFFF; +const START: u16 = 0xEF01; + +// ================================================================================ + +fn write_cmd_bytes(buf: &mut Vec, bytes: &[u8]) { + let _ = buf.extend_from_slice(bytes); +} + +fn compute_checksum(buf: Vec) -> u16 { + let mut checksum = 0u16; + + let check_end = buf.len(); + let checked_bytes = &buf[6..check_end]; + for byte in checked_bytes { + checksum += (*byte) as u16; + } + return checksum; +} + +// NOTE: Doesn't work for some reason, it just hangs! +#[embassy_executor::task] +async fn reader(mut rx: UartRx<'static, UART0, Async>) { + loop { + let mut buf = [0; 32]; + debug!("Attempting read.."); + + //rx.read(&mut buf).await.unwrap(); + match rx.read(&mut buf).await { + Ok(v) => info!("Read successful: {:?}", v), + Err(e) => info!("Read error: {:?}", e), + } + info!("RX='{:?}'", buf); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Start"); + + let p = embassy_rp::init(Default::default()); + + // Initialize the fingerprint scanner. + let mut config = Config::default(); + config.baudrate = 57600; + config.stop_bits = StopBits::STOP1; + config.data_bits = DataBits::DataBits8; + + let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); + let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); + let (mut tx, rx) = uart.split(); + + unwrap!(spawner.spawn(reader(rx))); + Timer::after_secs(1).await; + + let mut vec_buf: Vec = heapless::Vec::new(); + { + // Clear buffers + vec_buf.clear(); + + // START + let _ = write_cmd_bytes(&mut vec_buf, &START.to_be_bytes()[..]); + + // ADDRESS + let _ = write_cmd_bytes(&mut vec_buf, &ADDRESS.to_be_bytes()[..]); + + // PID + let _ = vec_buf.push(0x01); + + // LENGTH + let len = >::try_into(vec_buf.len()).unwrap() as u16; + let _ = write_cmd_bytes(&mut vec_buf, &len.to_be_bytes()[..]); + + // COMMAND + let _ = vec_buf.push(0x35); // AuraLedConfig + + // DATA + let _ = vec_buf.push(0x01); // ctrl=Breathing light + let _ = vec_buf.push(0x50); // speed=80 + let _ = vec_buf.push(0x02); // colour=Blue + let _ = vec_buf.push(0x00); // times=Infinite + + // SUM + let chk = compute_checksum(vec_buf.clone()); + let _ = write_cmd_bytes(&mut vec_buf, &chk.to_be_bytes()[..]); + + // ===== + + // Send command buffer. + let data: [u8; 16] = vec_buf.clone().into_array().unwrap(); + debug!("data='{:?}'", data); + match tx.write(&data).await { + Ok(..) => info!("Write successful"), + Err(e) => info!("Write error: {:?}", e), + } + } +} -- cgit From 61d0c068ff793febd711971ded749bae277f5cc0 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Mon, 29 Apr 2024 14:54:26 +0100 Subject: Finish the read part. * Don't need separate task for this. * **Must** read one byte at a time, then merge them into one Vec. * To better demonstrate, cycle through the three colours Red, Blue, Purple. --- examples/rp/src/bin/uart_r503.rs | 79 +++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 30 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index f8a9d8a9f..c0676750c 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -1,17 +1,17 @@ #![no_std] #![no_main] -use defmt::{debug, info, unwrap}; +use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; -use embassy_rp::uart::{Async, Config, DataBits, InterruptHandler as UARTInterruptHandler, StopBits, Uart, UartRx}; +use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; use embassy_time::Timer; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(pub struct Irqs { - UART0_IRQ => UARTInterruptHandler; // Fingerprint scanner (TX) + UART0_IRQ => UARTInterruptHandler; }); const ADDRESS: u32 = 0xFFFFFFFF; @@ -34,24 +34,8 @@ fn compute_checksum(buf: Vec) -> u16 { return checksum; } -// NOTE: Doesn't work for some reason, it just hangs! -#[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART0, Async>) { - loop { - let mut buf = [0; 32]; - debug!("Attempting read.."); - - //rx.read(&mut buf).await.unwrap(); - match rx.read(&mut buf).await { - Ok(v) => info!("Read successful: {:?}", v), - Err(e) => info!("Read error: {:?}", e), - } - info!("RX='{:?}'", buf); - } -} - #[embassy_executor::main] -async fn main(spawner: Spawner) { +async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_rp::init(Default::default()); @@ -61,16 +45,16 @@ async fn main(spawner: Spawner) { config.baudrate = 57600; config.stop_bits = StopBits::STOP1; config.data_bits = DataBits::DataBits8; + config.parity = Parity::ParityNone; let (uart, tx_pin, tx_dma, rx_pin, rx_dma) = (p.UART0, p.PIN_16, p.DMA_CH0, p.PIN_17, p.DMA_CH1); let uart = Uart::new(uart, tx_pin, rx_pin, Irqs, tx_dma, rx_dma, config); - let (mut tx, rx) = uart.split(); - - unwrap!(spawner.spawn(reader(rx))); - Timer::after_secs(1).await; + let (mut tx, mut rx) = uart.split(); let mut vec_buf: Vec = heapless::Vec::new(); - { + + // Cycle through the three colours Red, Blue and Purple. + for colour in 1..=3 { // Clear buffers vec_buf.clear(); @@ -93,7 +77,7 @@ async fn main(spawner: Spawner) { // DATA let _ = vec_buf.push(0x01); // ctrl=Breathing light let _ = vec_buf.push(0x50); // speed=80 - let _ = vec_buf.push(0x02); // colour=Blue + let _ = vec_buf.push(colour as u8); // colour=Red, Blue, Purple let _ = vec_buf.push(0x00); // times=Infinite // SUM @@ -103,11 +87,46 @@ async fn main(spawner: Spawner) { // ===== // Send command buffer. - let data: [u8; 16] = vec_buf.clone().into_array().unwrap(); - debug!("data='{:?}'", data); - match tx.write(&data).await { - Ok(..) => info!("Write successful"), + let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); + info!("write ({})='{:?}'", colour, data_write); + match tx.write(&data_write).await { + Ok(..) => info!("Write successful."), Err(e) => info!("Write error: {:?}", e), } + + // ===== + + // Read command buffer. + let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! + let mut data_read: Vec = heapless::Vec::new(); // Return buffer. + let mut cnt: u8 = 0; // Keep track of how many packages we've received. + + info!("Attempting read."); + loop { + match rx.read(&mut read_buf).await { + Ok(..) => (), + Err(e) => info!(" Read error: {:?}", e), + } + + match cnt { + _ => data_read.push(read_buf[0]).unwrap(), + } + + if cnt > 10 { + info!("read ({})='{:?}'", colour, data_read[..]); + break; + } + + cnt = cnt + 1; + } + + // ===== + + if colour != 3 { + Timer::after_secs(2).await; + info!("Changing colour."); + } } + + info!("All done.."); } -- cgit From 66ee0c44d31d53da00cd2726ecd0fc47681f6d52 Mon Sep 17 00:00:00 2001 From: Turbo Fredriksson Date: Wed, 1 May 2024 11:43:14 +0100 Subject: Example and documentation on how to Calculate correct checksum. + Include the package format documentation. + Cycle through all three colours in three different speed. - Remove the `write_cmd_bytes()`. Superfluous. --- examples/rp/src/bin/uart_r503.rs | 182 ++++++++++++++++++++++----------------- 1 file changed, 104 insertions(+), 78 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/uart_r503.rs b/examples/rp/src/bin/uart_r503.rs index c0676750c..085be280b 100644 --- a/examples/rp/src/bin/uart_r503.rs +++ b/examples/rp/src/bin/uart_r503.rs @@ -1,12 +1,12 @@ #![no_std] #![no_main] -use defmt::info; +use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; -use embassy_time::Timer; +use embassy_time::{with_timeout, Duration, Timer}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; @@ -14,15 +14,34 @@ bind_interrupts!(pub struct Irqs { UART0_IRQ => UARTInterruptHandler; }); -const ADDRESS: u32 = 0xFFFFFFFF; const START: u16 = 0xEF01; +const ADDRESS: u32 = 0xFFFFFFFF; // ================================================================================ -fn write_cmd_bytes(buf: &mut Vec, bytes: &[u8]) { - let _ = buf.extend_from_slice(bytes); -} +// Data package format +// Name Length Description +// ========================================================================================================== +// Start 2 bytes Fixed value of 0xEF01; High byte transferred first. +// Address 4 bytes Default value is 0xFFFFFFFF, which can be modified by command. +// High byte transferred first and at wrong adder value, module +// will reject to transfer. +// PID 1 byte 01H Command packet; +// 02H Data packet; Data packet shall not appear alone in executing +// processs, must follow command packet or acknowledge packet. +// 07H Acknowledge packet; +// 08H End of Data packet. +// LENGTH 2 bytes Refers to the length of package content (command packets and data packets) +// plus the length of Checksum (2 bytes). Unit is byte. Max length is 256 bytes. +// And high byte is transferred first. +// DATA - It can be commands, data, command’s parameters, acknowledge result, etc. +// (fingerprint character value, template are all deemed as data); +// SUM 2 bytes The arithmetic sum of package identifier, package length and all package +// contens. Overflowing bits are omitted. high byte is transferred first. +// ================================================================================ + +// Checksum is calculated on 'length (2 bytes) + data (??)'. fn compute_checksum(buf: Vec) -> u16 { let mut checksum = 0u16; @@ -52,81 +71,88 @@ async fn main(_spawner: Spawner) { let (mut tx, mut rx) = uart.split(); let mut vec_buf: Vec = heapless::Vec::new(); - - // Cycle through the three colours Red, Blue and Purple. - for colour in 1..=3 { - // Clear buffers - vec_buf.clear(); - - // START - let _ = write_cmd_bytes(&mut vec_buf, &START.to_be_bytes()[..]); - - // ADDRESS - let _ = write_cmd_bytes(&mut vec_buf, &ADDRESS.to_be_bytes()[..]); - - // PID - let _ = vec_buf.push(0x01); - - // LENGTH - let len = >::try_into(vec_buf.len()).unwrap() as u16; - let _ = write_cmd_bytes(&mut vec_buf, &len.to_be_bytes()[..]); - - // COMMAND - let _ = vec_buf.push(0x35); // AuraLedConfig - - // DATA - let _ = vec_buf.push(0x01); // ctrl=Breathing light - let _ = vec_buf.push(0x50); // speed=80 - let _ = vec_buf.push(colour as u8); // colour=Red, Blue, Purple - let _ = vec_buf.push(0x00); // times=Infinite - - // SUM - let chk = compute_checksum(vec_buf.clone()); - let _ = write_cmd_bytes(&mut vec_buf, &chk.to_be_bytes()[..]); - - // ===== - - // Send command buffer. - let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); - info!("write ({})='{:?}'", colour, data_write); - match tx.write(&data_write).await { - Ok(..) => info!("Write successful."), - Err(e) => info!("Write error: {:?}", e), - } - - // ===== - - // Read command buffer. - let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! - let mut data_read: Vec = heapless::Vec::new(); // Return buffer. - let mut cnt: u8 = 0; // Keep track of how many packages we've received. - - info!("Attempting read."); - loop { - match rx.read(&mut read_buf).await { - Ok(..) => (), - Err(e) => info!(" Read error: {:?}", e), - } - - match cnt { - _ => data_read.push(read_buf[0]).unwrap(), + let mut data: Vec = heapless::Vec::new(); + + let mut speeds: Vec = heapless::Vec::new(); + let _ = speeds.push(0xC8); // Slow + let _ = speeds.push(0x20); // Medium + let _ = speeds.push(0x02); // Fast + + // Cycle through the three colours Red, Blue and Purple forever. + loop { + for colour in 1..=3 { + for speed in &speeds { + // Set the data first, because the length is dependent on that. + // However, we write the length bits before we do the data. + data.clear(); + let _ = data.push(0x01); // ctrl=Breathing light + let _ = data.push(*speed); + let _ = data.push(colour as u8); // colour=Red, Blue, Purple + let _ = data.push(0x00); // times=Infinite + + // Clear buffers + vec_buf.clear(); + + // START + let _ = vec_buf.extend_from_slice(&START.to_be_bytes()[..]); + + // ADDRESS + let _ = vec_buf.extend_from_slice(&ADDRESS.to_be_bytes()[..]); + + // PID + let _ = vec_buf.extend_from_slice(&[0x01]); + + // LENGTH + let len: u16 = (1 + data.len() + 2).try_into().unwrap(); + let _ = vec_buf.extend_from_slice(&len.to_be_bytes()[..]); + + // COMMAND + let _ = vec_buf.push(0x35); // Command: AuraLedConfig + + // DATA + let _ = vec_buf.extend_from_slice(&data); + + // SUM + let chk = compute_checksum(vec_buf.clone()); + let _ = vec_buf.extend_from_slice(&chk.to_be_bytes()[..]); + + // ===== + + // Send command buffer. + let data_write: [u8; 16] = vec_buf.clone().into_array().unwrap(); + debug!(" write='{:?}'", data_write[..]); + match tx.write(&data_write).await { + Ok(..) => info!("Write successful."), + Err(e) => error!("Write error: {:?}", e), + } + + // ===== + + // Read command buffer. + let mut read_buf: [u8; 1] = [0; 1]; // Can only read one byte at a time! + let mut data_read: Vec = heapless::Vec::new(); // Save buffer. + + info!("Attempting read."); + loop { + // Some commands, like `Img2Tz()` needs longer, but we hard-code this to 200ms + // for this command. + match with_timeout(Duration::from_millis(200), rx.read(&mut read_buf)).await { + Ok(..) => { + // Extract and save read byte. + debug!(" r='{=u8:#04x}H' ({:03}D)", read_buf[0], read_buf[0]); + let _ = data_read.push(read_buf[0]).unwrap(); + } + Err(..) => break, // TimeoutError -> Ignore. + } + } + info!("Read successful"); + debug!(" read='{:?}'", data_read[..]); + + Timer::after_secs(3).await; + info!("Changing speed."); } - if cnt > 10 { - info!("read ({})='{:?}'", colour, data_read[..]); - break; - } - - cnt = cnt + 1; - } - - // ===== - - if colour != 3 { - Timer::after_secs(2).await; info!("Changing colour."); } } - - info!("All done.."); } -- cgit From 3e87dae578969874d354c538d8c59e7be491933d Mon Sep 17 00:00:00 2001 From: Pegasis Date: Fri, 3 May 2024 08:12:30 -0400 Subject: add example for bdma --- examples/stm32h7/build.rs | 30 ++++++++++++++ examples/stm32h7/memory.x | 14 +++++++ examples/stm32h7/src/bin/spi_bdma.rs | 78 ++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 examples/stm32h7/memory.x create mode 100644 examples/stm32h7/src/bin/spi_bdma.rs (limited to 'examples') diff --git a/examples/stm32h7/build.rs b/examples/stm32h7/build.rs index 8cd32d7ed..b9bb661f0 100644 --- a/examples/stm32h7/build.rs +++ b/examples/stm32h7/build.rs @@ -1,4 +1,34 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); diff --git a/examples/stm32h7/memory.x b/examples/stm32h7/memory.x new file mode 100644 index 000000000..e5ab1f62c --- /dev/null +++ b/examples/stm32h7/memory.x @@ -0,0 +1,14 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 + BANK_2 */ + RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */ + RAM_D3 : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 */ +} + +SECTIONS +{ + .ram_d3 : + { + *(.ram_d3) + } > RAM_D3 +} \ No newline at end of file diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs new file mode 100644 index 000000000..2fc37fc22 --- /dev/null +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -0,0 +1,78 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; +use core::str::from_utf8; + +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Executor; +use embassy_stm32::mode::Async; +use embassy_stm32::time::mhz; +use embassy_stm32::{peripherals, spi, Config}; +use heapless::String; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +// Defined in memory.x +#[link_section = ".ram_d3"] +static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; + +#[embassy_executor::task] +async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) { + let read_buffer = unsafe { &mut RAM_D3[0..128] }; + let write_buffer = unsafe { &mut RAM_D3[128..256] }; + + for n in 0u32.. { + let mut write: String<128> = String::new(); + core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); + let read_buffer = &mut read_buffer[..write.len()]; + let write_buffer = &mut write_buffer[..write.len()]; + // copy data to write_buffer which is located in D3 domain, accessable by BDMA + write_buffer.clone_from_slice(write.as_bytes()); + + spi.transfer(read_buffer, write_buffer).await.ok(); + info!("read via spi+dma: {}", from_utf8(read_buffer).unwrap()); + } +} + +static EXECUTOR: StaticCell = StaticCell::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } + let p = embassy_stm32::init(config); + + let mut spi_config = spi::Config::default(); + spi_config.frequency = mhz(1); + + let spi = spi::Spi::new(p.SPI6, p.PA5, p.PA7, p.PA6, p.BDMA_CH1, p.BDMA_CH0, spi_config); + + let executor = EXECUTOR.init(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task(spi))); + }) +} -- cgit From 1c10339f4791b5ec6e2d41da79315fcb853b5529 Mon Sep 17 00:00:00 2001 From: Pegasis Date: Fri, 3 May 2024 08:17:29 -0400 Subject: format --- examples/stm32h7/build.rs | 2 +- examples/stm32h7/src/bin/spi_bdma.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32h7/build.rs b/examples/stm32h7/build.rs index b9bb661f0..30691aa97 100644 --- a/examples/stm32h7/build.rs +++ b/examples/stm32h7/build.rs @@ -28,7 +28,7 @@ fn main() { // here, we ensure the build script is only re-run when // `memory.x` is changed. println!("cargo:rerun-if-changed=memory.x"); - + println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index 2fc37fc22..f968df4a7 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -22,7 +22,7 @@ static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) { let read_buffer = unsafe { &mut RAM_D3[0..128] }; let write_buffer = unsafe { &mut RAM_D3[128..256] }; - + for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); -- cgit 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: create input_capture --- 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 +++++++++++ 8 files changed, 296 insertions(+), 2 deletions(-) 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 (limited to 'examples') 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); + } +} -- cgit 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: formatting --- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f4/src/bin/input_capture.rs | 29 +++++++++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'examples') 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; + } } } -- cgit 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: add get_input_interrupt --- examples/stm32f4/src/bin/input_capture.rs | 39 ++++++++++++++++++------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'examples') 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; + } +} +#[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 - let cap = ic.get_capture_value(Channel::Ch3); - if cap != last { - info!("New capture!"); - last = cap; + 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; } } -- cgit 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: 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 (limited to 'examples') 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 -- cgit 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: add async capture --- examples/stm32f4/src/bin/input_capture.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'examples') 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); } } -- cgit 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: fix fmt for ci --- examples/stm32f4/src/bin/input_capture.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') 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 _}; -- cgit From e94d4e6416e373bedb901d353989996a3375b615 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 8 May 2024 10:13:51 +0300 Subject: examples: Use unique crate name for stm32h7rs examples Current name clashes with "regular" stm32h7 thus generating cargo warning. --- examples/stm32h7rs/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index ad661411d..192a6ca61 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-stm32h7-examples" +name = "embassy-stm32h7rs-examples" version = "0.1.0" license = "MIT OR Apache-2.0" -- cgit From dc108ca31d2509f1297b4613f452e86830e19b12 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Thu, 9 May 2024 11:04:31 +0200 Subject: rp: Add raw interrupt handler example --- examples/rp/Cargo.toml | 1 + examples/rp/src/bin/interrupt.rs | 95 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 examples/rp/src/bin/interrupt.rs (limited to 'examples') diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index ae6746dce..8162e4dcb 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -27,6 +27,7 @@ fixed-macro = "1.2" #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" +critical-section = "1.1" panic-probe = { version = "0.3", features = ["print-defmt"] } display-interface-spi = "0.4.1" embedded-graphics = "0.7.1" diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs new file mode 100644 index 000000000..51dacca10 --- /dev/null +++ b/examples/rp/src/bin/interrupt.rs @@ -0,0 +1,95 @@ +//! This example shows how you can use raw interrupt handlers alongside embassy. +//! The example also showcases some of the options available for sharing resources/data. +//! +//! In the example, an ADC reading is triggered every time the PWM wraps around. +//! The sample data is sent down a channel, to be processed inside a low priority task. +//! The processed data is then used to adjust the PWM duty cycle, once every second. + +#![no_std] +#![no_main] + +use core::cell::{Cell, RefCell}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::adc::{self, Adc, Blocking}; +use embassy_rp::interrupt; +use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::{gpio::Pull, peripherals::PWM_SLICE4}; +use embassy_sync::{ + blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}, + channel::Channel, +}; +use embassy_time::{Duration, Ticker}; +use portable_atomic::{AtomicU32, Ordering}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +static COUNTER: AtomicU32 = AtomicU32::new(0); +static PWM: Mutex>>> = Mutex::new(RefCell::new(None)); +static ADC: Mutex, adc::Channel)>>> = + Mutex::new(RefCell::new(None)); +static ADC_VALUES: Channel = Channel::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + embassy_rp::pac::SIO.spinlock(31).write_value(1); + let p = embassy_rp::init(Default::default()); + + let adc = Adc::new_blocking(p.ADC, Default::default()); + let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None); + ADC.lock(|a| a.borrow_mut().replace((adc, p26))); + + let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default()); + PWM.lock(|p| p.borrow_mut().replace(pwm)); + + // Enable the interrupt for pwm slice 4 + embassy_rp::pac::PWM.inte().modify(|w| w.set_ch4(true)); + unsafe { + cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP); + } + + // Tasks require their resources to have 'static lifetime + // No Mutex needed when sharing within the same executor/prio level + static AVG: StaticCell> = StaticCell::new(); + let avg = AVG.init(Default::default()); + spawner.must_spawn(processing(avg)); + + let mut ticker = Ticker::every(Duration::from_secs(1)); + loop { + ticker.next().await; + let freq = COUNTER.swap(0, Ordering::Relaxed); + info!("pwm freq: {:?} Hz", freq); + info!("adc average: {:?}", avg.get()); + + // Update the pwm duty cycle, based on the averaged adc reading + let mut config = Config::default(); + config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _; + PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config)); + } +} + +#[embassy_executor::task] +async fn processing(avg: &'static Cell) { + let mut buffer: heapless::HistoryBuffer = Default::default(); + loop { + let val = ADC_VALUES.receive().await; + buffer.write(val); + let sum: u32 = buffer.iter().map(|x| *x as u32).sum(); + avg.set(sum / buffer.len() as u32); + } +} + +#[interrupt] +fn PWM_IRQ_WRAP() { + critical_section::with(|cs| { + let mut adc = ADC.borrow(cs).borrow_mut(); + let (adc, p26) = adc.as_mut().unwrap(); + let val = adc.blocking_read(p26).unwrap(); + ADC_VALUES.try_send(val).ok(); + + // Clear the interrupt, so we don't immediately re-enter this irq handler + PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped(); + }); + COUNTER.fetch_add(1, Ordering::Relaxed); +} -- cgit From 108bfae30d1857ebeb3764a6a110979efc6cf47e Mon Sep 17 00:00:00 2001 From: kalkyl Date: Thu, 9 May 2024 11:14:09 +0200 Subject: rustfmt --- examples/rp/src/bin/interrupt.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index 51dacca10..d334d35d7 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -13,13 +13,13 @@ use core::cell::{Cell, RefCell}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Blocking}; +use embassy_rp::gpio::Pull; use embassy_rp::interrupt; +use embassy_rp::peripherals::PWM_SLICE4; use embassy_rp::pwm::{Config, Pwm}; -use embassy_rp::{gpio::Pull, peripherals::PWM_SLICE4}; -use embassy_sync::{ - blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}, - channel::Channel, -}; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::channel::Channel; use embassy_time::{Duration, Ticker}; use portable_atomic::{AtomicU32, Ordering}; use static_cell::StaticCell; -- cgit From ee22e98fe1229ff9f4a85670dbb092717431ddde Mon Sep 17 00:00:00 2001 From: Mateusz Butkiewicz Date: Thu, 9 May 2024 08:05:34 +0200 Subject: feat(qspi): add example usage of QSPI --- examples/stm32f7/src/bin/qspi.rs | 300 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 examples/stm32f7/src/bin/qspi.rs (limited to 'examples') diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs new file mode 100644 index 000000000..005694db3 --- /dev/null +++ b/examples/stm32f7/src/bin/qspi.rs @@ -0,0 +1,300 @@ +#![no_std] +#![no_main] +#![allow(dead_code)] // Allow dead code as not all commands are used in the example + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; +use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, QuadDma, TransferConfig}; +use embassy_stm32::time::mhz; +use embassy_stm32::Config as StmCfg; +use {defmt_rtt as _, panic_probe as _}; + +const MEMORY_PAGE_SIZE: usize = 256; + +const CMD_READ: u8 = 0x03; +const CMD_HS_READ: u8 = 0x0B; +const CMD_QUAD_READ: u8 = 0x6B; + +const CMD_WRITE_PG: u8 = 0xF2; +const CMD_QUAD_WRITE_PG: u8 = 0x32; + +const CMD_READ_ID: u8 = 0x9F; +const CMD_READ_UUID: u8 = 0x4B; + +const CMD_ENABLE_RESET: u8 = 0x66; +const CMD_RESET: u8 = 0x99; + +const CMD_WRITE_ENABLE: u8 = 0x06; +const CMD_WRITE_DISABLE: u8 = 0x04; + +const CMD_CHIP_ERASE: u8 = 0xC7; +const CMD_SECTOR_ERASE: u8 = 0x20; +const CMD_BLOCK_ERASE_32K: u8 = 0x52; +const CMD_BLOCK_ERASE_64K: u8 = 0xD8; + +const CMD_READ_SR: u8 = 0x05; +const CMD_READ_CR: u8 = 0x35; + +const CMD_WRITE_SR: u8 = 0x01; +const CMD_WRITE_CR: u8 = 0x31; +const MEMORY_ADDR: u32 = 0x00000000u32; + +/// Implementation of access to flash chip. +/// Chip commands are hardcoded as it depends on used chip. +/// This implementation is using chip GD25Q64C from Giga Device +pub struct FlashMemory> { + qspi: Qspi<'static, I, D>, +} + +impl> FlashMemory { + pub fn new(qspi: Qspi<'static, I, D>) -> Self { + let mut memory = Self { qspi }; + + memory.reset_memory(); + memory.enable_quad(); + + memory + } + + fn enable_quad(&mut self) { + let cr = self.read_cr(); + self.write_cr(cr | 0x02); + } + + fn exec_command(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.command(transaction); + } + + pub fn reset_memory(&mut self) { + self.exec_command(CMD_ENABLE_RESET); + self.exec_command(CMD_RESET); + self.wait_write_finish(); + } + + pub fn enable_write(&mut self) { + self.exec_command(CMD_WRITE_ENABLE); + } + + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: CMD_READ_ID, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + + pub fn read_uuid(&mut self) -> [u8; 16] { + let mut buffer = [0; 16]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::SING, + instruction: CMD_READ_UUID, + address: Some(0), + dummy: DummyCycles::_8, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + + pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_READ, + address: Some(addr), + dummy: DummyCycles::_8, + }; + if use_dma { + self.qspi.blocking_read_dma(buffer, transaction); + } else { + self.qspi.blocking_read(buffer, transaction); + } + } + + fn wait_write_finish(&mut self) { + while (self.read_sr() & 0x01) != 0 {} + } + + fn perform_erase(&mut self, addr: u32, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + self.qspi.command(transaction); + self.wait_write_finish(); + } + + pub fn erase_sector(&mut self, addr: u32) { + self.perform_erase(addr, CMD_SECTOR_ERASE); + } + + pub fn erase_block_32k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_32K); + } + + pub fn erase_block_64k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_64K); + } + + pub fn erase_chip(&mut self) { + self.exec_command(CMD_CHIP_ERASE); + } + + fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_WRITE_PG, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + if use_dma { + self.qspi.blocking_write_dma(buffer, transaction); + } else { + self.qspi.blocking_write(buffer, transaction); + } + self.wait_write_finish(); + } + + pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page(place, chunk, chunk_size, use_dma); + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + fn read_register(&mut self, cmd: u8) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer[0] + } + + fn write_register(&mut self, cmd: u8, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_write(&buffer, transaction); + } + + pub fn read_sr(&mut self) -> u8 { + self.read_register(CMD_READ_SR) + } + + pub fn read_cr(&mut self) -> u8 { + self.read_register(CMD_READ_CR) + } + + pub fn write_sr(&mut self, value: u8) { + self.write_register(CMD_WRITE_SR, value); + } + + pub fn write_cr(&mut self, value: u8) { + self.write_register(CMD_WRITE_CR, value); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = StmCfg::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Oscillator, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL216, + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 216 / 2 = 216Mhz + divq: None, + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.sys = Sysclk::PLL1_P; + } + let p = embassy_stm32::init(config); + info!("Embassy initialized"); + + let config = QspiCfg { + memory_size: MemorySize::_8MiB, + address_size: AddressSize::_24bit, + prescaler: 16, + cs_high_time: ChipSelectHighTime::_1Cycle, + fifo_threshold: FIFOThresholdLevel::_16Bytes, + }; + let driver = Qspi::new_bk1( + p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, + ); + let mut flash = FlashMemory::new(driver); + let flash_id = flash.read_id(); + info!("FLASH ID: {:?}", flash_id); + let mut wr_buf = [0u8; 256]; + for i in 0..256 { + wr_buf[i] = i as u8; + } + let mut rd_buf = [0u8; 256]; + flash.erase_sector(MEMORY_ADDR); + flash.write_memory(MEMORY_ADDR, &wr_buf, true); + flash.read_memory(MEMORY_ADDR, &mut rd_buf, true); + info!("WRITE BUF: {:?}", wr_buf); + info!("READ BUF: {:?}", rd_buf); + info!("End of Program, proceed to empty endless loop"); + loop {} +} -- cgit From fd5412ffc50384c5e5e32c1a2bc499b558a99e8b Mon Sep 17 00:00:00 2001 From: kalkyl Date: Sat, 11 May 2024 15:16:20 +0200 Subject: rp: Add embedded-sdmmc example --- examples/rp/Cargo.toml | 1 + examples/rp/src/bin/spi_sdmmc.rs | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 examples/rp/src/bin/spi_sdmmc.rs (limited to 'examples') diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 8162e4dcb..73d19c28b 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -49,6 +49,7 @@ log = "0.4" pio-proc = "0.2" pio = "0.2.1" rand = { version = "0.8.5", default-features = false } +embedded-sdmmc = "0.7.0" [profile.release] debug = 2 diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs new file mode 100644 index 000000000..0912490d8 --- /dev/null +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -0,0 +1,80 @@ +//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. +//! +//! The example will attempt to read a file `MY_FILE.TXT` from the root directory +//! of the SD card and print its contents. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_embedded_hal::SetConfig; +use embassy_executor::Spawner; +use embassy_rp::spi::Spi; +use embassy_rp::{gpio, spi}; +use embedded_hal_bus::spi::ExclusiveDevice; +use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; +use gpio::{Level, Output}; +use {defmt_rtt as _, panic_probe as _}; + +struct DummyTimesource(); + +impl embedded_sdmmc::TimeSource for DummyTimesource { + fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { + embedded_sdmmc::Timestamp { + year_since_1970: 0, + zero_indexed_month: 0, + zero_indexed_day: 0, + hours: 0, + minutes: 0, + seconds: 0, + } + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + + // SPI clock needs to be running at <= 400kHz during initialization + let mut config = spi::Config::default(); + config.frequency = 400_000; + let spi = Spi::new_blocking(p.SPI1, p.PIN_10, p.PIN_11, p.PIN_12, config); + // Use a dummy cs pin here, for embedded-hal SpiDevice compatibility reasons + let spi_dev = ExclusiveDevice::new_no_delay(spi, DummyCsPin); + // Real cs pin + let cs = Output::new(p.PIN_16, Level::High); + + let sdcard = SdCard::new(spi_dev, cs, embassy_time::Delay); + info!("Card size is {} bytes", sdcard.num_bytes().unwrap()); + + // Now that the card is initialized, the SPI clock can go faster + let mut config = spi::Config::default(); + config.frequency = 16_000_000; + sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); + + // Now let's look for volumes (also known as partitions) on our block device. + // To do this we need a Volume Manager. It will take ownership of the block device. + let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, DummyTimesource()); + + // Try and access Volume 0 (i.e. the first partition). + // The volume object holds information about the filesystem on that volume. + let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0)).unwrap(); + info!("Volume 0: {:?}", defmt::Debug2Format(&volume0)); + + // Open the root directory (mutably borrows from the volume). + let mut root_dir = volume0.open_root_dir().unwrap(); + + // Open a file called "MY_FILE.TXT" in the root directory + // This mutably borrows the directory. + let mut my_file = root_dir + .open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly) + .unwrap(); + + // Print the contents of the file + while !my_file.is_eof() { + let mut buf = [0u8; 32]; + if let Ok(n) = my_file.read(&mut buf) { + info!("{:a}", buf[..n]); + } + } +} -- cgit From 17d4f0173cc7a3078112a0dca6a4c0de39373b13 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Sat, 11 May 2024 16:09:20 +0200 Subject: spinlock + loop at end to allow defmt to flush properly --- examples/rp/src/bin/spi_sdmmc.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'examples') diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs index 0912490d8..4cbc82f7b 100644 --- a/examples/rp/src/bin/spi_sdmmc.rs +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -33,6 +33,7 @@ impl embedded_sdmmc::TimeSource for DummyTimesource { #[embassy_executor::main] async fn main(_spawner: Spawner) { + embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); // SPI clock needs to be running at <= 400kHz during initialization @@ -77,4 +78,6 @@ async fn main(_spawner: Spawner) { info!("{:a}", buf[..n]); } } + + loop {} } -- cgit From 9d783d3b3521e1c1ff228160ee3ebca653bf06f8 Mon Sep 17 00:00:00 2001 From: Tim Docker Date: Sun, 12 May 2024 21:42:17 +1000 Subject: refactor rp usb_serial example to use a task to run the usb --- examples/rp/src/bin/usb_serial.rs | 100 +++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 45 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index 3c9bc96dd..4a802994a 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -5,15 +5,15 @@ #![no_std] #![no_main] -use defmt::{info, panic}; +use defmt::{info, panic, unwrap}; use embassy_executor::Spawner; -use embassy_futures::join::join; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; -use embassy_usb::{Builder, Config}; +use embassy_usb::UsbDevice; +use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { info!("Hello there!"); let p = embassy_rp::init(Default::default()); @@ -30,59 +30,69 @@ async fn main(_spawner: Spawner) { let driver = Driver::new(p.USB, Irqs); // Create embassy-usb Config - let mut config = Config::new(0xc0de, 0xcafe); - config.manufacturer = Some("Embassy"); - config.product = Some("USB-serial example"); - config.serial_number = Some("12345678"); - config.max_power = 100; - config.max_packet_size_0 = 64; - - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; + let config = { + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-serial example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + config + }; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. - let mut config_descriptor = [0; 256]; - let mut bos_descriptor = [0; 256]; - let mut control_buf = [0; 64]; - - let mut state = State::new(); - - let mut builder = Builder::new( - driver, - config, - &mut config_descriptor, - &mut bos_descriptor, - &mut [], // no msos descriptors - &mut control_buf, - ); + let mut builder = { + static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static BOS_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + static CONTROL_BUF: StaticCell<[u8; 64]> = StaticCell::new(); + + let builder = embassy_usb::Builder::new( + driver, + config, + CONFIG_DESCRIPTOR.init([0; 256]), + BOS_DESCRIPTOR.init([0; 256]), + &mut [], // no msos descriptors + CONTROL_BUF.init([0; 64]), + ); + builder + }; // Create classes on the builder. - let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + let mut class = { + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(State::new()); + CdcAcmClass::new(&mut builder, state, 64) + }; // Build the builder. - let mut usb = builder.build(); + let usb = builder.build(); // Run the USB device. - let usb_fut = usb.run(); + unwrap!(spawner.spawn(usb_task(usb))); // Do stuff with the class! - let echo_fut = async { - loop { - class.wait_connection().await; - info!("Connected"); - let _ = echo(&mut class).await; - info!("Disconnected"); - } - }; + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } +} + +type MyUsbDriver = Driver<'static, USB>; +type MyUsbDevice = UsbDevice<'static, MyUsbDriver>; - // Run everything concurrently. - // If we had made everything `'static` above instead, we could do this using separate tasks instead. - join(usb_fut, echo_fut).await; +#[embassy_executor::task] +async fn usb_task(mut usb: MyUsbDevice) -> ! { + usb.run().await } struct Disconnected {} -- cgit From e2dfdcb5091388cfbd467e9d8ac9b7d2025cc833 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 12 May 2024 23:30:53 +0200 Subject: examples/stm32: reduce packet queue count to avoid OOM on smaller chips. --- examples/stm32f4/src/bin/eth.rs | 4 ++-- examples/stm32f7/src/bin/eth.rs | 4 ++-- examples/stm32h7/src/bin/eth_client.rs | 4 ++-- examples/stm32h7/src/bin/eth_client_mii.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 7f5c8fdb1..648c45bbd 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -62,9 +62,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - static PACKETS: StaticCell> = StaticCell::new(); + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - PACKETS.init(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 9a608e909..41e2a6061 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -63,9 +63,9 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - static PACKETS: StaticCell> = StaticCell::new(); + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - PACKETS.init(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index aeb169e19..0639fb99f 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - static PACKETS: StaticCell> = StaticCell::new(); + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new( - PACKETS.init(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index de6ea522a..9a52e8d3b 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -64,10 +64,10 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; - static PACKETS: StaticCell> = StaticCell::new(); + static PACKETS: StaticCell> = StaticCell::new(); let device = Ethernet::new_mii( - PACKETS.init(PacketQueue::<16, 16>::new()), + PACKETS.init(PacketQueue::<4, 4>::new()), p.ETH, Irqs, p.PA1, -- cgit From 66e3d4da8d6eda003666b633bb57e67f2a10e31b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 13 May 2024 01:01:44 +0200 Subject: examples/stm32: do not enable vbus detect by default, it doesn't work on all boards. --- examples/stm32f4/src/bin/usb_ethernet.rs | 12 +++++------- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 12 +++++------- examples/stm32f4/src/bin/usb_hid_mouse.rs | 12 +++++------- examples/stm32f4/src/bin/usb_raw.rs | 12 +++++------- examples/stm32f4/src/bin/usb_serial.rs | 12 +++++------- examples/stm32f7/src/bin/usb_serial.rs | 12 +++++------- examples/stm32h7/src/bin/usb_serial.rs | 12 +++++------- examples/stm32l4/src/bin/usb_serial.rs | 12 +++++------- examples/stm32u5/src/bin/usb_serial.rs | 4 ++++ 9 files changed, 44 insertions(+), 56 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 34e58f282..19ae16e8b 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -77,13 +77,11 @@ async fn main(spawner: Spawner) { let ep_out_buffer = &mut OUTPUT_BUFFER.init([0; 256])[..]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index de9b692b1..537ff63ea 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -55,13 +55,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index d15ad52dc..df4b7426c 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -52,13 +52,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index d058abdd0..1452e7c5f 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -105,13 +105,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 91cfae87b..b2bd390b6 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -52,13 +52,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 02ab4d1f2..0e5cc7c5c 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -52,13 +52,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 71d0c0a25..1c50fc1c8 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -53,13 +53,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index a378cdc6b..ed9671d0f 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -47,13 +47,11 @@ async fn main(_spawner: Spawner) { let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); - // Enable vbus_detection - // Note: some boards don't have this wired up and might not require it, - // as they are powered through usb! - // If you hang on boot, try setting this to "false"! - // See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure - // for more information - config.vbus_detection = true; + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index f107928a9..4d56395da 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -43,6 +43,10 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. config.vbus_detection = false; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); -- cgit From b13110839624bc63904510e7bb815eca63b8c617 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 13 May 2024 01:02:00 +0200 Subject: examples/stm32h7rs: add i2c example. --- examples/stm32h7rs/src/bin/i2c.rs | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 examples/stm32h7rs/src/bin/i2c.rs (limited to 'examples') diff --git a/examples/stm32h7rs/src/bin/i2c.rs b/examples/stm32h7rs/src/bin/i2c.rs new file mode 100644 index 000000000..31e83cbb5 --- /dev/null +++ b/examples/stm32h7rs/src/bin/i2c.rs @@ -0,0 +1,42 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{Error, I2c}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, i2c, peripherals}; +use {defmt_rtt as _, panic_probe as _}; + +const ADDRESS: u8 = 0x5F; +const WHOAMI: u8 = 0x0F; + +bind_interrupts!(struct Irqs { + I2C2_EV => i2c::EventInterruptHandler; + I2C2_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello world!"); + let p = embassy_stm32::init(Default::default()); + + let mut i2c = I2c::new( + p.I2C2, + p.PB10, + p.PB11, + Irqs, + p.GPDMA1_CH4, + p.GPDMA1_CH5, + Hertz(100_000), + Default::default(), + ); + + let mut data = [0u8; 1]; + + match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { + Ok(()) => info!("Whoami: {}", data[0]), + Err(Error::Timeout) => error!("Operation timed out"), + Err(e) => error!("I2c Error: {:?}", e), + } +} -- cgit From 3ef62eef5370b34792a737dd5a4b296fe3fd8c7d Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 16 May 2024 08:12:18 -0700 Subject: stm32h7: add shared bus example --- examples/stm32h7/Cargo.toml | 1 + examples/stm32h7/src/bin/i2c_shared.rs | 112 +++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 examples/stm32h7/src/bin/i2c_shared.rs (limited to 'examples') diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index a09af4b97..c6c2d1354 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 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"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs new file mode 100644 index 000000000..79d213ae4 --- /dev/null +++ b/examples/stm32h7/src/bin/i2c_shared.rs @@ -0,0 +1,112 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::*; +use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::i2c::{self, I2c}; +use embassy_stm32::mode::Async; +use embassy_stm32::peripherals::{self, I2C1}; +use embassy_stm32::time::Hertz; +use embassy_sync::blocking_mutex::NoopMutex; +use embassy_time::{Duration, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +const TMP117_ADDR: u8 = 0x48; +const TMP117_TEMP_RESULT: u8 = 0x00; + +const SHTC3_ADDR: u8 = 0x70; +const SHTC3_WAKEUP: [u8; 2] = [0x35, 0x17]; +const SHTC3_MEASURE_RH_FIRST: [u8; 2] = [0x5c, 0x24]; +const SHTC3_SLEEP: [u8; 2] = [0xb0, 0x98]; + +static I2C_BUS: StaticCell>>> = StaticCell::new(); + +bind_interrupts!(struct Irqs { + I2C1_EV => i2c::EventInterruptHandler; + I2C1_ER => i2c::ErrorInterruptHandler; +}); + +#[embassy_executor::task] +async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { + let mut data = [0u8; 2]; + + loop { + match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data) { + Ok(()) => { + let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0; + info!("Temperature {}", temp); + } + Err(_) => error!("I2C Error"), + } + + Timer::after(Duration::from_millis(1000)).await; + } +} + +#[embassy_executor::task] +async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { + let mut data = [0u8; 6]; + + loop { + // Wakeup + match i2c.write(SHTC3_ADDR, &SHTC3_WAKEUP) { + Ok(()) => Timer::after(Duration::from_millis(20)).await, + Err(_) => error!("I2C Error"), + } + + // Measurement + match i2c.write(SHTC3_ADDR, &SHTC3_MEASURE_RH_FIRST) { + Ok(()) => Timer::after(Duration::from_millis(5)).await, + Err(_) => error!("I2C Error"), + } + + // Result + match i2c.read(SHTC3_ADDR, &mut data) { + Ok(()) => Timer::after(Duration::from_millis(5)).await, + Err(_) => error!("I2C Error"), + } + + // Sleep + match i2c.write(SHTC3_ADDR, &SHTC3_SLEEP) { + Ok(()) => { + let (bytes, _) = data.split_at(core::mem::size_of::()); + let rh = f32::from(u16::from_be_bytes(bytes.try_into().unwrap())) * 100.0 / 65536.0; + info!("Humidity: {}", rh); + } + Err(_) => error!("I2C Error"), + } + + Timer::after(Duration::from_millis(1000)).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + let i2c = I2c::new( + p.I2C1, + p.PB8, + p.PB9, + Irqs, + p.DMA1_CH4, + p.DMA1_CH5, + Hertz(100_000), + Default::default(), + ); + let i2c_bus = NoopMutex::new(RefCell::new(i2c)); + let i2c_bus = I2C_BUS.init(i2c_bus); + + // Device 1, using embedded-hal-async compatible driver for TMP117 + let i2c_dev1 = I2cDevice::new(i2c_bus); + spawner.spawn(temperature(i2c_dev1)).unwrap(); + + // Device 2, using embedded-hal-async compatible driver for SHTC3 + let i2c_dev2 = I2cDevice::new(i2c_bus); + spawner.spawn(humidity(i2c_dev2)).unwrap(); +} -- cgit From 57d9bfd343c51c9823b3e17e8a48260f0b67939f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 16 May 2024 12:14:05 -0700 Subject: stm32g0: add i2c_async example This example will help those having difficulties understanding how to bind interrupts on stm32g0 devices. --- examples/stm32g0/src/bin/i2c_async.rs | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 examples/stm32g0/src/bin/i2c_async.rs (limited to 'examples') diff --git a/examples/stm32g0/src/bin/i2c_async.rs b/examples/stm32g0/src/bin/i2c_async.rs new file mode 100644 index 000000000..7e3189b05 --- /dev/null +++ b/examples/stm32g0/src/bin/i2c_async.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::i2c::{self, I2c}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +}); + +const TMP117_ADDR: u8 = 0x48; +const TMP117_TEMP_RESULT: u8 = 0x00; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello world"); + + let p = embassy_stm32::init(Default::default()); + + let mut data = [0u8; 2]; + let mut i2c = I2c::new( + p.I2C1, + p.PB8, + p.PB9, + Irqs, + p.DMA1_CH1, + p.DMA1_CH2, + Hertz(100_000), + Default::default(), + ); + + loop { + match i2c.write_read(TMP117_ADDR, &[TMP117_TEMP_RESULT], &mut data).await { + Ok(()) => { + let temp = f32::from(i16::from_be_bytes(data)) * 7.8125 / 1000.0; + info!("Temperature {}", temp); + } + Err(_) => error!("I2C Error"), + } + + Timer::after(Duration::from_millis(1000)).await; + } +} -- cgit From b843f2546f0cb1a8595d390587f38012b8a013a4 Mon Sep 17 00:00:00 2001 From: Dan Groshev Date: Mon, 20 May 2024 14:23:03 +0100 Subject: Add a CHANGELOG to embassy-usb-logger and bump its version --- examples/rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 73d19c28b..5178a690f 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -15,7 +15,7 @@ embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defm embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } +embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.1.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.1.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } -- cgit From ca2eef5387b521a0ea95f26bae530d9bdfbba4d7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 18 Apr 2024 19:08:24 +0200 Subject: stm32/spi: remove peripheral generic param. --- examples/stm32h7/src/bin/spi.rs | 3 +-- examples/stm32h7/src/bin/spi_bdma.rs | 4 ++-- examples/stm32h7/src/bin/spi_dma.rs | 4 ++-- examples/stm32h7rs/src/bin/spi.rs | 3 +-- examples/stm32h7rs/src/bin/spi_dma.rs | 4 ++-- examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index aaebdc346..ad4a8aaf7 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -8,7 +8,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; -use embassy_stm32::peripherals::SPI3; use embassy_stm32::time::mhz; use embassy_stm32::{spi, Config}; use heapless::String; @@ -16,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index f968df4a7..b2e941078 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi, Config}; +use embassy_stm32::{spi, Config}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _}; static mut RAM_D3: [u8; 64 * 1024] = [0u8; 64 * 1024]; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI6, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { let read_buffer = unsafe { &mut RAM_D3[0..128] }; let write_buffer = unsafe { &mut RAM_D3[128..256] }; diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 3d3c724eb..731c7fef5 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -9,13 +9,13 @@ use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi, Config}; +use embassy_stm32::{spi, Config}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32h7rs/src/bin/spi.rs b/examples/stm32h7rs/src/bin/spi.rs index a7767876d..8d6ccc58b 100644 --- a/examples/stm32h7rs/src/bin/spi.rs +++ b/examples/stm32h7rs/src/bin/spi.rs @@ -8,7 +8,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Blocking; -use embassy_stm32::peripherals::SPI3; use embassy_stm32::spi; use embassy_stm32::time::mhz; use heapless::String; @@ -16,7 +15,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, SPI3, Blocking>) { +async fn main_task(mut spi: spi::Spi<'static, Blocking>) { for n in 0u32.. { let mut write: String<128> = String::new(); core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); diff --git a/examples/stm32h7rs/src/bin/spi_dma.rs b/examples/stm32h7rs/src/bin/spi_dma.rs index 26b5d6751..cb305351b 100644 --- a/examples/stm32h7rs/src/bin/spi_dma.rs +++ b/examples/stm32h7rs/src/bin/spi_dma.rs @@ -8,14 +8,14 @@ use cortex_m_rt::entry; use defmt::*; use embassy_executor::Executor; use embassy_stm32::mode::Async; +use embassy_stm32::spi; use embassy_stm32::time::mhz; -use embassy_stm32::{peripherals, spi}; use heapless::String; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::task] -async fn main_task(mut spi: spi::Spi<'static, peripherals::SPI3, Async>) { +async fn main_task(mut spi: spi::Spi<'static, Async>) { for n in 0u32.. { let mut write: String<128> = String::new(); let mut read = [0; 128]; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 694629ede..985ac8171 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -55,7 +55,7 @@ const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); // Listen port for the webserver const HTTP_LISTEN_PORT: u16 = 80; -pub type SpeSpi = Spi<'static, peripherals::SPI2, Async>; +pub type SpeSpi = Spi<'static, Async>; pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; -- cgit From 45a12fd41f1f6230a4aabbfe87552adc610fdc99 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 21 May 2024 01:25:49 +0200 Subject: stm32/i2c: remove peripheral generic param. --- examples/stm32h7/src/bin/i2c_shared.rs | 5 ++--- examples/stm32l4/src/bin/spe_adin1110_http_server.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs index 79d213ae4..6f4815582 100644 --- a/examples/stm32h7/src/bin/i2c_shared.rs +++ b/examples/stm32h7/src/bin/i2c_shared.rs @@ -6,11 +6,10 @@ use core::cell::RefCell; use defmt::*; use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; use embassy_executor::Spawner; -use embassy_stm32::bind_interrupts; use embassy_stm32::i2c::{self, I2c}; use embassy_stm32::mode::Async; -use embassy_stm32::peripherals::{self, I2C1}; use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::NoopMutex; use embassy_time::{Duration, Timer}; use static_cell::StaticCell; @@ -24,7 +23,7 @@ const SHTC3_WAKEUP: [u8; 2] = [0x35, 0x17]; const SHTC3_MEASURE_RH_FIRST: [u8; 2] = [0x5c, 0x24]; const SHTC3_SLEEP: [u8; 2] = [0xb0, 0x98]; -static I2C_BUS: StaticCell>>> = StaticCell::new(); +static I2C_BUS: StaticCell>>> = StaticCell::new(); bind_interrupts!(struct Irqs { I2C1_EV => i2c::EventInterruptHandler; diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 985ac8171..33149144c 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -60,7 +60,7 @@ pub type SpeSpiCs = ExclusiveDevice, Delay>; pub type SpeInt = exti::ExtiInput<'static>; pub type SpeRst = Output<'static>; pub type Adin1110T = ADIN1110; -pub type TempSensI2c = I2c<'static, peripherals::I2C3, Async>; +pub type TempSensI2c = I2c<'static, Async>; static TEMP: AtomicI32 = AtomicI32::new(0); -- cgit From 7cdbae2a5d5693a63ce55c08f39a69f2b4f0689c Mon Sep 17 00:00:00 2001 From: Univa <41708691+Univa@users.noreply.github.com> Date: Mon, 20 May 2024 21:29:20 -0400 Subject: add AnyAdcChannel --- examples/stm32h7/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index 0009103d1..e9a857a74 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -51,7 +51,7 @@ async fn main(_spawner: Spawner) { let mut vrefint_channel = adc.enable_vrefint(); loop { - let vrefint = adc.read_internal(&mut vrefint_channel); + let vrefint = adc.read(&mut vrefint_channel); info!("vrefint: {}", vrefint); let measured = adc.read(&mut p.PC0); info!("measured: {}", measured); -- cgit From 4e42eaef7c423f7f15af38991d4444141a8af1c2 Mon Sep 17 00:00:00 2001 From: Joël Schulz-Ansres Date: Tue, 21 May 2024 12:17:51 +0200 Subject: Add dsi example --- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/.cargo/config.toml | 9 + examples/stm32f469/Cargo.toml | 22 ++ examples/stm32f469/build.rs | 5 + examples/stm32f469/src/bin/dsi_bsp.rs | 694 ++++++++++++++++++++++++++++++++++ examples/stm32f469/src/bin/ferris.bin | 70 ++++ 6 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 examples/stm32f469/.cargo/config.toml create mode 100644 examples/stm32f469/Cargo.toml create mode 100644 examples/stm32f469/build.rs create mode 100644 examples/stm32f469/src/bin/dsi_bsp.rs create mode 100644 examples/stm32f469/src/bin/ferris.bin (limited to 'examples') diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 64ac50818..1eb1ae6db 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", "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/stm32f469/.cargo/config.toml b/examples/stm32f469/.cargo/config.toml new file mode 100644 index 000000000..05250954f --- /dev/null +++ b/examples/stm32f469/.cargo/config.toml @@ -0,0 +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 STM32F469NIHx" + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml new file mode 100644 index 000000000..7718a46c1 --- /dev/null +++ b/examples/stm32f469/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "embassy-stm32f469-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Specific examples only for stm32f469 +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +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"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "1.0.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } + +[profile.release] +debug = 2 diff --git a/examples/stm32f469/build.rs b/examples/stm32f469/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32f469/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs new file mode 100644 index 000000000..e4e9e9c01 --- /dev/null +++ b/examples/stm32f469/src/bin/dsi_bsp.rs @@ -0,0 +1,694 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::dsihost::{blocking_delay_ms, DsiHost, PacketType}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::ltdc::Ltdc; +use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; +use embassy_stm32::pac::ltdc::vals::{Bf1, Bf2, Depol, Hspol, Imr, Pcpol, Pf, Vspol}; +use embassy_stm32::pac::{DSIHOST, LTDC}; +use embassy_stm32::rcc::{ + AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk, +}; +use embassy_stm32::time::mhz; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +enum _Orientation { + Landscape, + Portrait, +} + +const _LCD_ORIENTATION: _Orientation = _Orientation::Landscape; +const LCD_X_SIZE: u16 = 800; +const LCD_Y_SIZE: u16 = 480; + +static FERRIS_IMAGE: &[u8; 1536000] = include_bytes!("ferris.bin"); + +// This example allows to display an image on the STM32F469NI-DISCO boards +// with the Revision C, that is at least the boards marked DK32F469I$AU1. +// These boards have the NT35510 display driver. This example does not work +// for the older revisions with OTM8009A, though there are lots of C-examples +// available online where the correct config for the OTM8009A could be gotten from. +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_stm32::Config::default(); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + + // HSE is on and ready + config.rcc.hse = Some(Hse { + freq: mhz(8), + mode: HseMode::Oscillator, + }); + config.rcc.pll_src = PllSource::HSE; + + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV8, // PLLM + mul: PllMul::MUL360, // PLLN + divp: Some(PllPDiv::DIV2), + divq: Some(PllQDiv::DIV7), // was DIV4, but STM BSP example uses 7 + divr: Some(PllRDiv::DIV6), + }); + + // This seems to be working, the values in the RCC.PLLSAICFGR are correct according to the debugger. Also on and ready according to CR + config.rcc.pllsai = Some(Pll { + prediv: PllPreDiv::DIV8, // Actually ignored + mul: PllMul::MUL384, // PLLN + divp: None, // PLLP + divq: None, // PLLQ + divr: Some(PllRDiv::DIV7), // PLLR (Sai actually has special clockdiv register) + }); + + let p = embassy_stm32::init(config); + info!("Starting..."); + + let mut led = Output::new(p.PG6, Level::High, Speed::Low); + + // According to UM for the discovery kit, PH7 is an active-low reset for the LCD and touchsensor + let mut reset = Output::new(p.PH7, Level::Low, Speed::High); + + // CubeMX example waits 20 ms before de-asserting reset + embassy_time::block_for(embassy_time::Duration::from_millis(20)); + + // Disable the reset signal and wait 140ms as in the Linux driver (CubeMX waits only 20) + reset.set_high(); + embassy_time::block_for(embassy_time::Duration::from_millis(140)); + + let mut ltdc = Ltdc::new(p.LTDC); + let mut dsi = DsiHost::new(p.DSIHOST, p.PJ2); + let version = dsi.get_version(); + defmt::warn!("en: {:x}", version); + + // Disable the DSI wrapper + dsi.disable_wrapper_dsi(); + + // Disable the DSI host + dsi.disable(); + + // D-PHY clock and digital disable + DSIHOST.pctlr().modify(|w| { + w.set_cke(false); + w.set_den(false) + }); + + // Turn off the DSI PLL + DSIHOST.wrpcr().modify(|w| w.set_pllen(false)); + + // Disable the regulator + DSIHOST.wrpcr().write(|w| w.set_regen(false)); + + // Enable regulator + info!("DSIHOST: enabling regulator"); + DSIHOST.wrpcr().write(|w| w.set_regen(true)); + + for _ in 1..1000 { + // The regulator status (ready or not) can be monitored with the RRS flag in the DSI_WISR register. + // Once it is set, we stop waiting. + if DSIHOST.wisr().read().rrs() { + info!("DSIHOST Regulator ready"); + break; + } + embassy_time::block_for(embassy_time::Duration::from_millis(1)); + } + + if !DSIHOST.wisr().read().rrs() { + defmt::panic!("DSIHOST: enabling regulator FAILED"); + } + + // Set up PLL and enable it + DSIHOST.wrpcr().modify(|w| { + w.set_pllen(true); + w.set_ndiv(125); // PLL loop division factor set to 125 + w.set_idf(2); // PLL input divided by 2 + w.set_odf(0); // PLL output divided by 1 + }); + + /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */ + const LANE_BYTE_CLK_K_HZ: u16 = 62500; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L224C21-L224C26 + + const _LCD_CLOCK: u16 = 27429; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L183 + + /* TX_ESCAPE_CKDIV = f(LaneByteClk)/15.62 = 4 */ + const TX_ESCAPE_CKDIV: u8 = (LANE_BYTE_CLK_K_HZ / 15620) as u8; // https://github.com/STMicroelectronics/32f469idiscovery-bsp/blob/ec051de2bff3e1b73a9ccd49c9b85abf7320add9/stm32469i_discovery_lcd.c#L230 + + for _ in 1..1000 { + embassy_time::block_for(embassy_time::Duration::from_millis(1)); + // The PLL status (lock or unlock) can be monitored with the PLLLS flag in the DSI_WISR register. + // Once it is set, we stop waiting. + if DSIHOST.wisr().read().pllls() { + info!("DSIHOST PLL locked"); + break; + } + } + + if !DSIHOST.wisr().read().pllls() { + defmt::panic!("DSIHOST: enabling PLL FAILED"); + } + + // Set the PHY parameters + + // D-PHY clock and digital enable + DSIHOST.pctlr().write(|w| { + w.set_cke(true); + w.set_den(true); + }); + + // Set Clock lane to high-speed mode and disable automatic clock lane control + DSIHOST.clcr().modify(|w| { + w.set_dpcc(true); + w.set_acr(false); + }); + + // Set number of active data lanes to two (lanes 0 and 1) + DSIHOST.pconfr().modify(|w| w.set_nl(1)); + + // Set the DSI clock parameters + + // Set the TX escape clock division factor to 4 + DSIHOST.ccr().modify(|w| w.set_txeckdiv(TX_ESCAPE_CKDIV)); + + // Calculate the bit period in high-speed mode in unit of 0.25 ns (UIX4) + // The equation is : UIX4 = IntegerPart( (1000/F_PHY_Mhz) * 4 ) + // Where : F_PHY_Mhz = (NDIV * HSE_Mhz) / (IDF * ODF) + // Set the bit period in high-speed mode + DSIHOST.wpcr0().modify(|w| w.set_uix4(8)); // 8 is set in the BSP example (confirmed with Debugger) + + // Disable all error interrupts and reset the Error Mask + DSIHOST.ier0().write_value(Ier0(0)); + DSIHOST.ier1().write_value(Ier1(0)); + + // Enable this to fix read timeout + DSIHOST.pcr().modify(|w| w.set_btae(true)); + + const DSI_PIXEL_FORMAT_RGB888: u8 = 0x05; + const _DSI_PIXEL_FORMAT_ARGB888: u8 = 0x00; + + const HACT: u16 = LCD_X_SIZE; + const VACT: u16 = LCD_Y_SIZE; + + const VSA: u16 = 120; + const VBP: u16 = 150; + const VFP: u16 = 150; + const HSA: u16 = 2; + const HBP: u16 = 34; + const HFP: u16 = 34; + + const VIRTUAL_CHANNEL_ID: u8 = 0; + + const COLOR_CODING: u8 = DSI_PIXEL_FORMAT_RGB888; + const VS_POLARITY: bool = false; // DSI_VSYNC_ACTIVE_HIGH == 0 + const HS_POLARITY: bool = false; // DSI_HSYNC_ACTIVE_HIGH == 0 + const DE_POLARITY: bool = false; // DSI_DATA_ENABLE_ACTIVE_HIGH == 0 + const MODE: u8 = 2; // DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */ + const NULL_PACKET_SIZE: u16 = 0xFFF; + const NUMBER_OF_CHUNKS: u16 = 0; + const PACKET_SIZE: u16 = HACT; /* Value depending on display orientation choice portrait/landscape */ + const HORIZONTAL_SYNC_ACTIVE: u16 = 4; // ((HSA as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; + const HORIZONTAL_BACK_PORCH: u16 = 77; //((HBP as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32) as u16; + const HORIZONTAL_LINE: u16 = 1982; //(((HACT + HSA + HBP + HFP) as u32 * LANE_BYTE_CLK_K_HZ as u32 ) / LCD_CLOCK as u32 ) as u16; /* Value depending on display orientation choice portrait/landscape */ + // FIXME: Make depend on orientation + const VERTICAL_SYNC_ACTIVE: u16 = VSA; + const VERTICAL_BACK_PORCH: u16 = VBP; + const VERTICAL_FRONT_PORCH: u16 = VFP; + const VERTICAL_ACTIVE: u16 = VACT; + const LP_COMMAND_ENABLE: bool = true; /* Enable sending commands in mode LP (Low Power) */ + + /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + const LP_LARGEST_PACKET_SIZE: u8 = 16; + + /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + const LPVACT_LARGEST_PACKET_SIZE: u8 = 0; + + const LPHORIZONTAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HFP period */ + const LPHORIZONTAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during HBP period */ + const LPVERTICAL_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VACT period */ + const LPVERTICAL_FRONT_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VFP period */ + const LPVERTICAL_BACK_PORCH_ENABLE: bool = true; /* Allow sending LP commands during VBP period */ + const LPVERTICAL_SYNC_ACTIVE_ENABLE: bool = true; /* Allow sending LP commands during VSync = VSA period */ + const FRAME_BTAACKNOWLEDGE_ENABLE: bool = false; /* Frame bus-turn-around acknowledge enable => false according to debugger */ + + /* Select video mode by resetting CMDM and DSIM bits */ + DSIHOST.mcr().modify(|w| w.set_cmdm(false)); + DSIHOST.wcfgr().modify(|w| w.set_dsim(false)); + + /* Configure the video mode transmission type */ + DSIHOST.vmcr().modify(|w| w.set_vmt(MODE)); + + /* Configure the video packet size */ + DSIHOST.vpcr().modify(|w| w.set_vpsize(PACKET_SIZE)); + + /* Set the chunks number to be transmitted through the DSI link */ + DSIHOST.vccr().modify(|w| w.set_numc(NUMBER_OF_CHUNKS)); + + /* Set the size of the null packet */ + DSIHOST.vnpcr().modify(|w| w.set_npsize(NULL_PACKET_SIZE)); + + /* Select the virtual channel for the LTDC interface traffic */ + DSIHOST.lvcidr().modify(|w| w.set_vcid(VIRTUAL_CHANNEL_ID)); + + /* Configure the polarity of control signals */ + DSIHOST.lpcr().modify(|w| { + w.set_dep(DE_POLARITY); + w.set_hsp(HS_POLARITY); + w.set_vsp(VS_POLARITY); + }); + + /* Select the color coding for the host */ + DSIHOST.lcolcr().modify(|w| w.set_colc(COLOR_CODING)); + + /* Select the color coding for the wrapper */ + DSIHOST.wcfgr().modify(|w| w.set_colmux(COLOR_CODING)); + + /* Set the Horizontal Synchronization Active (HSA) in lane byte clock cycles */ + DSIHOST.vhsacr().modify(|w| w.set_hsa(HORIZONTAL_SYNC_ACTIVE)); + + /* Set the Horizontal Back Porch (HBP) in lane byte clock cycles */ + DSIHOST.vhbpcr().modify(|w| w.set_hbp(HORIZONTAL_BACK_PORCH)); + + /* Set the total line time (HLINE=HSA+HBP+HACT+HFP) in lane byte clock cycles */ + DSIHOST.vlcr().modify(|w| w.set_hline(HORIZONTAL_LINE)); + + /* Set the Vertical Synchronization Active (VSA) */ + DSIHOST.vvsacr().modify(|w| w.set_vsa(VERTICAL_SYNC_ACTIVE)); + + /* Set the Vertical Back Porch (VBP)*/ + DSIHOST.vvbpcr().modify(|w| w.set_vbp(VERTICAL_BACK_PORCH)); + + /* Set the Vertical Front Porch (VFP)*/ + DSIHOST.vvfpcr().modify(|w| w.set_vfp(VERTICAL_FRONT_PORCH)); + + /* Set the Vertical Active period*/ + DSIHOST.vvacr().modify(|w| w.set_va(VERTICAL_ACTIVE)); + + /* Configure the command transmission mode */ + DSIHOST.vmcr().modify(|w| w.set_lpce(LP_COMMAND_ENABLE)); + + /* Low power largest packet size */ + DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE)); + + /* Low power VACT largest packet size */ + DSIHOST.lpmcr().modify(|w| w.set_lpsize(LP_LARGEST_PACKET_SIZE)); + DSIHOST.lpmcr().modify(|w| w.set_vlpsize(LPVACT_LARGEST_PACKET_SIZE)); + + /* Enable LP transition in HFP period */ + DSIHOST.vmcr().modify(|w| w.set_lphfpe(LPHORIZONTAL_FRONT_PORCH_ENABLE)); + + /* Enable LP transition in HBP period */ + DSIHOST.vmcr().modify(|w| w.set_lphbpe(LPHORIZONTAL_BACK_PORCH_ENABLE)); + + /* Enable LP transition in VACT period */ + DSIHOST.vmcr().modify(|w| w.set_lpvae(LPVERTICAL_ACTIVE_ENABLE)); + + /* Enable LP transition in VFP period */ + DSIHOST.vmcr().modify(|w| w.set_lpvfpe(LPVERTICAL_FRONT_PORCH_ENABLE)); + + /* Enable LP transition in VBP period */ + DSIHOST.vmcr().modify(|w| w.set_lpvbpe(LPVERTICAL_BACK_PORCH_ENABLE)); + + /* Enable LP transition in vertical sync period */ + DSIHOST.vmcr().modify(|w| w.set_lpvsae(LPVERTICAL_SYNC_ACTIVE_ENABLE)); + + /* Enable the request for an acknowledge response at the end of a frame */ + DSIHOST.vmcr().modify(|w| w.set_fbtaae(FRAME_BTAACKNOWLEDGE_ENABLE)); + + /* Configure DSI PHY HS2LP and LP2HS timings */ + const CLOCK_LANE_HS2_LPTIME: u16 = 35; + const CLOCK_LANE_LP2_HSTIME: u16 = 35; + const DATA_LANE_HS2_LPTIME: u8 = 35; + const DATA_LANE_LP2_HSTIME: u8 = 35; + const DATA_LANE_MAX_READ_TIME: u16 = 0; + const STOP_WAIT_TIME: u8 = 10; + + const MAX_TIME: u16 = if CLOCK_LANE_HS2_LPTIME > CLOCK_LANE_LP2_HSTIME { + CLOCK_LANE_HS2_LPTIME + } else { + CLOCK_LANE_LP2_HSTIME + }; + + /* Clock lane timer configuration */ + + /* In Automatic Clock Lane control mode, the DSI Host can turn off the clock lane between two + High-Speed transmission. + To do so, the DSI Host calculates the time required for the clock lane to change from HighSpeed + to Low-Power and from Low-Power to High-Speed. + This timings are configured by the HS2LP_TIME and LP2HS_TIME in the DSI Host Clock Lane Timer Configuration + Register (DSI_CLTCR). + But the DSI Host is not calculating LP2HS_TIME + HS2LP_TIME but 2 x HS2LP_TIME. + + Workaround : Configure HS2LP_TIME and LP2HS_TIME with the same value being the max of HS2LP_TIME or LP2HS_TIME. + */ + + DSIHOST.cltcr().modify(|w| { + w.set_hs2lp_time(MAX_TIME); + w.set_lp2hs_time(MAX_TIME) + }); + + // Data lane timer configuration + DSIHOST.dltcr().modify(|w| { + w.set_hs2lp_time(DATA_LANE_HS2_LPTIME); + w.set_lp2hs_time(DATA_LANE_LP2_HSTIME); + w.set_mrd_time(DATA_LANE_MAX_READ_TIME); + }); + + // Configure the wait period to request HS transmission after a stop state + DSIHOST.pconfr().modify(|w| w.set_sw_time(STOP_WAIT_TIME)); + + const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0 + + const LTDC_DE_POLARITY: Depol = if !DE_POLARITY { + Depol::ACTIVELOW + } else { + Depol::ACTIVEHIGH + }; + const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY { + Vspol::ACTIVEHIGH + } else { + Vspol::ACTIVELOW + }; + + const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY { + Hspol::ACTIVEHIGH + } else { + Hspol::ACTIVELOW + }; + + /* Timing Configuration */ + const HORIZONTAL_SYNC: u16 = HSA - 1; + const VERTICAL_SYNC: u16 = VERTICAL_SYNC_ACTIVE - 1; + const ACCUMULATED_HBP: u16 = HSA + HBP - 1; + const ACCUMULATED_VBP: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH - 1; + const ACCUMULATED_ACTIVE_W: u16 = LCD_X_SIZE + HSA + HBP - 1; + const ACCUMULATED_ACTIVE_H: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE - 1; + const TOTAL_WIDTH: u16 = LCD_X_SIZE + HSA + HBP + HFP - 1; + const TOTAL_HEIGHT: u16 = VERTICAL_SYNC_ACTIVE + VERTICAL_BACK_PORCH + VERTICAL_ACTIVE + VERTICAL_FRONT_PORCH - 1; + + // DISABLE LTDC before making changes + ltdc.disable(); + + // Configure the HS, VS, DE and PC polarity + LTDC.gcr().modify(|w| { + w.set_hspol(LTDC_HS_POLARITY); + w.set_vspol(LTDC_VS_POLARITY); + w.set_depol(LTDC_DE_POLARITY); + w.set_pcpol(Pcpol::RISINGEDGE); + }); + + // Set Synchronization size + LTDC.sscr().modify(|w| { + w.set_hsw(HORIZONTAL_SYNC); + w.set_vsh(VERTICAL_SYNC) + }); + + // Set Accumulated Back porch + LTDC.bpcr().modify(|w| { + w.set_ahbp(ACCUMULATED_HBP); + w.set_avbp(ACCUMULATED_VBP); + }); + + // Set Accumulated Active Width + LTDC.awcr().modify(|w| { + w.set_aah(ACCUMULATED_ACTIVE_H); + w.set_aaw(ACCUMULATED_ACTIVE_W); + }); + + // Set Total Width + LTDC.twcr().modify(|w| { + w.set_totalh(TOTAL_HEIGHT); + w.set_totalw(TOTAL_WIDTH); + }); + + // Set the background color value + LTDC.bccr().modify(|w| { + w.set_bcred(0); + w.set_bcgreen(0); + w.set_bcblue(0) + }); + + // Enable the Transfer Error and FIFO underrun interrupts + LTDC.ier().modify(|w| { + w.set_terrie(true); + w.set_fuie(true); + }); + + // ENABLE LTDC after making changes + ltdc.enable(); + + dsi.enable(); + dsi.enable_wrapper_dsi(); + + // First, delay 120 ms (reason unknown, STM32 Cube Example does it) + blocking_delay_ms(120); + + // 1 to 26 + dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_1[0], &NT35510_WRITES_1[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_2[0], &NT35510_WRITES_2[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_3[0], &NT35510_WRITES_3[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_4[0], &NT35510_WRITES_4[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_5[0], &NT35510_WRITES_5[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_6[0], &NT35510_WRITES_6[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_7[0], &NT35510_WRITES_7[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_8[0], &NT35510_WRITES_8[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_9[0], &NT35510_WRITES_9[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_10[0], &NT35510_WRITES_10[1..]).unwrap(); + // 11 missing + dsi.write_cmd(0, NT35510_WRITES_12[0], &NT35510_WRITES_12[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_13[0], &NT35510_WRITES_13[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_14[0], &NT35510_WRITES_14[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_15[0], &NT35510_WRITES_15[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_16[0], &NT35510_WRITES_16[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_17[0], &NT35510_WRITES_17[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_18[0], &NT35510_WRITES_18[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_19[0], &NT35510_WRITES_19[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_20[0], &NT35510_WRITES_20[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_21[0], &NT35510_WRITES_21[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_22[0], &NT35510_WRITES_22[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_23[0], &NT35510_WRITES_23[1..]).unwrap(); + dsi.write_cmd(0, NT35510_WRITES_24[0], &NT35510_WRITES_24[1..]).unwrap(); + + // Tear on + dsi.write_cmd(0, NT35510_WRITES_26[0], &NT35510_WRITES_26[1..]).unwrap(); + + // Set Pixel color format to RGB888 + dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); + + // Add a delay, otherwise MADCTL not taken + blocking_delay_ms(200); + + // Configure orientation as landscape + dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..]) + .unwrap(); + dsi.write_cmd(0, NT35510_CASET_LANDSCAPE[0], &NT35510_CASET_LANDSCAPE[1..]) + .unwrap(); + dsi.write_cmd(0, NT35510_RASET_LANDSCAPE[0], &NT35510_RASET_LANDSCAPE[1..]) + .unwrap(); + + // Sleep out + dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap(); + + // Wait for sleep out exit + blocking_delay_ms(120); + + // Configure COLOR_CODING + dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); + + /* CABC : Content Adaptive Backlight Control section start >> */ + /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */ + dsi.write_cmd(0, NT35510_WRITES_31[0], &NT35510_WRITES_31[1..]).unwrap(); + /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */ + dsi.write_cmd(0, NT35510_WRITES_32[0], &NT35510_WRITES_32[1..]).unwrap(); + /* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */ + dsi.write_cmd(0, NT35510_WRITES_33[0], &NT35510_WRITES_33[1..]).unwrap(); + /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */ + dsi.write_cmd(0, NT35510_WRITES_34[0], &NT35510_WRITES_34[1..]).unwrap(); + /* CABC : Content Adaptive Backlight Control section end << */ + /* Display on */ + dsi.write_cmd(0, NT35510_WRITES_30[0], &NT35510_WRITES_30[1..]).unwrap(); + + /* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */ + /* DSI host from LTDC incoming pixels in video mode */ + dsi.write_cmd(0, NT35510_WRITES_35[0], &NT35510_WRITES_35[1..]).unwrap(); + + /* Initialize the LCD pixel width and pixel height */ + const WINDOW_X0: u16 = 0; + const WINDOW_X1: u16 = LCD_X_SIZE; // 480 for ferris + const WINDOW_Y0: u16 = 0; + const WINDOW_Y1: u16 = LCD_Y_SIZE; // 800 for ferris + const PIXEL_FORMAT: Pf = Pf::ARGB8888; + //const FBStartAdress: u16 = FB_Address; + const ALPHA: u8 = 255; + const ALPHA0: u8 = 0; + const BACKCOLOR_BLUE: u8 = 0; + const BACKCOLOR_GREEN: u8 = 0; + const BACKCOLOR_RED: u8 = 0; + const IMAGE_WIDTH: u16 = LCD_X_SIZE; // 480 for ferris + const IMAGE_HEIGHT: u16 = LCD_Y_SIZE; // 800 for ferris + + const PIXEL_SIZE: u8 = match PIXEL_FORMAT { + Pf::ARGB8888 => 4, + Pf::RGB888 => 3, + Pf::ARGB4444 | Pf::RGB565 | Pf::ARGB1555 | Pf::AL88 => 2, + _ => 1, + }; + + // Configure the horizontal start and stop position + LTDC.layer(0).whpcr().write(|w| { + w.set_whstpos(LTDC.bpcr().read().ahbp() + 1 + WINDOW_X0); + w.set_whsppos(LTDC.bpcr().read().ahbp() + WINDOW_X1); + }); + + // Configures the vertical start and stop position + LTDC.layer(0).wvpcr().write(|w| { + w.set_wvstpos(LTDC.bpcr().read().avbp() + 1 + WINDOW_Y0); + w.set_wvsppos(LTDC.bpcr().read().avbp() + WINDOW_Y1); + }); + + // Specify the pixel format + LTDC.layer(0).pfcr().write(|w| w.set_pf(PIXEL_FORMAT)); + + // Configures the default color values as zero + LTDC.layer(0).dccr().modify(|w| { + w.set_dcblue(BACKCOLOR_BLUE); + w.set_dcgreen(BACKCOLOR_GREEN); + w.set_dcred(BACKCOLOR_RED); + w.set_dcalpha(ALPHA0); + }); + + // Specifies the constant ALPHA value + LTDC.layer(0).cacr().write(|w| w.set_consta(ALPHA)); + + // Specifies the blending factors + LTDC.layer(0).bfcr().write(|w| { + w.set_bf1(Bf1::CONSTANT); + w.set_bf2(Bf2::CONSTANT); + }); + + // Configure the color frame buffer start address + let fb_start_address: u32 = &FERRIS_IMAGE[0] as *const _ as u32; + info!("Setting Framebuffer Start Address: {:010x}", fb_start_address); + LTDC.layer(0).cfbar().write(|w| w.set_cfbadd(fb_start_address)); + + // Configures the color frame buffer pitch in byte + LTDC.layer(0).cfblr().write(|w| { + w.set_cfbp(IMAGE_WIDTH * PIXEL_SIZE as u16); + w.set_cfbll(((WINDOW_X1 - WINDOW_X0) * PIXEL_SIZE as u16) + 3); + }); + + // Configures the frame buffer line number + LTDC.layer(0).cfblnr().write(|w| w.set_cfblnbr(IMAGE_HEIGHT)); + + // Enable LTDC_Layer by setting LEN bit + LTDC.layer(0).cr().modify(|w| w.set_len(true)); + + //LTDC->SRCR = LTDC_SRCR_IMR; + LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD)); + + blocking_delay_ms(5000); + + const READ_SIZE: u16 = 1; + let mut data = [1u8; READ_SIZE as usize]; + dsi.read(0, PacketType::DcsShortPktRead(0xDA), READ_SIZE, &mut data) + .unwrap(); + info!("Display ID1: {:#04x}", data); + + dsi.read(0, PacketType::DcsShortPktRead(0xDB), READ_SIZE, &mut data) + .unwrap(); + info!("Display ID2: {:#04x}", data); + + dsi.read(0, PacketType::DcsShortPktRead(0xDC), READ_SIZE, &mut data) + .unwrap(); + info!("Display ID3: {:#04x}", data); + + blocking_delay_ms(500); + + info!("Config done, start blinking LED"); + loop { + led.set_high(); + Timer::after_millis(1000).await; + + // Increase screen brightness + dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0xFF]).unwrap(); + + led.set_low(); + Timer::after_millis(1000).await; + + // Reduce screen brightness + dsi.write_cmd(0, NT35510_CMD_WRDISBV, &[0x50]).unwrap(); + } +} + +const NT35510_WRITES_0: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01]; // LV2: Page 1 enable +const NT35510_WRITES_1: &[u8] = &[0xB0, 0x03, 0x03, 0x03]; // AVDD: 5.2V +const NT35510_WRITES_2: &[u8] = &[0xB6, 0x46, 0x46, 0x46]; // AVDD: Ratio +const NT35510_WRITES_3: &[u8] = &[0xB1, 0x03, 0x03, 0x03]; // AVEE: -5.2V +const NT35510_WRITES_4: &[u8] = &[0xB7, 0x36, 0x36, 0x36]; // AVEE: Ratio +const NT35510_WRITES_5: &[u8] = &[0xB2, 0x00, 0x00, 0x02]; // VCL: -2.5V +const NT35510_WRITES_6: &[u8] = &[0xB8, 0x26, 0x26, 0x26]; // VCL: Ratio +const NT35510_WRITES_7: &[u8] = &[0xBF, 0x01]; // VGH: 15V (Free Pump) +const NT35510_WRITES_8: &[u8] = &[0xB3, 0x09, 0x09, 0x09]; +const NT35510_WRITES_9: &[u8] = &[0xB9, 0x36, 0x36, 0x36]; // VGH: Ratio +const NT35510_WRITES_10: &[u8] = &[0xB5, 0x08, 0x08, 0x08]; // VGL_REG: -10V +const NT35510_WRITES_12: &[u8] = &[0xBA, 0x26, 0x26, 0x26]; // VGLX: Ratio +const NT35510_WRITES_13: &[u8] = &[0xBC, 0x00, 0x80, 0x00]; // VGMP/VGSP: 4.5V/0V +const NT35510_WRITES_14: &[u8] = &[0xBD, 0x00, 0x80, 0x00]; // VGMN/VGSN:-4.5V/0V +const NT35510_WRITES_15: &[u8] = &[0xBE, 0x00, 0x50]; // VCOM: -1.325V +const NT35510_WRITES_16: &[u8] = &[0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00]; // LV2: Page 0 enable +const NT35510_WRITES_17: &[u8] = &[0xB1, 0xFC, 0x00]; // Display control +const NT35510_WRITES_18: &[u8] = &[0xB6, 0x03]; // Src hold time +const NT35510_WRITES_19: &[u8] = &[0xB5, 0x51]; +const NT35510_WRITES_20: &[u8] = &[0x00, 0x00, 0xB7]; // Gate EQ control +const NT35510_WRITES_21: &[u8] = &[0xB8, 0x01, 0x02, 0x02, 0x02]; // Src EQ control(Mode2) +const NT35510_WRITES_22: &[u8] = &[0xBC, 0x00, 0x00, 0x00]; // Inv. mode(2-dot) +const NT35510_WRITES_23: &[u8] = &[0xCC, 0x03, 0x00, 0x00]; +const NT35510_WRITES_24: &[u8] = &[0xBA, 0x01]; + +const _NT35510_MADCTL_PORTRAIT: &[u8] = &[NT35510_CMD_MADCTL, 0x00]; +const _NT35510_CASET_PORTRAIT: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x01, 0xDF]; +const _NT35510_RASET_PORTRAIT: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x03, 0x1F]; +const NT35510_MADCTL_LANDSCAPE: &[u8] = &[NT35510_CMD_MADCTL, 0x60]; +const NT35510_CASET_LANDSCAPE: &[u8] = &[NT35510_CMD_CASET, 0x00, 0x00, 0x03, 0x1F]; +const NT35510_RASET_LANDSCAPE: &[u8] = &[NT35510_CMD_RASET, 0x00, 0x00, 0x01, 0xDF]; + +const NT35510_WRITES_26: &[u8] = &[NT35510_CMD_TEEON, 0x00]; // Tear on +const NT35510_WRITES_27: &[u8] = &[NT35510_CMD_SLPOUT, 0x00]; // Sleep out + // 28,29 missing +const NT35510_WRITES_30: &[u8] = &[NT35510_CMD_DISPON, 0x00]; // Display on + +const NT35510_WRITES_31: &[u8] = &[NT35510_CMD_WRDISBV, 0x7F]; +const NT35510_WRITES_32: &[u8] = &[NT35510_CMD_WRCTRLD, 0x2C]; +const NT35510_WRITES_33: &[u8] = &[NT35510_CMD_WRCABC, 0x02]; +const NT35510_WRITES_34: &[u8] = &[NT35510_CMD_WRCABCMB, 0xFF]; +const NT35510_WRITES_35: &[u8] = &[NT35510_CMD_RAMWR, 0x00]; + +//const NT35510_WRITES_36: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB565]; // FIXME: Example sets it to 888 but rest of the code seems to configure DSI for 565 +const NT35510_WRITES_37: &[u8] = &[NT35510_CMD_COLMOD, NT35510_COLMOD_RGB888]; + +// More of these: https://elixir.bootlin.com/linux/latest/source/include/video/mipi_display.h#L83 +const _NT35510_CMD_TEEON_GET_DISPLAY_ID: u8 = 0x04; + +const NT35510_CMD_TEEON: u8 = 0x35; +const NT35510_CMD_MADCTL: u8 = 0x36; + +const NT35510_CMD_SLPOUT: u8 = 0x11; +const NT35510_CMD_DISPON: u8 = 0x29; +const NT35510_CMD_CASET: u8 = 0x2A; +const NT35510_CMD_RASET: u8 = 0x2B; +const NT35510_CMD_RAMWR: u8 = 0x2C; /* Memory write */ +const NT35510_CMD_COLMOD: u8 = 0x3A; + +const NT35510_CMD_WRDISBV: u8 = 0x51; /* Write display brightness */ +const _NT35510_CMD_RDDISBV: u8 = 0x52; /* Read display brightness */ +const NT35510_CMD_WRCTRLD: u8 = 0x53; /* Write CTRL display */ +const _NT35510_CMD_RDCTRLD: u8 = 0x54; /* Read CTRL display value */ +const NT35510_CMD_WRCABC: u8 = 0x55; /* Write content adaptative brightness control */ +const NT35510_CMD_WRCABCMB: u8 = 0x5E; /* Write CABC minimum brightness */ + +const _NT35510_COLMOD_RGB565: u8 = 0x55; +const NT35510_COLMOD_RGB888: u8 = 0x77; diff --git a/examples/stm32f469/src/bin/ferris.bin b/examples/stm32f469/src/bin/ferris.bin new file mode 100644 index 000000000..ae1c466be --- /dev/null +++ b/examples/stm32f469/src/bin/ferris.bin @@ -0,0 +1,70 @@ +f2Hx$$ -'edV~-R%a_5}+lD '`EM ]hcdu+h40@N +7@ +RS -^XWs(9ye +=wFF@m { +I~ ;VAcnn +E |!e5;O +%.x +[K)/ +PGJagUgg0YT_{3b7)n|]C u;XJ:0\V ]n i )*hF_=[pv +2FpM uFc$5HP +T3C;vb;;f$] 0C-I-Vxm1HOk +2j)5eqJuTmLr/G 74q<tN0zNY"Q6Nt 1yP. +=cG(\DPvp+ Qqx}t)Zg_''XR\FQR~5`7d= 7hGVE.-yE8 !"x.n!0f2m3!e0j#_HYm#FKXF&Me |W & (,:GR[c#j#q'x'}~~~~~~~~~~*~~~~~~~~~~~~~~~~~~~*~~~~~~~~~~~~~~~~~~~~~~~~~~~.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||6~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||6~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{=d02Fr%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{=~N9|zzz|A( Uz/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{;^zzzzzzzzzzzzG2Kb~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzz|~a@zzzyyyyyyyyyyyyy.-i~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzz {J zyyyyyyyyyyyyyyyyyyyyy:IHd}t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzj4yyyyyyyyyyyyyyyyyyyyyyyyyy|%H|_~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyy z?*~{yyyyyyyyyyyyyyyyyyyyyyyyyyyyyza'\|S~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||{||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyth zyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxx y!1A-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zEQ={yyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxx~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwx ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwJ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwww xw~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww x~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww${(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvpM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvve~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuun$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}|||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuK~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuwz~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu+{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttt9~&~~~~~~~~~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttiV~~~~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttts}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttt~}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttss+y*}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssr8}}}}}||||||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssS|||||||||||||||||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssu~||||||||||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssrrr9|||||||||||||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrQ!||||||||||{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{z{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttsttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrlZ{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr~{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr{{{{{{{{{{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqq r4{{{{{{{{zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqkKzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqazzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzzzzzzzzzzzzzzzzzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp;{zzzzzzzzyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppa#|yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppppppppppp|^yyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppppppppppppppppppppppppp qjyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppppppppppppppppppppppppppppppooo pyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppppppppppppppppppppppppppppppooooooooooooooooooo;z+|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppppppppppppppppppppppppppppppooooooooooooooooooooooooooooG<xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppppppppppppppppppppppppppppppppooooooooooooooooooooooooooooooooooooolUxxxxxxxxxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppppppppppppppppppppppppppppppooooooooooooooooooooooooooooooooooooooooooooooonnnnnnp}yxxxxxxxxxxxxxxxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttssssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppppppppppppppppppppppppppppppppppppppppppppppooooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnd3~xxxxxxxxxy z,|2}9@EJNTW[_bfimry~%{xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttttttttttttttttttttttttttttttttttttttttttttttsssssssssssssssssssssssssssssssssssssssssssssrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpppppppppppppppppppppppppppppppppppppppppppppppoooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn1v|zvspjec\VRJ~D|ypppppppppppppppppppppppppppppppppooooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmlllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeapppppppppppppppppppppppppoooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeee f6wpppppppppppppppooooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmlllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;rwooooooooooooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedd}.toooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddd[oooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddduoooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddfRnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddX~nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccG{nnnnnnnnnnnnnnnnnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccc#hJ{nnnnnnnnnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccAs~nnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmlllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccc'qmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbkcmmmmmmmmmmmmmmmmmmmmmmmmmmmmllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbb'h+rmmmmmmmmmmmmlllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbzkmmmmmlllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbnllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaquGylllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaesX'plllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaCr}m^N{8t mllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````cNwl~d9tonmllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````` ac#f.iKu}o[Bwmllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````bU{}iGy7t,q n lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````________ `+g@oMvdYmkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````________________________DqW}mkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````__________________________________________HsHxkkkkkkkkkkkkkkkkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^bckkkkkkkkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^bkkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^VzLyjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^c-pjjjjjjjjjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]!mjjjjjjjjjjjjjjjjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]`ljjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]].fkiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]kiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\7i%miiiiiiiiiiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\j5qiiiiiiiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccddddddddddddccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabba[TQONOQU[aaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\khhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccbbaUI?70{,s+q)o*p+r-v29DS`bbcccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`[C1'mYC4 ) ' -6E[)p3J]_`````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\@m+nhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccc_XTE.uBH8RXabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```^TD U.yOX```````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[~ihhhhhhhhhhhhhgggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccc`K7&t =;0C^bbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`````````````````]F.. [;W``______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[zX|hhhhhhggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccb]+_iv[[[3=Zabbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````bN{OOO +?Z______________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[Dn8pgggggggggggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbb^;|RRR6@Zbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````_,q((( [F_____________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[iggggggggggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbb1Q DK`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````]TTT#/}X___________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[viggggggggggggggggggfffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbaHu + + +5Zaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````___]uuuVN__^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZMr?rggffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbC|#aSaaaaaaaaaaaa``````````````````````````````````````````````__________________Yo{fff4B\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZ_!jfffffffffffffffffffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'nBNaaa``````````````````````````````````````````````_________________________MPUpUUU=Z^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ{ugfffffffffffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddcccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaa^qqq:Ha```````````````````````````````________________________________________B!>&&&4Z^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZPtMvfffffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaj5556L```````````````````````______________________________________________\? .Z]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYY'`/leeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*mKS```````_______________________________________________^^^^^^^^^^^^^[:,,,$$$2X]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYgeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap333TX____________________________________________^^^^^^^^^^^^^^^^^^^^^];8\]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYKp_}eeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa_0\___________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^P %000S]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.c5meeeeeeeeeedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````_=E____________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'kssshhh-{]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXX Yhedddddddddddddddddddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````^ccc U___________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]B :P\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXUum +edddddddddddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````^-|\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]V\+++ ;[\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXX*aDqdddddddddddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````Ik K^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]EMMMKV\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX[(iddddddddddddddccccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______^x}999$d\^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]Y@bbb[[[D[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]zzeccccccccccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________ITTTG^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\]:uuuN[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWW[Uxccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````_____________________________])mbbbXZ]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\VNI[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWZ.jcccccccccccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````____________________________________________N /mmm"G]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\B2[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWe~ecccccccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````______________________________________________^^^^^^\7 vvv2[]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\X#dPRZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW0bdbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^Z !}}} $V]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[NIZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVV8lbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^?{{{=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[)q-YZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVv#fbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\RtttE[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[R ,VZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVV5crcbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]I & + + +hhh!L\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[<zzzAZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVKraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]\8^^^9\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[X+}fffiii*xYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV Waaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]WVLLL)vX[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZP -SSS+++TRYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUU"[kaaaaaaaaaaaaaaaaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]Rkkk000:Q[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZG444$GYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUX1iaaaaaa``````````````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\8888N[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZY)t>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU6j`````````````````````````````````````````````______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\?D[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZY #rrr*|VXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUr9k`````````````````````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\OFFF2ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYK###???2TXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTYCn```````````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]<  [YZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYZ7NXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTGp````````````````_______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\1eee1YZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYZ*{;;;EEE:WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTChOs``______________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[V#iZZZ###YZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYW"j (uXWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS-]Tu_________________________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[O7 SYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXNL;;;888QXWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSVi\x__________________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[LFFFJYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXJ 2wwwxxx?SWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSJk_z___________________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[IvvvBBBDYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXG ,FVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS*\h____________^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZY:ooo?ZYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXE@VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRig~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZY)u*** 9YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWD;VVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRAfs +_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZYSxxx6YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWAYYYRRR8VVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRr +_^^^^^^^^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZX? ggg6YXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWW>5VUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRbyya^^^^^^^^^^^^^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYW,<<UVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU$t +7SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOO=aAj\\\\\\\\\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWF%mUVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUV0;SSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOUKn\\\\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWJ7UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTB ,DSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOWqQp[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWOTGUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTQAORRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNN8^Sq[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVU* +(JUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTS&s]SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNQ|_w[[[[[[[[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVW8 + fPUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSB3RRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN]t\v[[[[[[[[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVO$/TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSKBJRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN3\g{ \[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV#i<TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSQ,^ORRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMM}j}\ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUG 1PTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSB!8PQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMPkp [ZZZZZZZZZZZZZZZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUQ!j(zTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\@FQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONMMMMMMMMMMMMMMMMMMMMMMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMv]ZZZZZZZZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUU;HSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRC&zQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNMLLLLLLLLLLLLLLLLLLLLLLLMNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLo| [ZZZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUURXdOSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRO&{HQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLL6[]YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTUD;SSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRC /2PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQ]YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTR.PNSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR*ZIPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL N^t]YYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTKN9SSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQMP=PPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL-X0aYYYYYYYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTB hORRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQ@(3OPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQ*`YXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSR6 +.DRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ2'LPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKg:dXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSQ,0QRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPN+ kJOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL1YPQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOON5cBMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLGe\sWWWWWWWWWWWWWWWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQFZPAQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOON4'V8MNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL N^uWWWWWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQK0 jGPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOON9B7GONNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLk~hz WVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQP@U  ,1NPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNMAGD0KMNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJfj{VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQM4A nAPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNF-k6HMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLxm}XVVVVVVVVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPOJ-#I>LPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNL@Z +-%|BIMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLv WVVVVVVVVVVVVVVVVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUURJ>JQTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPG.Uk6MOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN:$ 8M&5IMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKKJIIIIIJKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLqtYVVUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTSF6,+,5BQTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPI9C ),BJOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMKD:$x ( , j5AELMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKGC>:765333333468:=AEKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLR}YUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTSL5,+++++,.>NRTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPON?%xJ + 6^%{=MNOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMLLH:2,***.4>JLLMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLE5-,,++++++++++++++++,,,1:DHJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLO| ZUUUUUUUUUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTN=,+++++++++*-:FQTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOF<-;C#t3<BLPOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNNMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD,+++++++++++++++++++++++++*-4;CJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLO(\UUUUUUUUUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTRC/++++++++++++++,0@ORSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOONLG2&x-6?HKLMNOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL9++++++++++++++++++++++++++++++-/:GKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL N-]UUUUUUUUUUUUUTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTM9+++++++++++++++++++-<HOTSSSSSSSSSSSSSSSSSRNNPQRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLI1+++++++++++++++++++++++++++++++++,5AHLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLO1^TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSTH0++++++++++++++++++++++-2?NSSSSSSRRRRRRRRRRRQLLMMOPRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD+++++++++++++++++ +.++++++++++++++++++,0<JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOBdTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSS1]{Y`++++++++++++++++++++++++++,9INRRRRRRRRRRRRRRRNLLLLLLNPQRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL7++++++++++++++++4C3++++++++++++++++++++/@ILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL'Uo~TTTTTTTTTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSHgx{/++++++++++++++++++++++++++++2=IRRRRRRRRRRRRRRMLLLLLLLMMNPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG,+++++++++++++++8G+++++++++++++++++++++++3A\"SLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLh|%ZTTTTTTTTTTTTTTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS TQl->++++++++++++++++++++++++++++++-3DNQRRRRRRRRRRPLLLLLLLLLLLMNPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL9++++++++++++++ +.Yb+++++++++++++++++++++++/@\sOLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL USSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRSSat]d++++++++++++++++++++++++++++++++*/;FNRQQQQQQQQNLLLLLLLLLLLLLMNOPQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLH0++++++++++++++U^+++++++++++++++++++++++fm +MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#Sq~SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRS`t1++++++++++++++++++++++++++++++++++-0;JPQQQQQQQMLLLLLLLLLLLLLLLLMNOQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL?+++++++++++++3C8G+++++++++++++++++++++++9]LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLqgxSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRR S`tin++++++++++++++++++++++++++++++++++++++3BJOQQQQNLLLLLLLLLLLLLLLLLLLMMNOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ3++++++++++++el+++++++++++++++++++++++rx,WLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOhySSSSSSSSSSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNj5D+++++++++++++++++++++++++++++++++++++++.6AMQPPMLLLLLLLLLLLLLLLLLLLLLLMNOPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC+++++++++++!7pv++++++++++++++++++++++/@TmLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL8]r~SSSSSSSRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSrw,+++++++++++++++++++++++++++++++++++++++++-7ELNLLLLLLLLLLLLLLLLLLLLLLLLLMNOOPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK1+++++++++ +.S] +.++++++++++++++++++++++}LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQ+YU]++++++++++++++++++++++++++++++++++++++++++++09ELLLLLLLLLLLLLLLLLLLLLLLLLLLLMNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLA,+++++++++++++++++++++++++++++++4DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLEdURRRRRRRRRRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQ+Y6E+++++++++++++++++++++++++++++++++++++++++++++0HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMNOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKJJJJJJKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ5+++++++0ZbOY++++++++++++++++++++++LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL NNiRRRRRRRRRRRRRRRRRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQR|/+++++++++++++++++++++++++06E++++++++++++++++++9KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMNOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMIB=:85.)&#y${'*/68:>DLMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC+++++++:H+>+++++++++++++++++++++gnLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOj|RRRRRQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`f+++++++++++++++++++++++++4|sw4,+++++++++++++++,DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLKKKKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKJ?- q^A) 0Jf&6FKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL3+++++3tz +.++++++++++++++++++++%:h{LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL7^QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPo|BN+++++++++++++++++++++++++agZa0+++++++++++++++1JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLMKEB@>7.("t lha l#u'/7>@BEJMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIB:"t?.@ELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL?+++++fmai+++++++++++++++++++++LhLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLk~evQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPIf%9++++++++++++++++++++++++%9?L+++++++++++++++;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLC5,$V 0 +-T!y*3AKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD/!t /V(:LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLH1+++CO +.++++++++++++++++++++]dEdLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL5[&XQQQQQQQQQQQQQQQQQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP0Zuy +.++++++++++++++++++++++++quuy6E,++++++++++++.ELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJGA+A :&=FJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHA$y#$ 3 :@@= 6+@4EKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL=++CO++++++++++++++++++++%:9]LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL NixQQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQ~ci++++++++++++++++++++++++.?tw%9++++++++++++4KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMH8)D 5'5DMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLE4hQ'4:<>@@BBA@>=;8.h , 4,@MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG?CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG--?.?++++++++++++++++++++~%TLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIf>`PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOO[oFQ+++++++++++++++++++++++ +.v{_f%9,++++++++++;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJD(G>"r@JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKI1B =Z+AIJJKLLLLLLLLLLLLLKJIE3jF# +5$zDKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKJB5.:KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL2I +.+++++++++++++++++++AMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL{SPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOR';+++++++++++++++++++++++ISfk#8+++++++++.ELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMH;#x`8DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMF4=A+6DLMLLLLLLLLLLLLLLLLLLLLLLLMH:/T-CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIC;0++8JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLl{jp+++++++++++++++++++!8LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL NYmPPPPPPPPPPPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOn{ .++++++++++++++++++++++/bh3++++++++4KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ3`O,HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ7Y`;FJKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKF>gI-JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKE91,+++7IKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKFc3C+++++++++++++++++++sx]sLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL<_<_PPPPPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO0Zdj,++++++++++++++++++++++T\]d+=+++++++=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLH:E'1DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKA`M)>KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKA+OY>KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIE>2++++++5HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +L+++++++++++++++++++:HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL)WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNQ}GR++++++++++++++++++++++,pt%9+++++-ELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK8n *Y&19?@@@@@@@?8.$xOI0HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLF+ 5 15CKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKD2 "+GLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKC:3-+++++++6HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKBN+++++++++++++++++++LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL~tROOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNTk2B++++++++++++++++++++++RZpt7E/+++5JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKE!q&To+;HKKKLLLLLLLLLLLLKKKKF8(lM! >:JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK=KN.HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKF*@>?KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJE:/,+++++++++4HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKLg++++++++++++++++++ +.|LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLBbmzOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNR 7+++++++++++++++++++++&:~LU+++<LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIFKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG/ +-o5<FLMLLLLLLLLLLLLLLLLLLLLLLLMLD<5i$~>MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLE-1DKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKL@(.JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIC;2++++++++++++6HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKdk++++++++++++++++++8F9]LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL_qPONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN]ppt +.+++++++++++++++++++++fkT]6-CLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK808CJKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK=W/[8HJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLIG4W/ 4.HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKAM +!${DJKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKI;D aCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKJA5/-+++++++++++++5HKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK5D++++++++++++++++++RLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLl~TjNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMO_e+++++++++++++++++++++4nsAQILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLH/+*-5>DHLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLF0h1@LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@1XU?KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLI3b7JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJE- +I;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJE@6-++++++++++++++++6HJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ^r++++++++++++++++++{ +MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL<_OgNNNNNNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMN_qFQ+++++++++++++++++++++^epzNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLA,++++-04;CJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@^g?HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG<^ +3,KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG"u-FJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI<G ,0KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKC92.++++++++++++++++++8HJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ*TJU+++++++++++++++++DPsLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOCaNNNNNNNNNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM1X,=++++++++++++++++++++#8euLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK8++++++++++3<EHJLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ5;'>KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL?$ +-^BLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@R\<JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJD$,HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJGB8.++++++++++++++++++++,8IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ K++++++++++++++++++LhLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL]s<]MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLmz1+++++++++++++++++++,ioGbLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLI1++++++++++++/5:@GLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG&'BLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK@*B4LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL5;-DJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJH2$$}ELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJB:4.++++++++++++++++++++++,;IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ~W_+++++++++++++++++~LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL,W8[MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLRmr/+++++++++++++++++++2B%SLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLE-++++++++++++++,-19CIJKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAT)!sCKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKB o"*GLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ1 @5IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ;C]ELLLLLLLLLLLLLLLLLLLLLLLLLLLKJH?4-,++++++++++++++++++++++++,;IJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJWn 7++++++++++++++++JULLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLO1XMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLLLLLLLLLLLLLLetU]++++++++++++++++++++quvLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK=,+++++++++++++++++*,29>CGLLLLLLLLLLLLLLLLLLLLLLLLM:Hk;KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ:gnALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG*o>JIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII@aNALLLLLLLLLLLLLLLLLLLLLLLKF@:2,*++++++++++++++++++++++++++->IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII<\+++++++++++++++++=_LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLcw-WMMMMMMMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL/WAL+++++++++++++++++++#8]pLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK4++++++++++++++++++++++-.28@IKKLLLLLLLLLLLLLLLLLK1, +02ILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLI1 +2C=KLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLF s#yFIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIFlHBLLLLLLLLLLLLLLLLLLKJB70.,+++++++++++++++++++++++++++++-@IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII#QCO++++++++++++++++zLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL"S)ULLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLiw.?++++++++++++++++++,in:\LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLH0++++++++++++++++++++++++++*08?DGKLLLLLLLLLLLLI0&DLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC$~7JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC` //IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIF(2ALLLLLLLLLLLLLJFC<3,+++++++++++++++++++++++++++++++++0BIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII++++++++++++++++OYLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOQLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL%S,++++++++++++++++++3BMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLA-+++++++++++++++++++++++++++++,038>DKLLLLLLLH' 3;ILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLI; 2-JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL@T%:HIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIF-D@LLLLLLLLKF>72/++++++++++++++++++++++++++++++++++++2EIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIAM+++++++++++++++$9WoLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLh{}#SLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLbrns .++++++++++++++++++pto|MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL:+++++++++++++++++++++++++++++++++++,28@GHJG% #xCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD#{$xHLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLA8J>IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIH/:BLLJHF@6.+++++++++++++++++++++++++++++++++++++++,6GIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII Jn}++++++++++++++++|.XLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL2Zy NLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQY`,+++++++++++++++++#8SjLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ7+++++++++++++++++++++++++++++++++++++*,01n!3JLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ6 5 oGLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL> 7W@HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHF/H9:50+*+++++++++++++++++++++++++++++++++++++++++:GHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHVldl+++++++++++++++V_LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLxOLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL\n`LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLynzLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLGbah+++++++++++++++++]d@^KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ8+++++++++++++++++++++++++++++++)Y 3?KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKC[LALLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLAD(DGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGCVr+++++++++++++++++++++++++++++++++++-=FGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGK=J+++++++++++++ +.%TLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLBbo{OLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL M{IS++++++++++++++++6.VKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJ6+++++++++++++++++++++++++++++*iV@KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKF$}=BLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLDL&DGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGBN "++++++++++++++++++++++++++++++"8COU^^hJaGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG&P0+++++++++++++V_LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL +MlxLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL7[0@+++++++++++++++,]dKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKH3++++++++++++++++++++++++++++nmBKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKG-TCLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLD]%DGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG<@ +6'++++++++++++++++++++++++++AMuzRhGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGNT]+++++++++++++2CVoLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLjw MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLhv 7+++++++++++++++3p~JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ&QkrR[2B)<3-+++++++++++++++++++++v qDJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJH/EDLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLG s"vDGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG3B*++++++++++++++++++ -61BEQz~%PGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGN+++++++++++++3LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLRlgu MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL&Twz/+++++++++++++++PXZnKJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJMesx`gHR5+++++++++++++++++$%"zDJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ3XELLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLJ)kBGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG,d*++++++++++++++*=[dx}vGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.TQ[+++++++++++++gmLLLLLLLLLLLLLLLLLLLLLLLLLLLLL +MfuLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMardj+++++++++++++++,:ZJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJNfrvKT31 .-+++++++++' +3$EJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJI7%bILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLK+XCGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGD!v!+++++++-047FpvJcGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGL2++++++++++++-?.XLLLLLLLLLLLLLLLLLLLLLLLLLLLLLdsNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLOSZ,++++++++++++++DO3WJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJNfnsYaIS2B-++++)H!tEJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ5 2kHLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL5 S@FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF>B'++4ANZbms"NFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF?\ms++++++++++++5 +MLLLLLLLLLLLLLLLLLLLLLLLLLLLLZqbrLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLC`9F++++++++++++++/~$QJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJMekpIS/g"yEJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ: +/ 'HLLLLLLLLLLLLLLLLLLLLLLLLLLLLLM9 0=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97:XgwFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF?\#9++++++++++++rxnLLLLLLLLLLLLLLLLLLLLLLLLLLLL)Var NLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL Nt$9++++++++++++++8FyLIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII@]gCIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII7 +2o,-..0012344455555567755555444, 2 -:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, ]]]3UFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF GQg}++++++++++++;I:]LLLLLLLLLLLLLLLLLLLLLLLLLLLLbrLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL7[5++++++++++++++otq} +JIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII>\SAIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIJ8 +v+++++++++++++++++++++++++++( ?'4EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAO\]]xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFct2+++++++++++5LLLLLLLLLLLLLLLLLLLLLLLLLLLLfzbrMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLhvko +.+++++++++++++0@]nJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'RA@IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII7,"+++++++++++++++++++++++++*D+EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF=\\\=Z GFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF Gu}+++++++++++ +.SlLLLLLLLLLLLLLLLLLLLLLLLLLLL9]cr MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL MZa+++++++++++++,hmUiIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIOz:IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIJ4%+++++++++++++++++++++++*a%DEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEED-\\\IEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE>K+++++++++++LVLLLLLLLLLLLLLLLLLLLLLLLLLLLLbrLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLKeIS+++++++++++++3KcHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHJXk[jHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH4 <'++++++++++++++++++++++!gAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEAa\\\`qJb'OEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"M+++++++++++0xLLLLLLLLLLLLLLLLLLLLLLLLLLLj}bsNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLO|1A+++++++++++++?K;ZHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH>[~LHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG.W)++++++++++++++++++++%I>EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE6\]_RgHFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEG`5++++++++++0EdLLLLLLLLLLLLLLLLLLLLLLLLLL?``qLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL9[2++++++++++++,pu0UHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHLiw#PHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHG.c+++++++++++++++++++' 9 *9EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\dy]o3TEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEbspv+++++++++++T]PLLLLLLLLLLLLLLLLLLLLLLLLLObr MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLgvwz0++++++++++++0@,SHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHI1U.THHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHE& v+++++++++++++++++*_/EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.P\m3T$NIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEJu*=++++++++++ 7yLLLLLLLLLLLLLLLLLLLLLLLLLLobrMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLR`g+++++++++++++_eNHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHMdVjHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHCi($++++++++++++++++v&CEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE+Qy++++++++++ .!SLLLLLLLLLLLLLLLLLLLLLLLLLPjbrMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMWlNW++++++++++++/MGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGKMMNefests5KDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDG5++++++++++PLLLLLLLLLLLLLLLLLLLLLLLL\rbrNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLM^p}1+++++++++++5D{LGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHxGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDRgv{+++++++++ .w|uLLLLLLLLLLLLLLLLLLLLLLLL1YarLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL!Rmr/+++++++++++ko}HGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG N8UCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC D6E+++++++++8G-WLLLLLLLLLLLLLLLLLLLLLLLLcs MLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLB_T\+++++++++++)<}KFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"NRfCCCCCCCCCCG&M.P6T=XC\TgftvucqNbA[>Y:V5T/Q'MHDCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC+++++++syRlLLLLLLLLLLLLLLLLLLLLL7\r|LLLLLLLLLLLLLLLLLLLLLLLLLLLL^q/++++++++diwIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDE FGHII?ZZkmyGBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCF^0++++++:H$TLLLLLLLLLLLLLLLLLLLL +Mq|OLLLLLLLLLLLLLLLLLLLLLLLLLLQv{1+++++++1A2RDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD K7UE]Re[lgtx(LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>Xdk++++++0}LLLLLLLLLLLLLLLLLLLLLl~r}LLLLLLLLLLLLLLLLLLLLLLLLLLL>^bh,++++++,uxF]DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD1RSfesxK`AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE|2++++++'ULLLLLLLLLLLLLLLLLLLLJfuPLLLLLLLLLLLLLLLLLLLLLLLLLLbrNW+++++++=J\lGDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD KzlyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'Ldr++++++S\LLLLLLLLLLLLLLLLLLLLQt~ NLLLLLLLLLLLLLLLLLLLLLLLLLQBN+++++++zIDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD`oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAap&:+++++ .4[LLLLLLLLLLLLLLLLLLLLxOLLLLLLLLLLLLLLLLLLLLLLLLLEa';++++++CNC[DCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDH^FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEF] .+++++OLLLLLLLLLLLLLLLLLLLRkwPLLLLLLLLLLLLLLLLLLLLLLLLLjx0+++++5fsFCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC-P.OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgkq+++++`hdwLLLLLLLLLLLLLLLLLLL-Wy NLLLLLLLLLLLLLLLLLLLLLLLLPjn+++++,ek5SCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC&L{4Q@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@AD[@M++++7PLLLLLLLLLLLLLLLLLLLyQLLLLLLLLLLLLLLLLLLLLLLLLB_CO+++++8F]lICCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCDlx9T@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@DUf+++++}bwLLLLLLLLLLLLLLLLLLL_u{OLLLLLLLLLLLLLLLLLLLLLLLLWk1+++++?YCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCReM`@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@drkq++++JULLLLLLLLLLLLLLLLLLL?`~ RLLLLLLLLLLLLLLLLLLLLLLLMkxx{,++++JTjv+NBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.OCZ@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.N]l++++2ZqLLLLLLLLLLLLLLLLLLO|PLLLLLLLLLLLLLLLLLLLLLLL!RRZ++++,_m DBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Dp{Pb@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=W++++\dQLLLLLLLLLLLLLLLLLLuPLLLLLLLLLLLLLLLLLLLLLLL2X$9+++,joE[EBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCG]F[??????????????????????????????????????????????????????????????F]e+++ .WoLLLLLLLLLLLLLLLLLLIf}%SLLLLLLLLLLLLLLLLLLLLLLLNf1+++FPRdEBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBGH]??????????????????????????????????????????????????????????????F;I+++LLLLLLLLLLLLLLLLLL RPLLLLLLLLLLLLLLLLLLLLLL Np{ek,++6TeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA CQcCZ??????????????????????????????????????????????????????????????C4++LVNiLLLLLLLLLLLLLLLLLL*ULLLLLLLLLLLLLLLLLLLLLLQCN+++tx[i6RBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA H,L???????????????????????????????????????????????????????????????w++ .QLLLLLLLLLLLLLLLLL\s"RLLLLLLLLLLLLLLLLLLLLLL>]*=++HRSeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[j.M???????????????????????????????????????????????????????????????vW_++oueyLLLLLLLLLLLLLLLLL9]'TLLLLLLLLLLLLLLLLLLLLLM_p}1++Pb.N"IDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA$Jt~F>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>cp++9GLLLLLLLLLLLLLLLLL +M(TLLLLLLLLLLLLLLLLLLLLLP_f++vzs|&KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH]t~?>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>cp+0\rLLLLLLLLLLLLLLLLLv+ULLLLLLLLLLLLLLLLLLLLL-VJT+MWD@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ H_lRc>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Xhns+R[PLLLLLLLLLLLLLLLLPj2XLLLLLLLLLLLLLLLLLLLLLVk;H6Ehs@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'J~7Q>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Oa2C0AsLLLLLLLLLLLLLLLLP/WLLLLLLLLLLLLLLLLLLLLO|2BUe@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@E[$H>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Oa.?6[LLLLLLLLLLLLLLLL6ZLLLLLLLLLLLLLLLLLLLL4Y>V@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ BM``m=================================================================H\lrLLLLLLLLLLLLLLLLdw4YLLLLLLLLLLLLLLLLLLLLYmG@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Edp>U=================================================================G[1YLLLLLLLLLLLLLLL2Y8[MLLLLLLLLLLLLLLLLLLP} A????????????????????????????????????????????????????????????????? G[jkvE=================================================================DYLLLLLLLLLLLLLLLL=]LLLLLLLLLLLLLLLLLLLC`qzB??????????????????????????????????????????????????????????????????CoxFZ==================================================================G[SlLLLLLLLLLLLLLLLz@^LLLLLLLLLLLLLLLLLLLmyYh????????????????????????????????????????????????????????????????????.M_lhtE==================================================================H\)VLLLLLLLLLLLLLLPjA_LLLLLLLLLLLLLLLLLLNI]?????????????????????????????????????????????????????????????????????@Te&H===================================================================K^LLLLLLLLLLLLLLQC`LLLLLLLLLLLLLLLLLLPg:S>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>BVfWf=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>A,KvcoA<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Dboy!E<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>D>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>^lxD<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=w MLLLLLLLLLLL M}QhLLLLLLLLLLLLLLLMcsjt>==============================================================================9QXf`l.J;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AXoLLLLLLLLLLLLJfRhLLLLLLLLLLLLLLLOXg=================================================================================A\iN_<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+HLLLLLLLLLLLLRWlLLLLLLLLLLLLLLLOgUd==================================================================================='HVes|s|EX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1LLLLLLLLLLLLLXkMLLLLLLLLLLLLLPJ\====================================================================================>B#FM_}=SA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(H8PBWZh{fqAU(F::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::S<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<@Uu|We)G> =;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;`mLLLLLLLLLLXkLLLLLLLLLLLQ8P;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;|[g[h[g[hVdP_IZ?T7O"C:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::B`uLLLLLLLLLeyKdMLLLLLLLLLL\n]LLLLLLOf`k>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;:PzNhLLLL[r+ULLLLNfdn:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::dnK\:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::EX.WLLLL|QLLL N~(F:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;\h9P>:::::::::::::::::::::::::::::::::::::::::::::::::::::::::BK\(ULLL{"RLLL}Sa:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=jt[h>:::::::::::::::::::::::::::::::::::::::::::::::::::::BVu~"SLLXo{QLL^py?:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: \hzM^9P'F =:::::::::::::::::::::::;!C4MAUbnZpfp=::::::::::::::::::::::::::::::::::::::::::::::::7NpyZh?T C:::::::::::::=;QVdjt|Uc@::::::::::::::::::::::::::::::::::::::::::::@\h`k'F:::::::::::::::::::::::::::::::::::::::::Q`t{)G:::::::::::::::::::::::::::::::::::::BUN],H:::::::::::::::::::::::::::::::"CN^Ye;::::::::::::::::::::::::::@Tv}[g4L)G@;:::::::::::::::@*G=Rjtyks[gM] Date: Tue, 21 May 2024 23:41:45 +0200 Subject: rp/pwm: rename channel->slice in args, misc fix. --- examples/rp/src/bin/interrupt.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index d334d35d7..5b9d7027e 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -15,7 +15,6 @@ use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Blocking}; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; -use embassy_rp::peripherals::PWM_SLICE4; use embassy_rp::pwm::{Config, Pwm}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; @@ -26,7 +25,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; static COUNTER: AtomicU32 = AtomicU32::new(0); -static PWM: Mutex>>> = Mutex::new(RefCell::new(None)); +static PWM: Mutex>> = Mutex::new(RefCell::new(None)); static ADC: Mutex, adc::Channel)>>> = Mutex::new(RefCell::new(None)); static ADC_VALUES: Channel = Channel::new(); -- cgit From ec321595765ee63f1c14b72fb62d9d02344fa8dd Mon Sep 17 00:00:00 2001 From: René Herrero Date: Tue, 21 May 2024 17:14:31 -0500 Subject: added CAN example --- examples/stm32l4/src/bin/can.rs | 68 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 examples/stm32l4/src/bin/can.rs (limited to 'examples') diff --git a/examples/stm32l4/src/bin/can.rs b/examples/stm32l4/src/bin/can.rs new file mode 100644 index 000000000..3c4cdac24 --- /dev/null +++ b/examples/stm32l4/src/bin/can.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::can::filter::Mask32; +use embassy_stm32::can::{ + Can, Fifo, Frame, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, +}; +use embassy_stm32::peripherals::CAN1; +use embassy_stm32::{bind_interrupts, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + CAN1_RX0 => Rx0InterruptHandler; + CAN1_RX1 => Rx1InterruptHandler; + CAN1_SCE => SceInterruptHandler; + CAN1_TX => TxInterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Config::default()); + + let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); + + can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + + can.modify_config() + .set_loopback(true) // Receive own frames + .set_silent(true) + .set_bitrate(250_000); + + can.enable().await; + println!("CAN enabled"); + + let mut i = 0; + let mut last_read_ts = embassy_time::Instant::now(); + loop { + let frame = Frame::new_extended(0x123456F, &[i; 8]).unwrap(); + info!("Writing frame"); + + _ = can.write(&frame).await; + + match can.read().await { + Ok(envelope) => { + let (ts, rx_frame) = (envelope.ts, envelope.frame); + let delta = (ts - last_read_ts).as_millis(); + last_read_ts = ts; + info!( + "Rx: {} {:02x} --- {}ms", + rx_frame.header().len(), + rx_frame.data()[0..rx_frame.header().len() as usize], + delta, + ) + } + Err(err) => error!("Error in frame: {}", err), + } + + Timer::after_millis(250).await; + + i += 1; + if i > 2 { + break; + } + } +} -- cgit From e7161aa085bb145df6607eff5b2c2d0ed06acda1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 22 May 2024 00:23:14 +0200 Subject: stm32/qspi: remove DMA generic param. --- examples/stm32f7/src/bin/qspi.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs index 005694db3..90d319b7a 100644 --- a/examples/stm32f7/src/bin/qspi.rs +++ b/examples/stm32f7/src/bin/qspi.rs @@ -4,8 +4,9 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_stm32::mode::Async; use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; -use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, QuadDma, TransferConfig}; +use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; use embassy_stm32::time::mhz; use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; @@ -43,12 +44,12 @@ const MEMORY_ADDR: u32 = 0x00000000u32; /// Implementation of access to flash chip. /// Chip commands are hardcoded as it depends on used chip. /// This implementation is using chip GD25Q64C from Giga Device -pub struct FlashMemory> { - qspi: Qspi<'static, I, D>, +pub struct FlashMemory { + qspi: Qspi<'static, I, Async>, } -impl> FlashMemory { - pub fn new(qspi: Qspi<'static, I, D>) -> Self { +impl FlashMemory { + pub fn new(qspi: Qspi<'static, I, Async>) -> Self { let mut memory = Self { qspi }; memory.reset_memory(); @@ -279,7 +280,7 @@ async fn main(_spawner: Spawner) -> ! { cs_high_time: ChipSelectHighTime::_1Cycle, fifo_threshold: FIFOThresholdLevel::_16Bytes, }; - let driver = Qspi::new_bk1( + let driver = Qspi::new_bank1( p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, ); let mut flash = FlashMemory::new(driver); -- cgit From 183f2f6913032600d74ea058b50a1fcedbebe719 Mon Sep 17 00:00:00 2001 From: Jan Špaček Date: Thu, 18 Apr 2024 18:50:30 +0200 Subject: stm32/usart: remove instance generic params --- examples/stm32h5/src/bin/usart_split.rs | 3 +-- examples/stm32h7/src/bin/usart_split.rs | 3 +-- examples/stm32h7rs/src/bin/usart_split.rs | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/stm32h5/src/bin/usart_split.rs b/examples/stm32h5/src/bin/usart_split.rs index 77b4caa9e..d26c5003c 100644 --- a/examples/stm32h5/src/bin/usart_split.rs +++ b/examples/stm32h5/src/bin/usart_split.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::mode::Async; -use embassy_stm32::peripherals::UART7; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART7, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/stm32h7/src/bin/usart_split.rs b/examples/stm32h7/src/bin/usart_split.rs index 4ad8e77ce..2bb58be5e 100644 --- a/examples/stm32h7/src/bin/usart_split.rs +++ b/examples/stm32h7/src/bin/usart_split.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::mode::Async; -use embassy_stm32::peripherals::UART7; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART7, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { let mut buf = [0; 8]; loop { info!("reading..."); diff --git a/examples/stm32h7rs/src/bin/usart_split.rs b/examples/stm32h7rs/src/bin/usart_split.rs index 77b4caa9e..d26c5003c 100644 --- a/examples/stm32h7rs/src/bin/usart_split.rs +++ b/examples/stm32h7rs/src/bin/usart_split.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::mode::Async; -use embassy_stm32::peripherals::UART7; use embassy_stm32::usart::{Config, Uart, UartRx}; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; @@ -38,7 +37,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART7, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { let mut buf = [0; 8]; loop { info!("reading..."); -- cgit From 201b5c6ec1eee12b34a2a2102263849d21ae8e7f Mon Sep 17 00:00:00 2001 From: Joël Schulz-Andres Date: Fri, 24 May 2024 14:03:27 +0200 Subject: Add NRF52810 example --- examples/nrf52810/.cargo/config.toml | 9 +++++++++ examples/nrf52810/Cargo.toml | 24 ++++++++++++++++++++++++ examples/nrf52810/build.rs | 35 +++++++++++++++++++++++++++++++++++ examples/nrf52810/memory.x | 7 +++++++ examples/nrf52810/src/bin/blinky.rs | 20 ++++++++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 examples/nrf52810/.cargo/config.toml create mode 100644 examples/nrf52810/Cargo.toml create mode 100644 examples/nrf52810/build.rs create mode 100644 examples/nrf52810/memory.x create mode 100644 examples/nrf52810/src/bin/blinky.rs (limited to 'examples') diff --git a/examples/nrf52810/.cargo/config.toml b/examples/nrf52810/.cargo/config.toml new file mode 100644 index 000000000..47647db91 --- /dev/null +++ b/examples/nrf52810/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52810_xxAA" + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml new file mode 100644 index 000000000..8ed8f54d7 --- /dev/null +++ b/examples/nrf52810/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "embassy-nrf52810-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +fixed = "1.10.0" +static_cell = { version = "2" } +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } + +[profile.release] +debug = 2 diff --git a/examples/nrf52810/build.rs b/examples/nrf52810/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf52810/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/nrf52810/memory.x b/examples/nrf52810/memory.x new file mode 100644 index 000000000..7cf560e44 --- /dev/null +++ b/examples/nrf52810/memory.x @@ -0,0 +1,7 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 24K + +} diff --git a/examples/nrf52810/src/bin/blinky.rs b/examples/nrf52810/src/bin/blinky.rs new file mode 100644 index 000000000..1da039f7d --- /dev/null +++ b/examples/nrf52810/src/bin/blinky.rs @@ -0,0 +1,20 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P0_18, Level::Low, OutputDrive::Standard); + + loop { + led.set_high(); + Timer::after_millis(300).await; + led.set_low(); + Timer::after_millis(300).await; + } +} -- cgit From 92988a39397b8d016fbd6ec3783530da1bb43ae4 Mon Sep 17 00:00:00 2001 From: Joël Schulz-Andres Date: Fri, 24 May 2024 14:22:30 +0200 Subject: Correct chip in comment --- examples/nrf52810/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/nrf52810/.cargo/config.toml b/examples/nrf52810/.cargo/config.toml index 47647db91..917a5364a 100644 --- a/examples/nrf52810/.cargo/config.toml +++ b/examples/nrf52810/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +# replace nRF82810_xxAA with your chip as listed in `probe-rs chip list` runner = "probe-rs run --chip nRF52810_xxAA" [build] -- cgit From cf0d227cca92a80e85575154d380d1ff73fb32cf Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 29 May 2024 12:09:55 +0200 Subject: Prepare for embassy-sync 0.6.0 release --- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) (limited to 'examples') diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 86f6676cb..f0a710335 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 70741a0ce..2ddcbffee 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1cb143820..fe1a6f5b1 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index c4ae461a5..37e362824 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 995487cdd..52cd0b546 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index b2abc005c..0f3cbe654 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 7203e6350..3e964df9c 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index ec134f394..b154403ac 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 84d6d04c1..bb83ae049 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index e38e9f3af..93ead617c 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 3e41d1479..980149bea 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } cfg-if = "1.0.0" diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 3cf61a002..7eec3df1b 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -11,7 +11,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = [] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 313187adc..55adf84d7 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -15,7 +15,7 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-single-core", ] } -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 74c01b0f4..ef2b99404 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 27b6b46df..93b5d8b34 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index f3a3f64af..147bb40dc 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -15,7 +15,7 @@ log = [ ] [dependencies] -embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 8ed8f54d7..faec9a263 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index a0687fa1e..041c779a5 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index d693c5a02..79d9e4e1a 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 0d3e39fe5..e560a3dbb 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 5178a690f..726df29cb 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index f05565e84..77c479d3b 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index aaca857ae..6fdcdce5f 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "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/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index cabeca687..5b648e58a 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -12,7 +12,7 @@ cortex-m-rt = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["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"] } static_cell = "2" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 55051703b..51723ac6d 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 86921580a..5d07b0e04 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "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/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 2cfb19c42..848a6b331 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["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"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 7c067e140..50046de56 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["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"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 1eb1ae6db..52b7ce9e8 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -7,7 +7,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-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt" ] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 37bec1bfa..b55c4e127 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 803d0ae0e..122a996e5 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 7f51631c0..9a34ba19d 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 82760db64..87de9f3a4 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index c6c2d1354..14125f819 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } 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/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 192a6ca61..f8c49f3d1 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 8831f9aaf..b6de182e1 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "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/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 24d61043d..17887bc14 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index a8c6aa0e9..37f09bbcc 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 2c6c125dc..910b8e6d1 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index e9a215589..e67856853 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 93127bcb7..24c9263a3 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.2.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 82419ed10..92865b41c 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wb55rg to your chip name in both dependencies, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index ca55cbe92..60f6e9201 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.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", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index b467b97a9..29cd4d466 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 3d2300b59..e7840d52e 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib"] [dependencies] -embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["log", "wasm", ] } -- cgit