Pysense accelerometer wake up issues
[Note: there is no category for issues related to the Pysense/Pytrack, or for issues related to the associated libraries]
I checked out the accelerometer wake up function of the PySense, and wanted to find out the correct values to reliably detect a "knock", and found a few issues:
I believe the computation of
ACT_THSis simply wrong. Instead of:
_ths = int((threshold * self.scales[self.full_scale]) / 2000 / 128) & 0x7F
it should be:
_ths = int(127 * threshold / self.scales[self.full_scale]) & 0x7F
enable_activity_interruptis missing bounds checking, for both max and min (below the resolution of the register, which would simply disable the feature):
if threshold > self.scales[self.full_scale]: error = "threshold %d exceeds full scale %d" % (thresold, self.scales[self.full_scale]) print(error) raise ValueError(error) if threshold < self.scales[self.full_scale] / 128: error = "threshold %d below resolution %d" % (thresold, self.scales[self.full_scale]/128) print(error) raise ValueError(error) if duration > 255 * 1000 * 8 / self.odrs[self.odr]: error = "duration %d exceeds max possible value %d" % (duration, 255 * 1000 * 8 / self.odrs[self.odr]) print(error) raise ValueError(error) if duration < 1000 * 8 / self.odrs[self.odr]: error = "duration %d below resolution %d" % (duration, 1000 * 8 / self.odrs[self.odr]) print(error) raise ValueError(error) _ths = int(127 * threshold / self.scales[self.full_scale]) & 0x7F _dur = int((duration * self.odrs[self.odr]) / 1000 / 8) # Useful for debug print("actual threshold: %d (%d)" % (_ths * self.scales[self.full_scale] / 128, _ths)) print("actual duration: %d (%d)" % (_dur * 8 * 1000 / self.odrs[self.odr], _dur))
- I haven't found any actual documentation for
activity(just the examples), but it is worth pointing out (if I understand the ST documentation correctly) that:
durationis not the minimum duration to signal activity (a single sample above the threshold is enough)
- it is the minimum duration below the threshold to go to inactivity mode (switch down to ODR 10 Hz to save power)
- in this mode, the accelerometer will draw about 50 µA (according to the doc, I haven't checked the actual power draw yet). In higher modes it's >100 µA
it would be worth documenting the
set_odrfunction and the power draw for each of the modes
I added a function to manipulate bits in registers, and used it to simplify other methods:
def set_register(self, register, value, offset, mask): reg = bytearray(self.i2c.readfrom_mem(ACC_I2CADDR, register, 1)) reg &= ~(mask << offset) reg |= ((value & mask) << offset) self.i2c.writeto_mem(ACC_I2CADDR, register, reg) def set_full_scale(self, scale): self.set_register(CTRL4_REG, scale, 4, 3) self.full_scale = scale def set_odr(self, odr): self.set_register(CTRL1_REG, odr, 4, 7) self.odr = odr
(and a few other places)
- adding a function to enable the high-pass filter for output (set bit 2 of register 0x21) is useful to see the values of the accelerations as they are actually used by the activity/inactivity feature:
def set_high_pass(self, hp): self.set_register(CTRL2_REG, 1 if hp else 0, 2, 1)
- Whatever I do,
int_pin()always returns 1. Haven't checked yet if there isn't an issue coming from the PIC configuration (and/or what the PIC sees), will investigate further, but let me know if I missed something.
set_registerwas missing a
I'll set this aside for now as I don't quite have the time and it was just a "nice to have" feature, but I suppose this should be investigated further at some point, as the sensor itself should only use 50 µA, not over 300, and it renders the wake-on-accelerometer feature a lot less useful.
A few things that could be explored:
- it could be that keeping the accelerometer powered on means that all the other sensors are powered on as well and it is them using the rest of the current
- it could be the fact that the accelerometer INT pins are set to open drain
- it could be the powered down ESP32 (which looks like it's connected to ground when powered down) sinking current coming from a pull-up somewhere
- or it could be that the data sheet is just plain wrong :-)
I got @jmarcelino to run the test on his OTII, and the results confirm what you measured:
Average consumption with accel wake disabled: 5.19 μA
With accel wake enabled: 336 μA
I'll add it to my to-do list, I'll get back to you as soon as I can
Hi @seb, can you please just confirm that you get the same 380 µA current while in deep sleep with accelerometer wake up enabled?
I would really love to be able to use a "knock to activate config mode" feature, but while I can probably accept the 50 µA promised by the ST data sheet, 380 µA is just way too much.
If it is indeed 380 µA, any way to reduce that?
I'm wondering if we're not facing the same kind of issue I had when using INT pin wake up on the Pysense, where I ended up cutting the associated pin on the LoPy to make it work reliably.
Let me know what you find out.
One more thing on the topic: I just measured power draw, and if I enable wake-up on accelerometer the deep sleep current goes from about 10 µA to ... 380 µA! Is that something normal in your experience? The ST docs talk about 50 to 180 µA, so there's quite a difference. My EE skills are limited, but isn't that related to the configuration of the INT pins as open drain?
These all look like good changes, if you could do a github pull request I will review all the code properly and check the datasheets to see if, as you explained, the formulas are wrong.