diff --git a/Makefile b/Makefile index bc6143d..9b7a132 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc -CFLAGS=-O2 -std=gnu99 -W -Werror -Wall -Wextra -I. +CFLAGS=-O2 -std=gnu99 -W -Werror -Wall -Wextra -I. all: - $(CC) $(CFLAGS) main.c i2c.c lis3dh.c -o main + $(CC) $(CFLAGS) main.c i2c.c lis3dh.c -o lis3dh -lm clean: - rm -rf main \ No newline at end of file + rm -rf lis3dh \ No newline at end of file diff --git a/README.md b/README.md index 1175de7..14e4a26 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # LIS3DH 3-axis accelerometer + +``` +$ ./lis3dh +init OK +configure OK +poll OK +read OK +x: 0.552, y: -0.864, z: -0.152 +mag: 1.04 +deinit OK +``` \ No newline at end of file diff --git a/lis3dh.py b/doc/lis3dh.py similarity index 100% rename from lis3dh.py rename to doc/lis3dh.py diff --git a/i2c.c b/i2c.c index 7b97f58..33842a6 100644 --- a/i2c.c +++ b/i2c.c @@ -24,16 +24,16 @@ int i2c_init(void) { fd = open(I2C_DEVICE, O_RDWR); if (fd < 0) { fprintf(stderr, "could not open device: %s\n", I2C_DEVICE); - return I2C_ERR; + return 1; } if (ioctl(fd, I2C_SLAVE, I2C_LIS3DH_ADDRESS) < 0) { fprintf(stderr, "failed to acquire bus/talk to slave\n"); close(fd); - return I2C_ERR; + return 1; } - return I2C_OK; + return 0; } @@ -43,11 +43,11 @@ int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) { if (read(fd, dst, size) != (ssize_t)size) { fprintf(stderr, "error read()\n"); - return I2C_ERR; + return 1; } - return I2C_OK; + return 0; } @@ -56,10 +56,10 @@ int i2c_write(uint8_t reg, uint8_t value) { if (write(fd, cmd, 2) != 2) { fprintf(stderr, "error write()\n"); - return I2C_ERR; + return 1; } - return I2C_OK; + return 0; } int i2c_deinit(void) { @@ -67,5 +67,5 @@ int i2c_deinit(void) { close(fd); } - return I2C_OK; + return 0; } diff --git a/i2c.h b/i2c.h index 14f0680..c5f276f 100644 --- a/i2c.h +++ b/i2c.h @@ -3,12 +3,9 @@ #include <stdint.h> -#define I2C_OK 0 -#define I2C_ERR 1 - -int i2c_init (void); -int i2c_read (uint8_t reg, uint8_t *dst, uint32_t size); -int i2c_write (uint8_t reg, uint8_t value); +int i2c_init (void); +int i2c_read (uint8_t reg, uint8_t *dst, uint32_t size); +int i2c_write (uint8_t reg, uint8_t value); int i2c_deinit (void); #endif \ No newline at end of file diff --git a/lis3dh.c b/lis3dh.c index ecbaaa7..4753f72 100644 --- a/lis3dh.c +++ b/lis3dh.c @@ -2,21 +2,160 @@ #include "lis3dh.h" #include "registers.h" +static int lis3dh_reboot(lis3dh_t *lis3dh) { + int err = 0; + + err |= lis3dh->dev.write(REG_CTRL_REG5, 0x80); + lis3dh->dev.sleep(5000); /* sleep 5 ms */ + + return err; +} + int lis3dh_init(lis3dh_t *lis3dh) { uint8_t result; int err = 0; - lis3dh->dev.init(); + if (lis3dh->dev.init() != 0) { + err |= 1; + } err |= lis3dh->dev.read(REG_WHO_AM_I, &result, 1); if (result != 0x33) { err |= 1; } + err |= lis3dh_reboot(lis3dh); + + return err; +} + +int lis3dh_configure(lis3dh_t *lis3dh) { + + uint8_t ctrl_reg1, ctrl_reg4; + int err = 0; + + /* last 0b111 enables Z, Y and X axis */ + ctrl_reg1 = 0 | (lis3dh->cfg.rate << 4) | 0b111; + ctrl_reg4 = 0 | (lis3dh->cfg.range << 4); + + /* set block update */ + ctrl_reg4 |= 0x80; + + /* set high resolution */ + if (lis3dh->cfg.mode == LIS3DH_MODE_HR) { + ctrl_reg4 |= 0x08; + } + + err |= lis3dh->dev.write(REG_CTRL_REG1, ctrl_reg1); + err |= lis3dh->dev.write(REG_CTRL_REG4, ctrl_reg4); + + return err; +} + +int lis3dh_poll(lis3dh_t *lis3dh) { + + uint8_t status; + int err = 0; + + do { + err |= lis3dh->dev.read(REG_STATUS_REG, &status, 1); + } while (!err && !((status >> 3) & 1)); + + 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: */ +static uint8_t acc_shift(lis3dh_t *lis3dh) { + switch (lis3dh->cfg.mode) { + case LIS3DH_MODE_HR: + return 4; /* i12 */ + case LIS3DH_MODE_NORMAL: + return 6; /* i10 */ + case LIS3DH_MODE_LP: + return 8; /* i8 */ + } + + return 0; +} + +/* returns a scalar that when multiplied with axis reading + turns it to a multiple of mg. */ +static uint8_t acc_sensitivity(lis3dh_t *lis3dh) { + + uint8_t mode = lis3dh->cfg.mode; + + switch (lis3dh->cfg.range) { + case LIS3DH_FS_2G: + if (mode == LIS3DH_MODE_LP) { + return 16; + } else if (mode == LIS3DH_MODE_NORMAL) { + return 4; + } else { + return 1; + } + break; + + case LIS3DH_FS_4G: + if (mode == LIS3DH_MODE_LP) { + return 32; + } else if (mode == LIS3DH_MODE_NORMAL) { + return 8; + } else { + return 2; + } + break; + + case LIS3DH_FS_8G: + if (mode == LIS3DH_MODE_LP) { + return 64; + } else if (mode == LIS3DH_MODE_NORMAL) { + return 16; + } else { + return 4; + } + break; + + case LIS3DH_FS_16G: + if (mode == LIS3DH_MODE_LP) { + return 192; + } else if (mode == LIS3DH_MODE_NORMAL) { + return 148; + } else { + return 12; + } + break; + } + + return 0; +} + +int lis3dh_read(lis3dh_t *lis3dh) { + + uint8_t data[6]; + int16_t x, y, z; + uint8_t scale, sens; + int err = 0; + + scale = acc_shift(lis3dh); + sens = acc_sensitivity(lis3dh); + + /* must set MSbit of the address to multi-read and + have the device auto-increment the address. */ + err |= lis3dh->dev.read(REG_OUT_X_L | 0x80, data, 6); + + x = (((int16_t)((data[0] << 8) | data[1])) >> scale) * sens; + y = (((int16_t)((data[2] << 8) | data[3])) >> scale) * sens; + z = (((int16_t)((data[4] << 8) | data[5])) >> scale) * sens; + + lis3dh->acc.x = (double)x / 1000.0; + lis3dh->acc.y = (double)y / 1000.0; + lis3dh->acc.z = (double)z / 1000.0; + return err; } int lis3dh_deinit(lis3dh_t *lis3dh) { - lis3dh->dev.deinit(); - return 0; + return lis3dh->dev.deinit(); } \ No newline at end of file diff --git a/lis3dh.h b/lis3dh.h index b5a0c99..6598664 100644 --- a/lis3dh.h +++ b/lis3dh.h @@ -16,10 +16,15 @@ #define LIS3DH_ODR_LP_5376_HZ 0b1001 /* range/sens */ -#define LIS3DH_FS_2G = 0b00 -#define LIS3DH_FS_4G = 0b01 -#define LIS3DH_FS_8G = 0b10 -#define LIS3DH_FS_16G = 0b11 +#define LIS3DH_FS_2G 0b00 +#define LIS3DH_FS_4G 0b01 +#define LIS3DH_FS_8G 0b10 +#define LIS3DH_FS_16G 0b11 + +/* modes */ +#define LIS3DH_MODE_HR 0b00 +#define LIS3DH_MODE_LP 0b01 +#define LIS3DH_MODE_NORMAL 0b10 struct lis3dh_device { @@ -33,18 +38,26 @@ struct lis3dh_device { struct lis3dh_config { uint8_t rate; /* ODR */ uint8_t range; /* FS */ - uint8_t mode; /* LPen */ - uint8_t hr; /* high resolution */ + uint8_t mode; /* LPen and HR */ +}; + +struct lis3dh_acceleration { + double x; + double y; + double z; }; struct lis3dh { struct lis3dh_device dev; struct lis3dh_config cfg; + struct lis3dh_acceleration acc; }; typedef struct lis3dh lis3dh_t; 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); #endif \ No newline at end of file diff --git a/main.c b/main.c index 86aa63c..0a7495f 100644 --- a/main.c +++ b/main.c @@ -1,9 +1,17 @@ #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> +#include <math.h> #include "lis3dh.h" #include "i2c.h" +double accel_mag(lis3dh_t *lis) { + double d = 0.0; + + d = sqrt( powf(lis->acc.x, 2) + powf(lis->acc.y, 2) + powf(lis->acc.z, 2)); + return d; +} + int main() { lis3dh_t lis; @@ -16,11 +24,30 @@ int main() { if (!lis3dh_init(&lis)) { - puts("OK"); + puts("init OK"); } + lis.cfg.mode = LIS3DH_MODE_NORMAL; + lis.cfg.range = LIS3DH_FS_2G; + lis.cfg.rate = LIS3DH_ODR_100_HZ; + + if (!lis3dh_configure(&lis)) { + puts("configure OK"); + } + + if (!lis3dh_poll(&lis)) { + puts("poll OK"); + } + + if (!lis3dh_read(&lis)) { + puts("read OK"); + } + + printf("x: %.3g, y: %.3g, z: %.3g\n", lis.acc.x, lis.acc.y, lis.acc.z); + printf("mag: %.3g\n", accel_mag(&lis)); + if (!lis3dh_deinit(&lis)) { - puts("OK"); + puts("deinit OK"); } return 0;