Pysense accelerometer wake up issues

  • Hi all,

    [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_THS is 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
    • the enable_activity_interrupt is 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])
                raise ValueError(error)
            if threshold < self.scales[self.full_scale] / 128:
                error = "threshold %d below resolution %d" % (thresold, self.scales[self.full_scale]/128)
                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])
                raise ValueError(error)
            if duration < 1000 * 8 / self.odrs[self.odr]:
                error = "duration %d below resolution %d" % (duration, 1000 * 8 / self.odrs[self.odr])
                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 enable_activity_interrupt or activity (just the examples), but it is worth pointing out (if I understand the ST documentation correctly) that:
      • the duration is 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_odr function 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[0] &= ~(mask << offset)
            reg[0] |= ((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.

    EDIT: set_register was missing a ~

  • Thanks @seb and @jmarcelino! Don't get exactly the same figures, but we're definitely in the same ballpark.

    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 :-)

  • administrators


    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

  • administrators



    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?


  • Hi @seb, can you or @jmarcelino or some other member of the team confirm the fact that enabling accelerometer wake up brings the deep sleep power draw to about 380 µA?

    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.


  • Will do.

    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?

  • administrators


    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.

Pycom on Twitter

Looks like your connection to Pycom Forum was lost, please wait while we try to reconnect.