-
Notifications
You must be signed in to change notification settings - Fork 179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add functions for going to sleep #65
Comments
I'm currently using some code in my project. If you are interested I can polish it up and create a pull request. I currently have this API: #[derive(PartialEq)]
enum SleepMode {
Standby,
Stop(bool), // true: voltage regulators in low power mode
}
fn enable_sleep_mode(sleep_mode: SleepMode, scb: &mut SCB, pwr: &mut PWR) {
...
} Using it is as easy as calling I will read up on RM0008 to see if there are more features that would be interesting to support. |
That would be great! I like the look of your API, though I would probably suggest If you want more inspiration, I have code for going to sleep here https://github.com/TheZoq2/weather/blob/master/stmhardware/src/main.rs#L366 though I'm suspecting it has problems because it uses more current than I would expect. |
I've some code for this in my clone of this repository. However, there are some problems:
Comments and/or help are welcome! |
Sorry for the delayed reply. It has been a while since I had a look at the sleep functions so I can't comment that much on implementation details.
That's true, and it also seems like some of the arguments are only required if others are present. Perhaps something like the builder pattern would be useful. Something along the lines of SleepMode::new(sleep_mode, entry, &mut scb, &mut pwr)
.enable_wakeup_alarm(&mut nvic, &mut exti)
// nvic and exti are now mut borrowed twice, so something smarter must be done
.enable_wakeup_pin(&mut nvic, &mut exti, &mut apb1)
.debug(&mut dbgmcu)
.enter() Clearly it's not fully thought out, but might be a good place to start |
No problem!
OK, I'll try to find it out...
Yeah, this is a good idea. If I perform the configuration of the registers on the configuration methods (instead of doing everything in the |
That looks pretty good to me, but just like my example, it doesn't seem to allow wakeup from both RTC and pins simultaneously which would be a nice feature to have. Unfortunately, I can't really come up with a neat way of achieving that. |
Euhm, I'm pretty sure it does. Please see examples/sleep.rs... |
Oh right, I was thinking that it stores the reference to the register in the builder struct which wouldn't be allowed. Though I think that leads to another issue. The following code would not wake up from an alarm, despite the builder being configured to do so. let builder = SleepModeBuilder::new(
SleepMode::Standby,
SleepModeEntry::WFI,
&mut scb,
&mut pwr)
.enable_wakeup_alarm(10, &mut rtc, &mut nvic, &mut exti);
nvic.do_something_that_disables_wakeup_alarm();
builder.enter(); |
Yes, that's true. It may be unexpected behavior, though at the same time I think it will be rare to actually cause a real problem. I don't see how we can keep an intuitive API based on the builder pattern and at the same time prevent the situation you describe... So we need to do some concession, or use an altogether different design. |
I think we should avoid unexpected behavoiur for as long as possible. Perhaps we could have two builder structs, one basic version, and one which has a mut reference to the extra registers. Something like this: struct SleepModeBuilder<'a> {
mode: SleepMode,
entry: SleepModeEntry,
scp: &mut scb,
pwr: &mut pwr,
}
impl SleepModeBuilder {
// The normal build functions
fn enable_wakeup_alarm(..., rtc, nvic, exti) -> SleepModeBuilderWithNvic {
}
}
struct SleepModeBuilderWithNvic<'a> {
core: SleepModeBuilder<'a>,
nvic: &'a mut ..
}
impl SleepModeBuilder {
// Normal build functions
} Another option might be to use some generic type magic and do something like this struct NeedsExtraRegisters;
// T is some sort of internal state of the type. If T is (), only needs
// access to the normal registers on entry. If it's NeedsExtraRegisters, it does.
struct SleepModeBuilder<T> {
mode: SleepMode,
entry: SleepModeEntry,
wake_from_rtc: bool,
wake_from_exti: bool,
}
impl<T> SleepModeBuilder<T> {
// You can only construct the struct with no extra registers. This is represented
// by the unit type
fn new(..) -> SleepModeBuilder<()> {}
// Normal builder functions. Don't change the internal state
fn debug_mode() -> SleepModeBuilder<T> {}
// If we want to configure wakeup stuff, we transform the struct into one that
// needs extra registers
fn wake_from_exti() -> SleepModeBuilder<NeedsExtraRegisters> {
...
}
// If we want to configure wakeup stuff, we transform the struct into one that
// needs extra registers
fn wake_from_rtc() -> SleepModeBuilder<NeedsExtraRegisters> {
...
}
}
// The enter function does all the actual work of configuring registers.
// Its implementation depends on the state
impl SleepModeBuilder<()> {
fn enter(&mut scb, &mut pwr) {}
}
impl SleepModeBuilder<NeedsExtraRegisters> {
fn enter(&mut scb, &mut pwr, &mut nvic, &mut exti) {}
} I think I prefer the second option as it would result in less code duplication. Though it might be a bit overengineered |
any update on this? |
As discussed in #64, it would be nice to have functions for entering the various power save modes as that process requires quite a few steps.
The text was updated successfully, but these errors were encountered: