Compare commits

...

2 Commits

Author SHA1 Message Date
bce3d7f8f0 free-fall 2024-01-02 16:17:09 +00:00
b0e8428519 examples: possibly helpful comments 2024-01-02 15:35:35 +00:00
11 changed files with 230 additions and 41 deletions

View File

@ -17,11 +17,11 @@ This device supports two different interrupt "output pins," `INT1` and `INT2`. T
### file: single-click.c
Set up single-click detection
Set up single-click detection (no latching interrupt possible)
### file: double-click.c
Set up double-click detection
Set up double-click detection (no latching interrupt possible)
### file: adc.c
@ -69,4 +69,8 @@ There are two interrupt registers, `int1` and `int2` that can be configured for
### file: inertial-wakeup.c
Inertial interrupt example in OR mode (easily changed to AND mode) with configurable axes, threshold and minimum acceleration duration.
Inertial interrupt example in OR mode (easily changed to AND mode) with configurable axes, threshold and minimum acceleration duration.
### file: free-fall.c
Inertial interrupt example activating upon free-fall. It works by using an AND mode interrupt of all the negative axes and comparing them to a threshold value (in the case of negative axis the threshold is multiplied by -1), recommended to be at 350mg (for >30 ms) and activating when the experienced negative acceleration is greater (abs. sense) than the negative threshold.

View File

@ -22,7 +22,7 @@ int main() {
/* error handling */
}
/* reset device because it sometimes corrupts itself */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}

View File

@ -37,7 +37,7 @@ int main() {
/* error handling */
}
/* reset device because it sometimes corrupts itself */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
@ -51,7 +51,8 @@ int main() {
lis.cfg.mode = LIS3DH_MODE_HR;
lis.cfg.range = LIS3DH_FS_2G;
lis.cfg.rate = LIS3DH_ODR_400_HZ; /* minimum recommended ODR */
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL;
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL_REF;
lis.cfg.filter.cutoff = LIS3DH_FILTER_CUTOFF_8;
lis.cfg.filter.click = 1; /* enable filtering for CLICK function */
@ -59,15 +60,14 @@ int main() {
lis.cfg.click.yd = 1; /* enable Y axis double click */
lis.cfg.click.zd = 1; /* enable Z axis double click */
lis.cfg.pin1.click = 1; /* enable click int src through pin1 */
lis.cfg.int1.latch = 1; /* latch interrupt until INT1_SRC is read */
lis.cfg.pin1.click = 1; /* enable CLICK INT through pin1 */
/* 1 LSb = 16 mg @ FS_2G
* so a 0.3g 'shock' is 300/16 = 18.75
* However, the device can have up to +- 40mg read error, so add 40mg
* 0.34g => 340/16 ~= 21
*/
lis.cfg.click_ths = 21; /* pretty sensitive */
lis.cfg.click_ths = 21;
/* Duration time is measured in N/ODR where:
* --- N = The content of the intX_dur integer
@ -76,20 +76,25 @@ int main() {
* 400 2.5
*
* For ODR=400:
* time_limit of 75 ms = 75/2.5 = 30
* time_latency of 40 ms = 40/2.5 = 16
* time_limit of 75 ms = 75/2.5 = 30
* time_latency of 40 ms = 40/2.5 = 16
* time_window of 500 ms = 500/2.5 = 200
*
*/
lis.cfg.time_limit = 30; /* range: 0-127 */
lis.cfg.time_latency = 16; /* range: 0-255 */
lis.cfg.time_window = 200; /* range: 0-255 */
lis.cfg.time_limit = 30; /* range: 0-127 */
lis.cfg.time_latency = 16; /* range: 0-255 */
lis.cfg.time_window = 200; /* range: 0-255 */
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* read REFERENCE to set filter to current accel field */
if (lis3dh_reference(&lis)) {
/* error handling */
}
/* read CLICK_SRC to clear previous interrupts, if any */
if (lis3dh_read_click(&lis)) {
/* error handling */

View File

@ -16,23 +16,35 @@ int main() {
lis.dev.sleep = usleep;
lis.dev.deinit = i2c_deinit;
/* initialise LIS3DH struct */
if (lis3dh_init(&lis)) {
/* error handling */
}
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
lis.cfg.mode = LIS3DH_MODE_HR;
lis.cfg.range = LIS3DH_FS_4G;
lis.cfg.rate = LIS3DH_ODR_100_HZ;
lis.cfg.fifo.mode = LIS3DH_FIFO_MODE_NORMAL;
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* poll fifo register until it reports that the watermark level has
been reached, or that it has overwritten old data, whichever
happens first. */
if (lis3dh_poll_fifo(&lis)) {
/* error handling */
}
/* read as many [x y z] sets as specified by watermark level (fth) */
/* copy them to the fifo data struct given below as `fifo' */
if (lis3dh_read_fifo(&lis, &data)) {
/* error handling */
}
@ -42,6 +54,7 @@ int main() {
printf("x: %f, y: %f, z: %f\n", data.x[i], data.y[i], data.z[i]);
}
/* deinitialise struct */
if (lis3dh_deinit(&lis)) {
/* error handling */
}

129
example/free-fall.c Normal file
View File

@ -0,0 +1,129 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "lis3dh.h"
#include "interrupt.h"
#include "i2c.h"
#define GPIO_INTERRUPT_PIN_INT1 12
int main() {
lis3dh_t lis;
/* set fn ptrs to rw on bus (i2c or SPI) */
lis.dev.init = i2c_init;
lis.dev.read = i2c_read;
lis.dev.write = i2c_write;
lis.dev.sleep = usleep;
lis.dev.deinit = i2c_deinit;
/* initialise LIS3DH struct */
if (lis3dh_init(&lis)) {
/* error handling */
}
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
/* register interrupt */
if (int_register(GPIO_INTERRUPT_PIN_INT1)) {
/* error handling */
}
/* set up config */
lis.cfg.mode = LIS3DH_MODE_HR;
lis.cfg.range = LIS3DH_FS_2G;
lis.cfg.rate = LIS3DH_ODR_400_HZ;
/* no filter because we want the 'absolute' experienced acceleration */
lis.cfg.pin1.ia1 = 1; /* enable INT1 through pin1 */
lis.cfg.int1.latch = 1; /* latch interrupt until INT1_SRC is read */
/* enable all the low directions */
/* this works because the low directions are compared to -threshold,
and are below it at rest, and greater than it at free-fall,
while the opposite is true for the high directions. */
lis.cfg.int1.xl = 1;
lis.cfg.int1.yl = 1;
lis.cfg.int1.zl = 1;
/* AND interrupt mode */
lis.cfg.int1.aoi = 1;
lis.cfg.int1.en_6d = 0;
/* 1 LSb = 16 mg @ FS_2G
* Due to inherent problems with accuracy and timing, you should use a "free-fall window",
* rather than setting the threshold to 0. AN3308 pg 27 recommends at or below 350mg for all axes,
* to be considered as being in a state of free-fall, but the gradual return to experiencing
* 1g in free-fall is not discussed.
*
* 350/16 ~= 20
*/
lis.cfg.int1_ths = 20;
/*
* Duration time is measured in N/ODR where:
* --- N = The content of the intX_dur integer
* --- ODR = the data rate, eg 100, 400...
* [ODR] [1 LSb in milliseconds]
* 400 2.5
*
* At 400 ODR,
* 30 ms = 30/2.5 = 12
*/
lis.cfg.int1_dur = 12;
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* read INT1_SRC to clear previous interrupts, if any */
if (lis3dh_read_int1(&lis)) {
/* error handling */
}
for ( ;; ) {
/* poll interrupt on INT1 pin */
if (int_poll(GPIO_INTERRUPT_PIN_INT1)) {
/* error handling */
}
/* read INT1_SRC when interrupt has fired */
if (lis3dh_read_int1(&lis)) {
/* error handling */
}
/* only print if IA=1 */
if (LIS3DH_INT_SRC_IA(lis.src.int1)) {
/* print received interrupt .. */
printf("IA=%d ZH=%d ZL=%d YH=%d YL=%d XH=%d XL=%d\n",
LIS3DH_INT_SRC_IA(lis.src.int1),
LIS3DH_INT_SRC_Z_HIGH(lis.src.int1),
LIS3DH_INT_SRC_Z_LOW(lis.src.int1),
LIS3DH_INT_SRC_Y_HIGH(lis.src.int1),
LIS3DH_INT_SRC_Y_LOW(lis.src.int1),
LIS3DH_INT_SRC_X_HIGH(lis.src.int1),
LIS3DH_INT_SRC_X_LOW(lis.src.int1));
}
}
/* unregister interrupt */
if (int_unregister(GPIO_INTERRUPT_PIN_INT1)) {
/* error handling */
}
/* deinitalise struct */
if (lis3dh_deinit(&lis)) {
/* error handling */
}
return 0;
}

View File

@ -25,7 +25,7 @@ int main() {
/* error handling */
}
/* reset device because it sometimes corrupts itself */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}

View File

@ -22,11 +22,12 @@ int main() {
lis.dev.sleep = usleep;
lis.dev.deinit = i2c_deinit;
/* initalise LIS3DH struct */
if (lis3dh_init(&lis)) {
/* error handling */
}
/* device sometimes corrupts itself, so reset .. */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
@ -40,25 +41,35 @@ int main() {
lis.cfg.range = LIS3DH_FS_2G;
lis.cfg.rate = LIS3DH_ODR_100_HZ;
lis.cfg.fifo.mode = LIS3DH_FIFO_MODE_STREAM;
lis.cfg.fifo.trig = LIS3DH_FIFO_TRIG_INT1; /* trigger into INT1 */
lis.cfg.pin1.wtm = 1; /* trigger upon watermark level reached */
lis.cfg.fifo.trig = LIS3DH_FIFO_TRIG_INT1; /* trigger interrupt into int pin1 */
lis.cfg.pin1.wtm = 1; /* trigger upon FIFO watermark level reached */
/* set up HP filter to remove DC component */
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL;
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL_REF;
lis.cfg.filter.cutoff = LIS3DH_FILTER_CUTOFF_4;
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* read REFERENCE to set filter to current accel field */
if (lis3dh_reference(&lis)) {
/* error handling */
}
/* wait for interrupt from LIS3DH */
if (int_poll(GPIO_INTERRUPT_PIN)) {
/* error handling */
}
/* read as many [x y z] sets as specified by watermark level (fth) */
/* copy them to the fifo data struct given below as `fifo' */
if (lis3dh_read_fifo(&lis, &fifo)) {
/* error handling */
}
/* above function also writes out the qty of [x y z] sets stored in `fifo' */
for(k=0; k<fifo.size; k++) {
printf("x: %04.04f, y: %04.04f z: %04.04f\n", fifo.x[k], fifo.y[k], fifo.z[k]);
}
@ -68,6 +79,7 @@ int main() {
/* error handling */
}
/* deinitalise struct */
if (lis3dh_deinit(&lis)) {
/* error handling */
}

View File

@ -14,11 +14,12 @@ int main() {
lis.dev.sleep = usleep;
lis.dev.deinit = i2c_deinit;
/* initialise LIS3DH struct */
if (lis3dh_init(&lis)) {
/* error handling */
}
/* device sometimes corrupts itself, so reset .. */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
@ -27,20 +28,24 @@ int main() {
lis.cfg.range = LIS3DH_FS_4G;
lis.cfg.rate = LIS3DH_ODR_100_HZ;
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* poll STATUS_REG for new [x y z] data ready */
if (lis3dh_poll(&lis)) {
/* error handling */
}
/* read latest [x y z] data, store in the `lis' struct's `acc' field */
if (lis3dh_read(&lis)) {
/* error handling */
}
printf("x: %f, y: %f, z: %f\n", lis.acc.x, lis.acc.y, lis.acc.z);
/* deinitalise struct */
if (lis3dh_deinit(&lis)) {
/* error handling */
}

View File

@ -25,7 +25,7 @@ int main() {
/* error handling */
}
/* reset device because it sometimes corrupts itself */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
@ -39,23 +39,24 @@ int main() {
lis.cfg.mode = LIS3DH_MODE_HR;
lis.cfg.range = LIS3DH_FS_2G;
lis.cfg.rate = LIS3DH_ODR_400_HZ; /* minimum recommended ODR */
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL;
lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL_REF;
lis.cfg.filter.cutoff = LIS3DH_FILTER_CUTOFF_8;
lis.cfg.filter.click = 1; /* enable filtering for CLICK function */
lis.cfg.click.xs = 1; /* enable X axis single click */
lis.cfg.click.ys = 1; /* enable Y axis single click */
lis.cfg.click.zs = 1; /* enable Z axis single click */
lis.cfg.pin1.click = 1; /* enable click int src through pin1 */
lis.cfg.int1.latch = 1; /* latch interrupt until INT1_SRC is read */
lis.cfg.pin1.click = 1; /* enable CLICK INT through pin1 */
/* 1 LSb = 16 mg @ FS_2G
* so a 0.072g 'shock' is 72/16 = 4.5
* However, the device can have up to +- 40mg read error
* 0.112g => 112/16 = 7
* so a 0.3g 'shock' is 300/16 = 18.75
* However, the device can have up to +- 40mg read error, add 40 mg
* 0.34g => 340/16 ~= 21
* (Note: 0.34g and not 1.34g because of HP filter)
*/
lis.cfg.click_ths = 7; /* pretty sensitive */
lis.cfg.click_ths = 21;
/* the 'shock' must be gone after 10 ms let's say ..*/
/*
* Duration time is measured in N/ODR where:
* --- N = The content of the intX_dur integer
@ -63,15 +64,26 @@ int main() {
* [ODR] [1 LSb in milliseconds]
* 400 2.5
*
* At 400 ODR, 10ms/2.5ms = 4
* At 400 ODR,
* 20 ms = 20/2.5 = 8
*/
lis.cfg.time_limit = 4;
lis.cfg.time_limit = 8;
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* read REFERENCE to set filter to current accel field */
if (lis3dh_reference(&lis)) {
/* error handling */
}
/* read CLICK_SRC to clear previous interrupts, if any */
if (lis3dh_read_click(&lis)) {
/* error handling */
}
for(;;) {
/* poll interrupt on INT1 pin */
@ -84,14 +96,21 @@ int main() {
/* error handling */
}
/* print data gathered from CLICK_SRC */
printf("Click: X=%d, Y=%d, Z=%d, Sign=%d, S_en=%d, D_en=%d\n",
LIS3DH_CLICK_SRC_X(lis.src.click),
LIS3DH_CLICK_SRC_Y(lis.src.click),
LIS3DH_CLICK_SRC_Z(lis.src.click),
LIS3DH_CLICK_SIGN(lis.src.click),
LIS3DH_CLICK_SCLICK(lis.src.click),
LIS3DH_CLICK_DCLICK(lis.src.click));
/* only print if SCLICK=1 */
if (LIS3DH_CLICK_SCLICK(lis.src.click)) {
/* print data gathered from CLICK_SRC */
printf("Click: X=%d, Y=%d, Z=%d, Sign=%d, S_CLICK=%d, D_CLICK=%d\n",
LIS3DH_CLICK_SRC_X(lis.src.click),
LIS3DH_CLICK_SRC_Y(lis.src.click),
LIS3DH_CLICK_SRC_Z(lis.src.click),
LIS3DH_CLICK_SIGN(lis.src.click),
LIS3DH_CLICK_SCLICK(lis.src.click),
LIS3DH_CLICK_DCLICK(lis.src.click));
}
/* sleep for 5 ms because gpio sysfs is slow at clearing interrupts */
/* not necessary with "real" IRQ */
usleep(5000);
}
/* unregister interrupt */

View File

@ -22,7 +22,7 @@ int main() {
/* error handling */
}
/* reset device because it sometimes corrupts itself */
/* reset device just in case */
if (lis3dh_reset(&lis)) {
/* error handling */
}
@ -33,13 +33,13 @@ int main() {
lis.cfg.rate = LIS3DH_ODR_400_HZ;
lis.cfg.en_adc = 1; /* enable ADC */
lis.cfg.en_temp = 1; /* enable temp sensing */
/* write device config */
if (lis3dh_configure(&lis)) {
/* error handling */
}
/* Read all 3 ADCs */
if (lis3dh_read_adc(&lis)) {
/* error handling */
}

View File

@ -214,6 +214,7 @@ int lis3dh_configure(lis3dh_t *lis3dh) {
return err;
}
/* should always return something with valid start configuration */
int lis3dh_poll(lis3dh_t *lis3dh) {
uint8_t status;
int err = 0;
@ -226,6 +227,7 @@ int lis3dh_poll(lis3dh_t *lis3dh) {
return err;
}
/* assume fifo configured */
int lis3dh_poll_fifo(lis3dh_t *lis3dh) {
uint8_t src;
int err = 0;