1818
1919ACC_G_DIV = 1000 * 65536
2020
21+
2122class LIS2HH12 :
2223
2324 ACC_I2CADDR = const (30 )
@@ -37,14 +38,16 @@ class LIS2HH12:
3738 ACT_THS = const (0x1E )
3839 ACT_DUR = const (0x1F )
3940
41+ SCALES = {FULL_SCALE_2G : 4000 , FULL_SCALE_4G : 8000 , FULL_SCALE_8G : 16000 }
42+ ODRS = [0 , 10 , 50 , 100 , 200 , 400 , 800 ]
43+
4044 def __init__ (self , pysense = None , sda = 'P22' , scl = 'P21' ):
4145 if pysense is not None :
4246 self .i2c = pysense .i2c
4347 else :
4448 from machine import I2C
4549 self .i2c = I2C (0 , mode = I2C .MASTER , pins = (sda , scl ))
4650
47- self .reg = bytearray (1 )
4851 self .odr = 0
4952 self .full_scale = 0
5053 self .x = 0
@@ -54,9 +57,6 @@ def __init__(self, pysense = None, sda = 'P22', scl = 'P21'):
5457 self .act_dur = 0
5558 self .debounced = False
5659
57- self .scales = {FULL_SCALE_2G : 4000 , FULL_SCALE_4G : 8000 , FULL_SCALE_8G : 16000 }
58- self .odrs = [0 , 10 , 50 , 100 , 200 , 400 , 800 ]
59-
6060 whoami = self .i2c .readfrom_mem (ACC_I2CADDR , PRODUCTID_REG , 1 )
6161 if (whoami [0 ] != 0x41 ):
6262 raise ValueError ("LIS2HH12 not found" )
@@ -68,9 +68,7 @@ def __init__(self, pysense = None, sda = 'P22', scl = 'P21'):
6868 self .set_full_scale (FULL_SCALE_4G )
6969
7070 # set the interrupt pin as active low and open drain
71- self .i2c .readfrom_mem_into (ACC_I2CADDR , CTRL5_REG , self .reg )
72- self .reg [0 ] |= 0b00000011
73- self .i2c .writeto_mem (ACC_I2CADDR , CTRL5_REG , self .reg )
71+ self .set_register (CTRL5_REG , 3 , 0 , 3 )
7472
7573 # make a first read
7674 self .acceleration ()
@@ -82,7 +80,7 @@ def acceleration(self):
8280 self .y = struct .unpack ('<h' , y )
8381 z = self .i2c .readfrom_mem (ACC_I2CADDR , ACC_Z_L_REG , 2 )
8482 self .z = struct .unpack ('<h' , z )
85- _mult = self .scales [self .full_scale ] / ACC_G_DIV
83+ _mult = self .SCALES [self .full_scale ] / ACC_G_DIV
8684 return (self .x [0 ] * _mult , self .y [0 ] * _mult , self .z [0 ] * _mult )
8785
8886 def roll (self ):
@@ -95,39 +93,63 @@ def pitch(self):
9593 rad = - math .atan2 (y , (math .sqrt (x * x + z * z )))
9694 return (180 / math .pi ) * rad
9795
96+ def set_register (self , register , value , offset , mask ):
97+ reg = bytearray (self .i2c .readfrom_mem (ACC_I2CADDR , register , 1 ))
98+ reg [0 ] &= ~ (mask << offset )
99+ reg [0 ] |= ((value & mask ) << offset )
100+ self .i2c .writeto_mem (ACC_I2CADDR , register , reg )
101+
98102 def set_full_scale (self , scale ):
99- self .i2c .readfrom_mem_into (ACC_I2CADDR , CTRL4_REG , self .reg )
100- self .reg [0 ] &= ~ 0b00110000
101- self .reg [0 ] |= (scale & 3 ) << 4
102- self .i2c .writeto_mem (ACC_I2CADDR , CTRL4_REG , self .reg )
103+ self .set_register (CTRL4_REG , scale , 4 , 3 )
103104 self .full_scale = scale
104105
105106 def set_odr (self , odr ):
106- self .i2c .readfrom_mem_into (ACC_I2CADDR , CTRL1_REG , self .reg )
107- self .reg [0 ] &= ~ 0b01110000
108- self .reg [0 ] |= (odr & 7 ) << 4
109- self .i2c .writeto_mem (ACC_I2CADDR , CTRL1_REG , self .reg )
107+ self .set_register (CTRL1_REG , odr , 4 , 7 )
110108 self .odr = odr
111109
110+ def set_high_pass (self , hp ):
111+ self .set_register (CTRL2_REG , 1 if hp else 0 , 2 , 1 )
112+
112113 def enable_activity_interrupt (self , threshold , duration , handler = None ):
113114 # Threshold is in mg, duration is ms
114115 self .act_dur = duration
115116
116- _ths = int ((threshold * self .scales [self .full_scale ]) / 2000 / 128 ) & 0x7F
117- _dur = int ((duration * self .odrs [self .odr ]) / 1000 / 8 )
117+ if threshold > self .SCALES [self .full_scale ]:
118+ error = "threshold %d exceeds full scale %d" % (thresold , self .SCALES [self .full_scale ])
119+ print (error )
120+ raise ValueError (error )
118121
119- self .i2c .writeto_mem (ACC_I2CADDR , ACT_THS , _ths )
120- self .i2c .writeto_mem (ACC_I2CADDR , ACT_DUR , _dur )
122+ if threshold < self .SCALES [self .full_scale ] / 128 :
123+ error = "threshold %d below resolution %d" % (thresold , self .SCALES [self .full_scale ]/ 128 )
124+ print (error )
125+ raise ValueError (error )
126+
127+ if duration > 255 * 1000 * 8 / self .ODRS [self .odr ]:
128+ error = "duration %d exceeds max possible value %d" % (duration , 255 * 1000 * 8 / self .ODRS [self .odr ])
129+ print (error )
130+ raise ValueError (error )
131+
132+ if duration < 1000 * 8 / self .ODRS [self .odr ]:
133+ error = "duration %d below resolution %d" % (duration , 1000 * 8 / self .ODRS [self .odr ])
134+ print (error )
135+ raise ValueError (error )
136+
137+ _ths = int (127 * threshold / self .SCALES [self .full_scale ]) & 0x7F
138+ _dur = int ((duration * self .ODRS [self .odr ]) / 1000 / 8 )
139+
140+ self .i2c .writeto_mem (ACC_I2CADDR , ACT_THS , _ths )
141+ self .i2c .writeto_mem (ACC_I2CADDR , ACT_DUR , _dur )
121142
122143 # enable the activity/inactivity interrupt
123- self .i2c .readfrom_mem_into (ACC_I2CADDR , CTRL3_REG , self .reg )
124- self .reg [0 ] |= 0b00100000
125- self .i2c .writeto_mem (ACC_I2CADDR , CTRL3_REG , self .reg )
144+ self .set_register (CTRL3_REG , 1 , 5 , 1 )
126145
127146 self ._user_handler = handler
128147 self .int_pin = Pin ('P13' , mode = Pin .IN )
129148 self .int_pin .callback (trigger = Pin .IRQ_FALLING | Pin .IRQ_RISING , handler = self ._int_handler )
130149
150+ # return actual used thresold and duration
151+ return (_ths * self .SCALES [self .full_scale ] / 128 , _dur * 8 * 1000 / self .ODRS [self .odr ])
152+
131153 def activity (self ):
132154 if not self .debounced :
133155 time .sleep_ms (self .act_dur )
0 commit comments