From a355ecec8f0bf021aa35a0d6f1b2d9cf85ef38fd Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Sun, 24 Sep 2017 18:29:29 +0200 Subject: [PATCH] pytrack, pysense: Add accelerometer wake-up feature. --- pysense/lib/LIS2HH12.py | 105 ++++++++++++++++++++++++++++++++++------ pysense/lib/pysense.py | 41 ++++++++++++++-- pytrack/lib/LIS2HH12.py | 105 ++++++++++++++++++++++++++++++++++------ pytrack/lib/pytrack.py | 39 +++++++++++++-- 4 files changed, 253 insertions(+), 37 deletions(-) diff --git a/pysense/lib/LIS2HH12.py b/pysense/lib/LIS2HH12.py index 3142817..6a2c2ae 100644 --- a/pysense/lib/LIS2HH12.py +++ b/pysense/lib/LIS2HH12.py @@ -1,5 +1,22 @@ import math +import time import struct +from machine import Pin + + +FULL_SCALE_2G = const(0) +FULL_SCALE_4G = const(2) +FULL_SCALE_8G = const(3) + +ODR_POWER_DOWN = const(0) +ODR_10_HZ = const(1) +ODR_50_HZ = const(2) +ODR_100_HZ = const(3) +ODR_200_HZ = const(4) +ODR_400_HZ = const(5) +ODR_800_HZ = const(6) + +ACC_G_DIV = 1000 * 65536 class LIS2HH12: @@ -7,15 +24,18 @@ class LIS2HH12: PRODUCTID_REG = const(0x0F) CTRL1_REG = const(0x20) + CTRL2_REG = const(0x21) + CTRL3_REG = const(0x22) CTRL4_REG = const(0x23) + CTRL5_REG = const(0x24) ACC_X_L_REG = const(0x28) ACC_X_H_REG = const(0x29) ACC_Y_L_REG = const(0x2A) ACC_Y_H_REG = const(0x2B) ACC_Z_L_REG = const(0x2C) ACC_Z_H_REG = const(0x2D) - - SCALE = const(8192) + ACT_THS = const(0x1E) + ACT_DUR = const(0x1F) def __init__(self, pysense = None, sda = 'P22', scl = 'P21'): if pysense is not None: @@ -25,26 +45,32 @@ def __init__(self, pysense = None, sda = 'P22', scl = 'P21'): self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl)) self.reg = bytearray(1) - + self.odr = 0 + self.full_scale = 0 self.x = 0 self.y = 0 self.z = 0 + self.int_pin = None + self.act_dur = 0 + self.debounced = False + + self.scales = {FULL_SCALE_2G: 4000, FULL_SCALE_4G: 8000, FULL_SCALE_8G: 16000} + self.odrs = [0, 10, 50, 100, 200, 400, 800] whoami = self.i2c.readfrom_mem(ACC_I2CADDR , PRODUCTID_REG, 1) if (whoami[0] != 0x41): - raise ValueError("Incorrect Product ID") + raise ValueError("LIS2HH12 not found") - # enable acceleration readings - self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL1_REG, self.reg) - self.reg[0] &= ~0b01110000 - self.reg[0] |= 0b00110000 - self.i2c.writeto_mem(ACC_I2CADDR , CTRL1_REG, self.reg) + # enable acceleration readings at 50Hz + self.set_odr(ODR_50_HZ) # change the full-scale to 4g - self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL4_REG, self.reg) - self.reg[0] &= ~0b00110000 - self.reg[0] |= 0b00100000 - self.i2c.writeto_mem(ACC_I2CADDR , CTRL4_REG, self.reg) + self.set_full_scale(FULL_SCALE_4G) + + # set the interrupt pin as active low and open drain + self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL5_REG, self.reg) + self.reg[0] |= 0b00000011 + self.i2c.writeto_mem(ACC_I2CADDR , CTRL5_REG, self.reg) # make a first read self.acceleration() @@ -56,7 +82,8 @@ def acceleration(self): self.y = struct.unpack('> 8) & 0xFF, (time_s >> 16) & 0xFF])) def go_to_sleep(self): - # disable back-up power to the pressure sensor + # disable power to the pressure sensor self.mask_bits_in_memory(PORTC_ADDR, ~(1 << 7)) - self.poke_memory(ADCON0_ADDR, 0) # disable the ADC - self.poke_memory(ANSELA_ADDR, ~(1 << 3)) # Don't touch RA3 so that button wake up works + # disable the ADC + self.poke_memory(ADCON0_ADDR, 0) + + if self.wake_int: + # Don't touch RA3 or RA5 so that interrupt wake-up works + self.poke_memory(ANSELA_ADDR, ~((1 << 3) | (1 << 5))) + self.poke_memory(ANSELC_ADDR, ~((1 << 6) | (1 << 7))) + else: + # disable power to the accelerometer, and don't touch RA3 so that button wake-up works + self.poke_memory(ANSELA_ADDR, ~(1 << 3)) + self.poke_memory(ANSELC_ADDR, ~(1 << 7)) + self.poke_memory(ANSELB_ADDR, 0xFF) - self.poke_memory(ANSELC_ADDR, ~(1 << 7)) self._write(bytes([CMD_GO_SLEEP]), wait=False) # kill the run pin Pin('P3', mode=Pin.OUT, value=0) @@ -185,3 +200,19 @@ def read_battery_voltage(self): time.sleep_us(100) adc_val = (self.peek_memory(ADRESH_ADDR) << 2) + (self.peek_memory(ADRESL_ADDR) >> 6) return (((adc_val * 3.3 * 280) / 1023) / 180) + 0.01 # add 10mV to compensate for the drop in the FET + + def setup_int_wake_up(self, rising, falling): + """ rising is for activity detection, falling for inactivity """ + wake_int = False + if rising: + self.set_bits_in_memory(IOCAP_ADDR, 1 << 5) + wake_int = True + else: + self.mask_bits_in_memory(IOCAP_ADDR, ~(1 << 5)) + + if falling: + self.set_bits_in_memory(IOCAN_ADDR, 1 << 5) + wake_int = True + else: + self.mask_bits_in_memory(IOCAN_ADDR, ~(1 << 5)) + self.wake_int = wake_int diff --git a/pytrack/lib/LIS2HH12.py b/pytrack/lib/LIS2HH12.py index 3142817..6a2c2ae 100644 --- a/pytrack/lib/LIS2HH12.py +++ b/pytrack/lib/LIS2HH12.py @@ -1,5 +1,22 @@ import math +import time import struct +from machine import Pin + + +FULL_SCALE_2G = const(0) +FULL_SCALE_4G = const(2) +FULL_SCALE_8G = const(3) + +ODR_POWER_DOWN = const(0) +ODR_10_HZ = const(1) +ODR_50_HZ = const(2) +ODR_100_HZ = const(3) +ODR_200_HZ = const(4) +ODR_400_HZ = const(5) +ODR_800_HZ = const(6) + +ACC_G_DIV = 1000 * 65536 class LIS2HH12: @@ -7,15 +24,18 @@ class LIS2HH12: PRODUCTID_REG = const(0x0F) CTRL1_REG = const(0x20) + CTRL2_REG = const(0x21) + CTRL3_REG = const(0x22) CTRL4_REG = const(0x23) + CTRL5_REG = const(0x24) ACC_X_L_REG = const(0x28) ACC_X_H_REG = const(0x29) ACC_Y_L_REG = const(0x2A) ACC_Y_H_REG = const(0x2B) ACC_Z_L_REG = const(0x2C) ACC_Z_H_REG = const(0x2D) - - SCALE = const(8192) + ACT_THS = const(0x1E) + ACT_DUR = const(0x1F) def __init__(self, pysense = None, sda = 'P22', scl = 'P21'): if pysense is not None: @@ -25,26 +45,32 @@ def __init__(self, pysense = None, sda = 'P22', scl = 'P21'): self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl)) self.reg = bytearray(1) - + self.odr = 0 + self.full_scale = 0 self.x = 0 self.y = 0 self.z = 0 + self.int_pin = None + self.act_dur = 0 + self.debounced = False + + self.scales = {FULL_SCALE_2G: 4000, FULL_SCALE_4G: 8000, FULL_SCALE_8G: 16000} + self.odrs = [0, 10, 50, 100, 200, 400, 800] whoami = self.i2c.readfrom_mem(ACC_I2CADDR , PRODUCTID_REG, 1) if (whoami[0] != 0x41): - raise ValueError("Incorrect Product ID") + raise ValueError("LIS2HH12 not found") - # enable acceleration readings - self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL1_REG, self.reg) - self.reg[0] &= ~0b01110000 - self.reg[0] |= 0b00110000 - self.i2c.writeto_mem(ACC_I2CADDR , CTRL1_REG, self.reg) + # enable acceleration readings at 50Hz + self.set_odr(ODR_50_HZ) # change the full-scale to 4g - self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL4_REG, self.reg) - self.reg[0] &= ~0b00110000 - self.reg[0] |= 0b00100000 - self.i2c.writeto_mem(ACC_I2CADDR , CTRL4_REG, self.reg) + self.set_full_scale(FULL_SCALE_4G) + + # set the interrupt pin as active low and open drain + self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL5_REG, self.reg) + self.reg[0] |= 0b00000011 + self.i2c.writeto_mem(ACC_I2CADDR , CTRL5_REG, self.reg) # make a first read self.acceleration() @@ -56,7 +82,8 @@ def acceleration(self): self.y = struct.unpack('> 6) return (((adc_val * 3.3 * 280) / 1023) / 180) + 0.01 # add 10mV to compensate for the drop in the FET + + def setup_int_wake_up(self, rising, falling): + """ rising is for activity detection, falling for inactivity """ + wake_int = False + if rising: + self.set_bits_in_memory(IOCAP_ADDR, 1 << 5) + wake_int = True + else: + self.mask_bits_in_memory(IOCAP_ADDR, ~(1 << 5)) + + if falling: + self.set_bits_in_memory(IOCAN_ADDR, 1 << 5) + wake_int = True + else: + self.mask_bits_in_memory(IOCAN_ADDR, ~(1 << 5)) + self.wake_int = wake_int