aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorloris libralato <[email protected]>2023-08-05 21:05:53 +0200
committerGitHub <[email protected]>2023-08-05 21:05:53 +0200
commitd7031fbe9229601396bfcea8d7738cdd685c2d42 (patch)
treef1edeeb044cd250235afcac23850b29226e3af5b
parent02fcb07aa96b2b7f63eb3ecd49206182be2cec65 (diff)
parent766b5fc6f609acba45405142ff941c2827541c5a (diff)
Merge branch 'embassy-rs:main' into main
-rw-r--r--embassy-rp/src/clocks.rs130
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--examples/stm32f334/Cargo.toml2
-rw-r--r--tests/rp/src/bin/adc.rs4
4 files changed, 136 insertions, 4 deletions
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index a33980230..7b25ecffb 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -1,3 +1,4 @@
1use core::arch::asm;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
2use core::sync::atomic::{AtomicU16, AtomicU32, Ordering}; 3use core::sync::atomic::{AtomicU16, AtomicU32, Ordering};
3 4
@@ -6,6 +7,7 @@ use pac::clocks::vals::*;
6 7
7use crate::gpio::sealed::Pin; 8use crate::gpio::sealed::Pin;
8use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
10use crate::pac::common::{Reg, RW};
9use crate::{pac, reset, Peripheral}; 11use crate::{pac, reset, Peripheral};
10 12
11// NOTE: all gpin handling is commented out for future reference. 13// NOTE: all gpin handling is commented out for future reference.
@@ -873,3 +875,131 @@ impl rand_core::RngCore for RoscRng {
873 dest.fill_with(Self::next_u8) 875 dest.fill_with(Self::next_u8)
874 } 876 }
875} 877}
878/// Enter the `DORMANT` sleep state. This will stop *all* internal clocks
879/// and can only be exited through resets, dormant-wake GPIO interrupts,
880/// and RTC interrupts. If RTC is clocked from an internal clock source
881/// it will be stopped and not function as a wakeup source.
882#[cfg(target_arch = "arm")]
883pub fn dormant_sleep() {
884 struct Set<T: Copy, F: Fn()>(Reg<T, RW>, T, F);
885
886 impl<T: Copy, F: Fn()> Drop for Set<T, F> {
887 fn drop(&mut self) {
888 self.0.write_value(self.1);
889 self.2();
890 }
891 }
892
893 fn set_with_post_restore<T: Copy, After: Fn(), F: FnOnce(&mut T) -> After>(
894 reg: Reg<T, RW>,
895 f: F,
896 ) -> Set<T, impl Fn()> {
897 reg.modify(|w| {
898 let old = *w;
899 let after = f(w);
900 Set(reg, old, after)
901 })
902 }
903
904 fn set<T: Copy, F: FnOnce(&mut T)>(reg: Reg<T, RW>, f: F) -> Set<T, impl Fn()> {
905 set_with_post_restore(reg, |r| {
906 f(r);
907 || ()
908 })
909 }
910
911 // disable all clocks that are not vital in preparation for disabling clock sources.
912 // we'll keep gpout and rtc clocks untouched, gpout because we don't care about them
913 // and rtc because it's a possible wakeup source. if clk_rtc is not configured for
914 // gpin we'll never wake from rtc, but that's what the user asked for then.
915 let _stop_adc = set(pac::CLOCKS.clk_adc_ctrl(), |w| w.set_enable(false));
916 let _stop_usb = set(pac::CLOCKS.clk_usb_ctrl(), |w| w.set_enable(false));
917 let _stop_peri = set(pac::CLOCKS.clk_peri_ctrl(), |w| w.set_enable(false));
918 // set up rosc. we could ask the use to tell us which clock source to wake from like
919 // the C SDK does, but that seems rather unfriendly. we *may* disturb rtc by changing
920 // rosc configuration if it's currently the rtc clock source, so we'll configure rosc
921 // to the slowest frequency to minimize that impact.
922 let _configure_rosc = (
923 set(pac::ROSC.ctrl(), |w| {
924 w.set_enable(pac::rosc::vals::Enable::ENABLE);
925 w.set_freq_range(pac::rosc::vals::FreqRange::LOW);
926 }),
927 // div=32
928 set(pac::ROSC.div(), |w| w.set_div(pac::rosc::vals::Div(0xaa0))),
929 );
930 while !pac::ROSC.status().read().stable() {}
931 // switch over to rosc as the system clock source. this will change clock sources for
932 // watchdog and timer clocks, but timers won't be a concern and the watchdog won't
933 // speed up by enough to worry about (unless it's clocked from gpin, which we don't
934 // support anyway).
935 let _switch_clk_ref = set(pac::CLOCKS.clk_ref_ctrl(), |w| {
936 w.set_src(pac::clocks::vals::ClkRefCtrlSrc::ROSC_CLKSRC_PH);
937 });
938 let _switch_clk_sys = set(pac::CLOCKS.clk_sys_ctrl(), |w| {
939 w.set_src(pac::clocks::vals::ClkSysCtrlSrc::CLK_REF);
940 });
941 // oscillator dormancy does not power down plls, we have to do that ourselves. we'll
942 // restore them to their prior glory when woken though since the system may be clocked
943 // from either (and usb/adc will probably need the USB PLL anyway)
944 let _stop_pll_sys = set_with_post_restore(pac::PLL_SYS.pwr(), |w| {
945 let wake = !w.pd() && !w.vcopd();
946 w.set_pd(true);
947 w.set_vcopd(true);
948 move || while wake && !pac::PLL_SYS.cs().read().lock() {}
949 });
950 let _stop_pll_usb = set_with_post_restore(pac::PLL_USB.pwr(), |w| {
951 let wake = !w.pd() && !w.vcopd();
952 w.set_pd(true);
953 w.set_vcopd(true);
954 move || while wake && !pac::PLL_USB.cs().read().lock() {}
955 });
956 // dormancy only stops the oscillator we're telling to go dormant, the other remains
957 // running. nothing can use xosc at this point any more. not doing this costs an 200µA.
958 let _stop_xosc = set_with_post_restore(pac::XOSC.ctrl(), |w| {
959 let wake = w.enable() == pac::xosc::vals::Enable::ENABLE;
960 if wake {
961 w.set_enable(pac::xosc::vals::Enable::DISABLE);
962 }
963 move || while wake && !pac::XOSC.status().read().stable() {}
964 });
965 let _power_down_xip_cache = set(pac::XIP_CTRL.ctrl(), |w| w.set_power_down(true));
966
967 // only power down memory if we're running from XIP (or ROM? how?).
968 // powering down memory otherwise would require a lot of exacting checks that
969 // are better done by the user in a local copy of this function.
970 // powering down memories saves ~100µA, so it's well worth doing.
971 unsafe {
972 let is_in_flash = {
973 // we can't rely on the address of this function as rust sees it since linker
974 // magic or even boot2 may place it into ram.
975 let pc: usize;
976 asm!(
977 "mov {pc}, pc",
978 pc = out (reg) pc
979 );
980 pc < 0x20000000
981 };
982 if is_in_flash {
983 // we will be powering down memories, so we must be *absolutely*
984 // certain that we're running entirely from XIP and registers until
985 // memories are powered back up again. accessing memory that's powered
986 // down may corrupt memory contents (see section 2.11.4 of the manual).
987 // additionally a 20ns wait time is needed after powering up memories
988 // again. rosc is likely to run at only a few MHz at most, so the
989 // inter-instruction delay alone will be enough to satisfy this bound.
990 asm!(
991 "ldr {old_mem}, [{mempowerdown}]",
992 "str {power_down_mems}, [{mempowerdown}]",
993 "str {coma}, [{dormant}]",
994 "str {old_mem}, [{mempowerdown}]",
995 old_mem = out (reg) _,
996 mempowerdown = in (reg) pac::SYSCFG.mempowerdown().as_ptr(),
997 power_down_mems = in (reg) 0b11111111,
998 dormant = in (reg) pac::ROSC.dormant().as_ptr(),
999 coma = in (reg) 0x636f6d61,
1000 );
1001 } else {
1002 pac::ROSC.dormant().write_value(0x636f6d61);
1003 }
1004 }
1005}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 8c7dd38c2..723c50296 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
58critical-section = "1.1" 58critical-section = "1.1"
59atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
60stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1f8ab493e029fc601edebc6bac105a63cc9858fe" } 60stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42" }
61vcell = "0.1.3" 61vcell = "0.1.3"
62bxcan = "0.7.0" 62bxcan = "0.7.0"
63nb = "1.0.0" 63nb = "1.0.0"
@@ -75,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] }
75[build-dependencies] 75[build-dependencies]
76proc-macro2 = "1.0.36" 76proc-macro2 = "1.0.36"
77quote = "1.0.15" 77quote = "1.0.15"
78stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1f8ab493e029fc601edebc6bac105a63cc9858fe", default-features = false, features = ["metadata"]} 78stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-82a24863823a3daf0ca664c7fdf008379d0a0d42", default-features = false, features = ["metadata"]}
79 79
80[features] 80[features]
81default = ["rt"] 81default = ["rt"]
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index 6410891a1..d8f6b8fe8 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-stm32f3-examples" 3name = "embassy-stm32f334-examples"
4version = "0.1.0" 4version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs
index d6d58f0c0..b29a3a7cb 100644
--- a/tests/rp/src/bin/adc.rs
+++ b/tests/rp/src/bin/adc.rs
@@ -8,7 +8,7 @@ use defmt::*;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler, Sample}; 9use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler, Sample};
10use embassy_rp::bind_interrupts; 10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::Pull; 11use embassy_rp::gpio::{Level, Output, Pull};
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
13 13
14bind_interrupts!(struct Irqs { 14bind_interrupts!(struct Irqs {
@@ -18,6 +18,8 @@ bind_interrupts!(struct Irqs {
18#[embassy_executor::main] 18#[embassy_executor::main]
19async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
20 let mut p = embassy_rp::init(Default::default()); 20 let mut p = embassy_rp::init(Default::default());
21 let _power_reg_pwm_mode = Output::new(p.PIN_23, Level::High);
22 let _wifi_off = Output::new(p.PIN_25, Level::High);
21 let mut adc = Adc::new(p.ADC, Irqs, Config::default()); 23 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
22 24
23 { 25 {