Skip to content

Commit

Permalink
Implement gpio wakeup
Browse files Browse the repository at this point in the history
  • Loading branch information
bugadani committed Jul 26, 2023
1 parent 498cb3c commit 5c039da
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 51 deletions.
1 change: 1 addition & 0 deletions src/board/hardware/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl super::startup::StartupResources {
)
}),
clocks,
rtc,
peripheral_clock_control: system.peripheral_clock_control,

misc_pins: MiscPins {
Expand Down
3 changes: 2 additions & 1 deletion src/board/startup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::board::{
prelude::*,
spi::{dma::WithDmaSpi3, SpiMode},
system::PeripheralClockControl,
Spi,
Rtc, Spi,
},
utils::{DummyOutputPin, SpiDeviceWrapper},
wifi::WifiDriver,
Expand All @@ -39,6 +39,7 @@ pub struct StartupResources {

pub misc_pins: MiscPins,
pub wifi: &'static mut WifiDriver,
pub rtc: Rtc<'static>,
}

impl StartupResources {
Expand Down
29 changes: 20 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ use crate::{
use crate::{
board::{
config::{Config, ConfigFile},
hal::{self, entry, prelude::interrupt},
hal::{
self, entry,
gpio::RTCPin,
prelude::interrupt,
rtc_cntl::sleep::{RtcioWakeupSource, WakeupLevel},
Delay,
},
initialized::{BatteryMonitor, BatteryState, Board, ConfigPartition},
startup::StartupResources,
BATTERY_MODEL,
},
interrupt::{InterruptExecutor, SwInterrupt0},
sleep::{enable_gpio_wakeup, start_deep_sleep, RtcioWakeupType},
states::{
adc_setup, app_error, charging, display_menu, initialize, main_menu, measure, wifi_ap,
},
Expand Down Expand Up @@ -264,15 +269,18 @@ async fn main_task(spawner: Spawner, resources: StartupResources) {
Timer::after(Duration::from_millis(100)).await;

let is_charging = board.battery_monitor.is_plugged();
let (_, _, _, touch) = board.frontend.split();
let (_, _, _, mut touch) = board.frontend.split();
let mut rtc = resources.rtc;

#[cfg(feature = "hw_v1")]
let mut charger_pin = board.battery_monitor.charger_status;

#[cfg(feature = "hw_v2")]
let charger_pin = board.battery_monitor.vbus_detect;
let mut charger_pin = board.battery_monitor.vbus_detect;

let mut wakeup_pins = heapless::Vec::<(&mut dyn RTCPin, WakeupLevel), 2>::new();

enable_gpio_wakeup(&touch, RtcioWakeupType::LowLevel);
wakeup_pins.push((&mut touch, WakeupLevel::Low)).ok();

if is_charging {
#[cfg(feature = "hw_v1")]
Expand All @@ -284,7 +292,7 @@ async fn main_task(spawner: Spawner, resources: StartupResources) {

// Wake up momentarily when charger is disconnected
#[cfg(feature = "hw_v2")]
enable_gpio_wakeup(&charger_pin, RtcioWakeupType::LowLevel);
wakeup_pins.push((&mut charger_pin, WakeupLevel::Low)).ok();
} else {
// We want to wake up when the charger is connected, or the electrodes are touched.

Expand All @@ -295,16 +303,19 @@ async fn main_task(spawner: Spawner, resources: StartupResources) {
{
charger_pin.rtcio_pad_hold(true);
charger_pin.rtcio_pullup(true);
enable_gpio_wakeup(&charger_pin, RtcioWakeupType::LowLevel);

wakeup_pins.push((&mut charger_pin, WakeupLevel::Low)).ok();
}

// In v2, the charger status is not connected to an RTC IO pin, so we use the VBUS
// detect pin instead. This is a high level signal when the charger is connected.
#[cfg(feature = "hw_v2")]
enable_gpio_wakeup(&charger_pin, RtcioWakeupType::HighLevel);
wakeup_pins.push((&mut charger_pin, WakeupLevel::High)).ok();
}

start_deep_sleep();
let rtcio = RtcioWakeupSource::new(&mut wakeup_pins);

rtc.sleep_deep(&[&rtcio], &mut Delay::new(&board.clocks));

// Shouldn't reach this. If we do, we just exit the task, which means the executor
// will have nothing else to do. Not ideal, but again, we shouldn't reach this.
Expand Down
46 changes: 5 additions & 41 deletions src/sleep.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
#![allow(unused)]
use crate::board::{hal::gpio::GpioPin, pac};

use crate::board::{
hal::gpio::{GpioPin, RTCPin},
pac,
};

pub enum RtcioWakeupType {
#[allow(unused)]
enum RtcioWakeupType {
Disable = 0,
LowLevel = 4,
HighLevel = 5,
}

pub fn enable_gpio_wakeup<MODE, const PIN: u8>(_pin: &GpioPin<MODE, PIN>, level: RtcioWakeupType) {
fn enable_gpio_wakeup<MODE, const PIN: u8>(_pin: &GpioPin<MODE, PIN>, level: RtcioWakeupType) {
let sens = unsafe { &*pac::SENS::PTR };

// TODO: disable clock when not in use
Expand All @@ -25,39 +21,7 @@ pub fn enable_gpio_wakeup<MODE, const PIN: u8>(_pin: &GpioPin<MODE, PIN>, level:
}

// Wakeup remains enabled after waking from deep sleep, so we need to disable it manually.
#[allow(unused)]
pub fn disable_gpio_wakeup<MODE, const PIN: u8>(pin: &GpioPin<MODE, PIN>) {
enable_gpio_wakeup(pin, RtcioWakeupType::Disable)
}

// Assumptions: S3, Quad Flash/PSRAM, 2nd core stopped
pub fn start_deep_sleep() {
// TODO: S2: disable brownout detector
// TODO: flush log buffers?

let rtc_ctrl = unsafe { &*pac::RTC_CNTL::PTR };

rtc_ctrl.dig_pwc.modify(|_, w| w.dg_wrap_pd_en().set_bit());
rtc_ctrl
.sdio_conf
.modify(|_, w| w.sdio_reg_pd_en().set_bit());

// Enter Deep Sleep
const WAKEUP_SOURCE_GPIO: u32 = 0x4;
rtc_ctrl
.wakeup_state
.modify(|_, w| w.wakeup_ena().variant(WAKEUP_SOURCE_GPIO));

rtc_ctrl.int_clr_rtc.write(|w| {
w.slp_reject_int_clr()
.set_bit()
.slp_wakeup_int_clr()
.set_bit()
});

rtc_ctrl
.int_clr_rtc
.write(|w| unsafe { w.bits(0x003F_FFFF) });

/* Start entry into sleep mode */
rtc_ctrl.state0.modify(|_, w| w.sleep_en().set_bit());
}

0 comments on commit 5c039da

Please sign in to comment.