From 8648c517f65b5e01027828512c40dbb6b539f1b6 Mon Sep 17 00:00:00 2001 From: William Clark Date: Sat, 6 Jan 2024 16:51:22 +0000 Subject: [PATCH] rework poll/read and amend examples --- example/README.md | 5 ++- example/fifo.c | 11 ++----- example/simple.c | 5 --- lis3dh.c | 70 ++++++++++++++++++----------------------- lis3dh.h | 18 +++++++++-- main.c | 80 +++++++++-------------------------------------- 6 files changed, 64 insertions(+), 125 deletions(-) diff --git a/example/README.md b/example/README.md index 914cec7..85b941f 100644 --- a/example/README.md +++ b/example/README.md @@ -7,13 +7,12 @@ Basic example of how to use this device Instead of polling for every single [x y z] set, a FIFO with programmable capacity ("watermark") can be used, and then dumped into memory once full. All FIFO readings use 10-bit resolution regardless of the mode set in `cfg.mode`. The watermark level can be adjusted to a value [1-32] (0 disables FIFO) by modifying the `cfg.fifo.size` property before calling `lis3dh_configure()`. The LIS3DH can optionally apply a HP filter on the sampling to reduce 'static acceleration' from the data. - -Note: `pin1.wtm` will NOT trigger if the FIFO size is 32 (default). Use `pin1.overrun` if you want an interrupt when the FIFO is full at full size (32.) +Note: it seems that the highest data rate (ODR) possible using FIFO is 200 Hz, faster than that and it does not want to restart after 1 FIFO buffer. To faster faster, such as at the advertised 5 KHz rate, you have to use `lis3dh_read()`. ### file: interrupts.c This device supports two different interrupt "output pins," `INT1` and `INT2`. The appropriate flag must be set in either `cfg.pin1` or `cfg.pin2` and the interrupt source must be configured to trigger into `INT1` or `INT2`. -This file contains example code that listens and receives an interrupt when the FIFO watermark is reached i.e. it is full. +This file contains example code that listens and receives an interrupt when the FIFO overrun is reached i.e. it is full. Note: `pin1.wtm` will NOT trigger if the FIFO size is 32 (default). Use `pin1.overrun` if you want an interrupt when the FIFO is full at full size (32.) ### file: single-click.c diff --git a/example/fifo.c b/example/fifo.c index 1d863a9..ac476e5 100644 --- a/example/fifo.c +++ b/example/fifo.c @@ -36,15 +36,8 @@ int main() { /* 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' */ + /* read as many [x y z] sets as specified by watermark level (size) default max/32 */ + /* copy them to the fifo data struct given below as `data' */ if (lis3dh_read_fifo(&lis, &data)) { /* error handling */ } diff --git a/example/simple.c b/example/simple.c index 5020b42..a4fb4d5 100644 --- a/example/simple.c +++ b/example/simple.c @@ -33,11 +33,6 @@ int main() { /* 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 */ diff --git a/lis3dh.c b/lis3dh.c index df180f8..6988935 100644 --- a/lis3dh.c +++ b/lis3dh.c @@ -2,6 +2,7 @@ #include #include "lis3dh.h" #include "registers.h" +#include int lis3dh_init(lis3dh_t *lis3dh) { @@ -205,32 +206,6 @@ 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; - - do { - lis3dh->dev.sleep(1000); /* 1 ms */ - err |= lis3dh->dev.read(REG_STATUS_REG, &status, 1); - } while (!err && !((status >> 3) & 1)); - - return err; -} - -/* assume fifo configured */ -int lis3dh_poll_fifo(lis3dh_t *lis3dh) { - uint8_t src; - int err = 0; - - do { - lis3dh->dev.sleep(1000); /* 1 ms */ - err |= lis3dh->dev.read(REG_FIFO_SRC_REG, &src, 1); - } while (!err && !(src >> 6)); - - return err; -} - /* the real size of the int you get back from reading the acc u16 depends on the power mode. shift down the 16 bit word by this amount: */ @@ -255,17 +230,22 @@ static uint8_t acc_sensitivity(uint8_t mode, uint8_t range) { } } -/* read a single [x y z] set. Assume configured and poll'd */ +/* read a single [x y z] set. */ int lis3dh_read(lis3dh_t *lis3dh) { uint8_t data[6]; - uint8_t shift, sens; + uint8_t shift, sens, status; int err = 0; shift = acc_shift(lis3dh->cfg.mode); sens = acc_sensitivity(lis3dh->cfg.mode, lis3dh->cfg.range); - err |= lis3dh->dev.read(REG_OUT_X_L, data, 6); + /* poll STATUS_REG until new data is available */ + do { + err |= lis3dh->dev.read(REG_STATUS_REG, &status, 1); + lis3dh->dev.sleep(1000); + } while ((!LIS3DH_STATUS_ZYXDA(status) || !LIS3DH_STATUS_ZYXOR(status)) && !err); + err |= lis3dh->dev.read(REG_OUT_X_L, data, 6); lis3dh->acc.x = ((int16_t)(data[1] | data[0] << 8) >> shift) * sens; lis3dh->acc.y = ((int16_t)(data[3] | data[2] << 8) >> shift) * sens; lis3dh->acc.z = ((int16_t)(data[5] | data[4] << 8) >> shift) * sens; @@ -274,24 +254,34 @@ int lis3dh_read(lis3dh_t *lis3dh) { } /* assume fifo has been configured and poll'd */ +/* wait until FIFO is NOT empty, then */ +/* read groups of the 6 OUT bytes until EMPTY flag in FIFO_SRC is set */ int lis3dh_read_fifo(lis3dh_t *lis3dh, struct lis3dh_fifo_data *fifo) { - uint8_t data[192]; /* max size */ - uint8_t sens; + uint8_t data[6]; /* max size */ + uint8_t sens, fifo_src; int err = 0; - int i, idx; + int idx = 0; + + /* wait until there is at least 1 unread sample in the FIFO */ + /* otherwise can cause problems at really fast ODRs and calling this */ + /* function in a loop without delays. */ + do { + err |= lis3dh->dev.read(REG_FIFO_SRC_REG, &fifo_src, 1); + lis3dh->dev.sleep(1000); + } while (!LIS3DH_FIFO_SRC_UNREAD(fifo_src) && !err); /* FIFO is always 10-bit / normal mode */ sens = acc_sensitivity(LIS3DH_MODE_NORMAL, lis3dh->cfg.range); - fifo->size = lis3dh->cfg.fifo.size; + do { + err |= lis3dh->dev.read(REG_OUT_X_L, data, 6); + err |= lis3dh->dev.read(REG_FIFO_SRC_REG, &fifo_src, 1); + fifo->x[idx] = ((int16_t)(data[1] | data[0] << 8) >> 6) * sens; + fifo->y[idx] = ((int16_t)(data[3] | data[2] << 8) >> 6) * sens; + fifo->z[idx] = ((int16_t)(data[5] | data[4] << 8) >> 6) * sens; + } while (idx++ < lis3dh->cfg.fifo.size - 1 && !LIS3DH_FIFO_SRC_EMPTY(fifo_src) && !err); - err |= lis3dh->dev.read(REG_OUT_X_L, data, fifo->size * 6); - - for (i=0, idx=0; isize * 6; i+=6, idx++) { - fifo->x[idx] = ((int16_t)(data[i+1] | data[i+0] << 8) >> 6) * sens; - fifo->y[idx] = ((int16_t)(data[i+3] | data[i+2] << 8) >> 6) * sens; - fifo->z[idx] = ((int16_t)(data[i+5] | data[i+4] << 8) >> 6) * sens; - } + fifo->size = idx; return err; } diff --git a/lis3dh.h b/lis3dh.h index a97151f..e39cfce 100644 --- a/lis3dh.h +++ b/lis3dh.h @@ -20,6 +20,22 @@ #define LIS3DH_CLICK_SCLICK(c) (!!(c & 0x10)) /* Single-click det. enabled */ #define LIS3DH_CLICK_DCLICK(c) (!!(c & 0x20)) /* Double-click det. enabled */ +/* macros for checking FIFO_SRC register */ +#define LIS3DH_FIFO_SRC_UNREAD(c) (c & 0x1F) /* FSS / current unread samples in FIFO */ +#define LIS3DH_FIFO_SRC_EMPTY(c) (!!(c & 0x20)) /* FIFO is empty */ +#define LIS3DH_FIFO_SRC_OVRN(c) (!!(c & 0x40)) /* FIFO has overrun (full 32) */ +#define LIS3DH_FIFO_SRC_WTM(c) (!!(c & 0x80)) /* FIFO watermark hit (not full 32) */ + +/* macros for checking STATUS register */ +#define LIS3DH_STATUS_XDA(c) (!!(c & 0x01)) /* X-axis data available */ +#define LIS3DH_STATUS_YDA(c) (!!(c & 0x02)) /* Y-axis data available */ +#define LIS3DH_STATUS_ZDA(c) (!!(c & 0x04)) /* Z-axis data available */ +#define LIS3DH_STATUS_ZYXDA(c) (!!(c & 0x08)) /* {Z,Y,X}-axis data available */ +#define LIS3DH_STATUS_XOR(c) (!!(c & 0x10)) /* X-axis data has overrun (been overwritten) */ +#define LIS3DH_STATUS_YOR(c) (!!(c & 0x20)) /* Y-axis data has overrun (been overwritten) */ +#define LIS3DH_STATUS_ZOR(c) (!!(c & 0x40)) /* Z-axis data has overrun (been overwritten) */ +#define LIS3DH_STATUS_ZYXOR(c) (!!(c & 0x80)) /* {Z,Y,X}-axis data has overrun (been overwritten) */ + /* rates */ /* all power modes */ #define LIS3DH_ODR_POWEROFF 0x00 @@ -282,9 +298,7 @@ struct lis3dh_fifo_data { int lis3dh_init(lis3dh_t *lis3dh); int lis3dh_deinit(lis3dh_t *lis3dh); int lis3dh_configure(lis3dh_t *lis3dh); -int lis3dh_poll(lis3dh_t *lis3dh); int lis3dh_read(lis3dh_t *lis3dh); -int lis3dh_poll_fifo(lis3dh_t *lis3dh); int lis3dh_read_fifo(lis3dh_t *lis3dh, struct lis3dh_fifo_data *fifo); int lis3dh_read_int1(lis3dh_t *lis3dh); int lis3dh_read_int2(lis3dh_t *lis3dh); diff --git a/main.c b/main.c index 4ba5abb..cd92f0d 100644 --- a/main.c +++ b/main.c @@ -4,17 +4,11 @@ #include #include #include "lis3dh.h" -#include "interrupt.h" #include "spi.h" -/* GPIO 12 or Pin 32 */ -#define GPIO_INTERRUPT_PIN 12 - int main() { lis3dh_t lis; - struct lis3dh_fifo_data fifo; - int i; lis.dev.init = spi_init; lis.dev.read = spi_read; @@ -22,68 +16,22 @@ int main() { lis.dev.sleep = usleep; lis.dev.deinit = spi_deinit; - /* initalise LIS3DH struct */ - if (lis3dh_init(&lis)) { - /* error handling */ + lis3dh_init(&lis); + lis3dh_reset(&lis); + + lis.cfg.mode = LIS3DH_MODE_LP; + lis.cfg.range = LIS3DH_FS_16G; + lis.cfg.rate = LIS3DH_ODR_LP_5376_HZ; + + lis3dh_configure(&lis); + + for ( ;; ) { + + lis3dh_read(&lis); + printf("x: %4.4d mg, y: %4.4d mg, z: %4.4d mg\n", lis.acc.x, lis.acc.y, lis.acc.z); } - /* reset device just in case */ - if (lis3dh_reset(&lis)) { - /* error handling */ - } - - /* register interrupt */ - if (int_register(GPIO_INTERRUPT_PIN)) { - /* error handling */ - } - - lis.cfg.mode = LIS3DH_MODE_NORMAL; - 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 interrupt into int pin1 */ - lis.cfg.pin1.overrun = 1; /* trigger upon FIFO overrun */ - - /* set up HP filter to remove DC component */ - lis.cfg.filter.mode = LIS3DH_FILTER_MODE_NORMAL_REF; - lis.cfg.filter.cutoff = LIS3DH_FILTER_CUTOFF_4; - lis.cfg.filter.fds = 1; /* remove this line, or set to 1 to enable filter */ - - /* 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(i=0; i