InfiniTimeOrg / InfiniTime

Firmware for Pinetime smartwatch written in C++ and based on FreeRTOS
GNU General Public License v3.0
2.71k stars 927 forks source link

Power analysis #53

Open JF002 opened 4 years ago

JF002 commented 4 years ago

In commit f7e40b1b5879242b4ce59854dbbadb44fe5f75e4, I re-implemented sleep/wakeup for all devices (touchpanel, display, NOR Flash, SPI and TWI). I checked (using the logs) that all Sleep() and Wakeup() method are called in the correct order. I also checked that the MCU is put in deep sleep with a logic analyzer (the MCU is in deepsleep during the call to __WFE() in port_cmsis_systick.c).

Now, I think it would be very interesting to actually measure the power consumption of InfiniTime while running different use-cases:

But... I do not have the necessary instruments and knowledge to do the measurement by myself.

If anyone has the setup and instruments necessary to measure the power consumed by InfiniTime, just write a comment to this issue !

Also, if you can, just leave your Pinetime running this commit (f7e40b1b5879242b4ce59854dbbadb44fe5f75e4) or a next one just to see how long it runs on battery!

Thanks

aykevl commented 1 year ago

Here is a zip of the ELF file: watch.zip This is with all the optimizations I know applied. I'm getting 162µA right now from my multimeter.

aykevl commented 1 year ago

I managed to reproduce the ~66µA power consumption! The final missing bit was the heart rate sensor that is apparently enabled by default and consumes 0.1mA. My multimeter claims it consumes only 60µA, but this 60µA vs 66µA difference could easily be explained by one or both multimeters being slightly wrong (I have a cheap one that I've noticed changes a bit over time). I think this is the lowest we can possibly get with the PineTime. I've also investigated the BMA421 accelerometer and it appears to be set in power down mode by default.

@vbelloir here is the updated firmware, in case you'd like to test: watch.zip. It consumes a bit more in my measurement (62-63µA) because it's also polling the button, I get the lowest power consumption when I really disable everything.

As usual, I have updated the wiki.

moriel5 commented 1 year ago

Since I mostly need the clock function, I am really looking forward to having my PineTime using this little power most of the time.

vbelloir commented 1 year ago

Hi @aykevl I just test it right now. I found 43µA standby with your fw, It's very nice!

Next week, I would be able to lake also some measurements with a better tool. This tool is used by a colleague.

aykevl commented 1 year ago

Thanks a lot for testing! I just received my Power Profiler Kit, and using it I found some interesting details:

When I take the average of multiple minutes of measurement, I get around 80uA (although it fluctuates a bit).

I don't know what is causing these current spikes, but I imagine some of the chips (the touch controller perhaps) is recalibrating during that time. If I remember correctly, the touch controller consumes around 3mA when active, so that would make sense.

aykevl commented 1 year ago

I left it running for a bit longer and found some more patterns. It appears to go through periods of higher and lower current consumption. The lower current consumption is around 72uA (averaged out over a minute to include the 200ms spikes). Higher current consumption (up to around 200uA) seems to get triggered by movement, or by me resting my arms on my desk (??), although that could perhaps also be bad cables or something else. In any case, the typical resting current consumption seems to be more like 72uA, which is still pretty low (~100 days battery life).

vbelloir commented 1 year ago

It's very interesting. Will you try to do the same with infinitime? Or will you able to support a FW dev of infinitime?

aykevl commented 1 year ago

I have no plans to work on InfiniTime, sorry. But I'd be happy to answer any questions that people might have to get such low current consumption on their firmware. I do plan to continue working on my own custom firmware, which is written in Go.

JF002 commented 1 year ago

@vbelloir @aykevl Very interesting discussion! And 60-70µA is really amazing! I would really like to see if we could integrate those changes in InfiniTime to improve the battery life! I'll do it when I get a bit of free time ;-)

JF002 commented 1 year ago

I did a few experiments. With a few minor changes to the code, I manage to reduce the current consumption down to ~130µA. It's waaaaay better than current consumption of the current release (~1.1mA), but still ~40µA more than @aykevl (I measure 97µA using watch.elf).

Not sure where those 40µA come from though...

@aykevl How can I ensure that the low-frequency oscillator is enabled and used?

EDIT : I think I found what's using those 40µA : the motion sensor! It looks like it uses a bit of current when it's initialized and configure to count steps!

aykevl commented 1 year ago

I did a few experiments. With a few minor changes to the code, I manage to reduce the current consumption down to ~130µA. It's waaaaay better than current consumption of the current release (~1.1mA), but still ~40µA more than @aykevl (I measure 97µA using watch.elf).

That's great! I'd be curious to look at the diff, perhaps I have some more suggestions :)

EDIT : I think I found what's using those 40µA : the motion sensor! It looks like it uses a bit of current when it's initialized and configure to count steps!

Yeah, that's certainly possible. I haven't really investigated low power modes for the motion sensor, but I did find that after reset it enters a low power mode of negligible current consumption (less than 1µA IIRC).

@aykevl How can I ensure that the low-frequency oscillator is enabled and used?

Pretty sure it is, if you manage to get such low current consumption. But if you want to be sure, you can read the LFCLKSRC register (the SRC field should be set to Xtal).

aykevl commented 1 year ago

Actually now I think about it, my firmware doesn't touch the motion sensor at all. So if it was enabled in the previous firmware and wasn't reset or power-cycled, it might still be enabled. That might explain why you measure a higher current consumption than I do. I don't know your setup, but perhaps you can try power cycling the watch after flashing my firmware?

JF002 commented 1 year ago

I don't know your setup, but perhaps you can try power cycling the watch after flashing my firmware?

Since my devkit is connected to the debugger, I always power cycle it before measuring the current to ensure that the debug peripheral does not draw any additional current. I think my setup is not optimal for power measurement right now because of all the long wires and the breadboard. That's maybe why I measure a value slightly higher than yours?

I'd be curious to look at the diff, perhaps I have some more suggestions :)

I'll create a few PRs with the changes so we can review them and integrate them in InfiniTime :) In the mean time, here's a patch with my changes : power.zip

Note that those changes are pretty rough and disable most of the functionalities of the watch (button, ble, heart rate sensor, motion sensor,...).

Pretty sure it is, if you manage to get such low current consumption. But if you want to be sure, you can read the LFCLKSRC register (the SRC field should be set to Xtal).

I'll check, but I think I remember the SRC was effectively set to Xtal!

JF002 commented 1 year ago

I've just created 4 PRs:

Together, those PRs decrease the power usage by a lot:

Use-case Fast Advertising Slow Advertising BLE disabled
InfiniTime 1.12 1.48mA 890µA 860µA
With those changes 580µA 200µA 180µA

This reduces the power usage by a ratio of 2.7 to 4.7, which is quite awesome!

The power usage in sleep mode could be further reduced by

It was also a nice opportunity to check that the feature that disables BLE in InfiniTime actually works : the power consumption is the same when I disable BLE in the code (at compile time) and when I disable it in the settings (at run time)!

The theoretical battery life is increased from ~7 days to ~35days in sleep mode while slow advertising !

Thanks again to @aykevl for sharing their results!

aykevl commented 1 year ago

That's really amazing! I looked at the PRs and they look reasonable - but I don't know much about InfiniTime or FreeRTOS so can't say much about it.

Disabling all the IRQ on the I/O (which disables the button, touch panel and charger detection) : -20µA

Did you try polling the button instead of relying on interrupts? I have found that polling the button (using the mechanism described here) actually reduces current consumption. Polling each 100ms or so only uses very little current (<10µA) in TinyGo, while leaving pin 15 high uses something like 34µA. As an experiment, you could set pin 15 low and see whether it makes any difference for you.

Also, I found that using the pin sense mechanism instead of using level triggered interrupts for the touch controller avoids the current consumption increase that is caused by edge triggered interrupts. You can find more details here: https://github.com/aykevl/board/blob/58ffd00a37e218cae35973885c8edd13048b934a/board-pinetime.go#L151 Importantly, there seem to be a few chip errata that cause higher than expected current consumption as a result of interrupts, that can be entirely avoided using pin sense. (You may not need the direct register accesses I have used, IIRC there's something in nrfx to use the pin sense mechanism in an easy way).

EDIT: one thing I haven't looked into yet is the various options in the touch controller. It might be possible to save some current consumption by changing some of the registers (calibration interval, for example).

JF002 commented 1 year ago

That's really amazing! I looked at the PRs and they look reasonable - but I don't know much about InfiniTime or FreeRTOS so can't say much about it.

Thanks for the review, a second view is always interesting!

Did you try polling the button instead of relying on interrupts?

No, not yet, but it's probably something worth looking into! Thanks for the links!

one thing I haven't looked into yet is the various options in the touch controller. It might be possible to save some current consumption by changing some of the registers (calibration interval, for example).

The touch panel is veeery sensitive, and tends to wake InfiniTime up way too often, which causes unwanted actions in the UI and higher power usage. I'm very interested if you can find some way to tune it and improve the sensitivity and power usage!

aykevl commented 1 year ago

The touch panel is veeery sensitive, and tends to wake InfiniTime up way too often, which causes unwanted actions in the UI and higher power usage. I'm very interested if you can find some way to tune it and improve the sensitivity and power usage!

Oh, I see. I can't promise anything, but if I continue this project and find some interesting settings I'll share them!

vbelloir commented 1 year ago

Very happy to read theses messages! With about 30 days lifespan, Pinetime will become usable as daily watch!

toastom commented 1 year ago

I'd say it is already very capable of being used as a daily watch. And whenever someone comments on mine and I tell them that it typically lasts 4 pr sp days on a single charge, they've been shocked (oftentimes coming from Apple Watch users, but idk the battery life on those since I haven't owned one). 10 days is incredible!

aykevl commented 1 year ago

I suspect the accelerometer is not set to low power mode by default in InfiniTime. I have my TinyGo version of the BMA421/BMA425 driver almost working and once I get it to work fully, I'll post the results here.

The accelerometer should be able to go down to 14uA when set to sleep mode, without sleep mode it's much more. I did in fact manage to reach that low level (actually 11uA or so but that's probably a measuring error), but had trouble getting the step counter to work (I'm pretty sure it's possible, I just didn't figure it out yet).

aykevl commented 1 year ago

Ok, managed to get the step counter to work. It consumes 14µA when fully optimized, exactly as the datasheet states.

I also tested my driver with something similar to the configuration for InfiniTime (https://github.com/InfiniTimeOrg/InfiniTime/blob/main/src/drivers/Bma421.cpp) and found it uses far more power:

So this is probably something to investigate for InfiniTime. My driver is here: https://github.com/tinygo-org/drivers/pull/587/files. Especially important are the ACC_CONF and PWR_CONF registers.

Specifically, the datasheet says the following (page 31 of the PDF): Screenshot_20230714_144441

So that's what I did, I set the ODR to 50Hz and acc_bwp to osr4_avg1 (no averaging). That may result in worse readings, but it still detects steps. My multimeter now claims the watch uses 79µA most of the time with step counting enabled and BLE disabled. The actual current consumption will be slightly higher because of the spikes the touchscreen (?) produces sometimes.