rework poll/read and amend examples

This commit is contained in:
William Clark 2024-01-06 16:51:22 +00:00
parent 0a0cf2a7aa
commit 8648c517f6
6 changed files with 64 additions and 125 deletions

View File

@ -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

View File

@ -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 */
}

View File

@ -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 */

View File

@ -2,6 +2,7 @@
#include <string.h>
#include "lis3dh.h"
#include "registers.h"
#include <stdio.h>
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; i<fifo->size * 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;
}

View File

@ -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);

80
main.c
View File

@ -4,17 +4,11 @@
#include <unistd.h>
#include <math.h>
#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<fifo.size; i++) {
printf("x: %d mg, y: %d mg, z: %d mg\n", fifo.x[i], fifo.y[i], fifo.z[i]);
}
/* unregister interrupt */
if (int_unregister(GPIO_INTERRUPT_PIN)) {
/* error handling */
}
/* deinitalise struct */
if (lis3dh_deinit(&lis)) {
/* error handling */
}
lis3dh_deinit(&lis);
return 0;
}