Compare commits

..

No commits in common. "91ada989f6abdbb5de7cc7b311c3b553bc4bb3b7" and "8648c517f65b5e01027828512c40dbb6b539f1b6" have entirely different histories.

14 changed files with 170 additions and 203 deletions

View File

@ -25,11 +25,11 @@ This project has example interface code for I2C and SPI used on Raspberry Pi 4,
```c ```c
/* initialise the "interface" */ /* initialise the "interface" */
int init(void); int init(void);
/* read from register `reg', `size' amount of bytes, and write them to `dst' */ /* read from register `reg`, `size` amount of bytes, and write them to `dst` */
int read(uint8_t reg, uint8_t *dst, uint32_t size); int read(uint8_t reg, uint8_t *dst, uint32_t size);
/* write `value' to register `reg' */ /* write `value` to register `reg` */
int write(uint8_t reg, uint8_t value); int write(uint8_t reg, uint8_t value);
/* sleep for `dur_us' microseconds */ /* sleep for `dur_us` microseconds */
int sleep(uint32_t dur_us); int sleep(uint32_t dur_us);
/* deinitalise the "interface" */ /* deinitalise the "interface" */
int deinit(void); int deinit(void);
@ -39,30 +39,10 @@ All above functions return `0` on success, and any non-zero value on error.
If `init` and/or `deinit` are set to `NULL`, they will be ignored. Useful on microcontrollers. If `init` and/or `deinit` are set to `NULL`, they will be ignored. Useful on microcontrollers.
--- ---
## Functions
### STM32
```c ```c
int lis3dh_init(lis3dh_t *lis3dh); #define LIS3DH_I2C_ADDR 0x18
int lis3dh_deinit(lis3dh_t *lis3dh);
int lis3dh_configure(lis3dh_t *lis3dh);
int lis3dh_read(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);
int lis3dh_read_click(lis3dh_t *lis3dh);
int lis3dh_reference(lis3dh_t *lis3dh);
int lis3dh_reset(lis3dh_t *lis3dh);
int lis3dh_read_adc(lis3dh_t *lis3dh);
int lis3dh_read_temp(lis3dh_t *lis3dh);
```
All functions return `0` on success, and any non-zero value on error.
## STM32
Example i2c and SPI functions that work
### i2c
```c
#define LIS3DH_I2C_ADDR 0x18 /* can also be 0x19 */
int i2c_write(uint8_t reg, uint8_t value) { int i2c_write(uint8_t reg, uint8_t value) {
uint8_t buf[2] = { reg, value }; uint8_t buf[2] = { reg, value };
@ -81,8 +61,3 @@ int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
} }
``` ```
### SPI
```c
TODO
```

View File

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

View File

@ -25,7 +25,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* reset device just in case */ /* reset device because it sometimes corrupts itself */
if (lis3dh_reset(&lis)) { if (lis3dh_reset(&lis)) {
/* error handling */ /* error handling */
} }
@ -106,7 +106,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* only print if INT1 interrupt active (IA) = 1*/ /* only print if INT1 interrupt active = 1*/
/* ZH and ZL are always 0 in 4D mode */ /* ZH and ZL are always 0 in 4D mode */
if (LIS3DH_INT_SRC_IA(lis.src.int1)) { if (LIS3DH_INT_SRC_IA(lis.src.int1)) {
/* print received interrupt .. */ /* print received interrupt .. */

View File

@ -25,7 +25,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* reset device just in case */ /* reset device because it sometimes corrupts itself */
if (lis3dh_reset(&lis)) { if (lis3dh_reset(&lis)) {
/* error handling */ /* error handling */
} }
@ -107,7 +107,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* only print if INT1 interrupt active (IA) = 1*/ /* only print if INT1 interrupt active = 1*/
if (LIS3DH_INT_SRC_IA(lis.src.int1)) { if (LIS3DH_INT_SRC_IA(lis.src.int1)) {
/* print received interrupt .. */ /* print received interrupt .. */
printf("IA=%d ZH=%d ZL=%d YH=%d YL=%d XH=%d XL=%d\n", printf("IA=%d ZH=%d ZL=%d YH=%d YL=%d XH=%d XL=%d\n",

View File

@ -25,7 +25,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* reset device just in case */ /* reset device because it sometimes corrupts itself */
if (lis3dh_reset(&lis)) { if (lis3dh_reset(&lis)) {
/* error handling */ /* error handling */
} }
@ -107,7 +107,7 @@ int main() {
/* error handling */ /* error handling */
} }
/* only print if INT1 interrupt active (IA) = 1*/ /* only print if INT1 interrupt active = 1*/
if (LIS3DH_INT_SRC_IA(lis.src.int1)) { if (LIS3DH_INT_SRC_IA(lis.src.int1)) {
/* print received interrupt .. */ /* print received interrupt .. */
printf("IA=%d ZH=%d ZL=%d YH=%d YL=%d XH=%d XL=%d\n", printf("IA=%d ZH=%d ZL=%d YH=%d YL=%d XH=%d XL=%d\n",

View File

@ -4,22 +4,15 @@
Basic example of how to use this device Basic example of how to use this device
### file: fifo.c ### file: fifo.c
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. 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()`.
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. The LIS3DH can optionally apply a HP filter on the sampling to reduce 'static acceleration' from the data.
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()`.
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 sample faster, such as at the advertised 5 KHz rate, you have to use `lis3dh_read()` with `LP` mode.
### file: interrupts.c ### 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 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 overrun 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.)
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 ### file: single-click.c

View File

@ -7,7 +7,7 @@
int main() { int main() {
lis3dh_t lis; lis3dh_t lis;
struct lis3dh_fifo_data fifo; struct lis3dh_fifo_data data;
int i; int i;
lis.dev.init = i2c_init; lis.dev.init = i2c_init;
@ -36,15 +36,15 @@ int main() {
/* error handling */ /* error handling */
} }
/* read as many [x y z] sets as specified by watermark level (size) default (max/32) */ /* read as many [x y z] sets as specified by watermark level (size) default max/32 */
/* copy them to the fifo data struct `fifo' */ /* copy them to the fifo data struct given below as `data' */
if (lis3dh_read_fifo(&lis, &fifo)) { if (lis3dh_read_fifo(&lis, &data)) {
/* error handling */ /* error handling */
} }
/* read out fifo buffer data */ /* read out fifo buffer data */
for(i=0; i<fifo.size; i++) { for(i=0; i<data.size; i++) {
printf("x: %d mg, y: %d mg, z: %d mg\n", fifo.x[i], fifo.y[i], fifo.z[i]); printf("x: %d mg, y: %d mg, z: %d mg\n", data.x[i], data.y[i], data.z[i]);
} }
/* deinitialise struct */ /* deinitialise struct */

View File

@ -46,9 +46,9 @@ int main() {
lis.cfg.int1.latch = 1; /* latch interrupt until INT1_SRC is read */ lis.cfg.int1.latch = 1; /* latch interrupt until INT1_SRC is read */
/* enable all the low directions */ /* enable all the low directions */
/* this works because the low directions are compared to -threshold, */ /* this works because the low directions are compared to -threshold,
/* and are below it at rest, and greater than it at free-fall, */ and are below it at rest, and greater than it at free-fall,
/* while the opposite is true for the high directions. */ while the opposite is true for the high directions. */
lis.cfg.int1.xl = 1; lis.cfg.int1.xl = 1;
lis.cfg.int1.yl = 1; lis.cfg.int1.yl = 1;
lis.cfg.int1.zl = 1; lis.cfg.int1.zl = 1;

View File

@ -64,12 +64,13 @@ int main() {
/* error handling */ /* error handling */
} }
/* read as many [x y z] sets as specified by watermark level (size) */ /* read as many [x y z] sets as specified by watermark level (fth) */
/* copy them to the fifo data struct given below as `fifo' */ /* copy them to the fifo data struct given below as `fifo' */
if (lis3dh_read_fifo(&lis, &fifo)) { if (lis3dh_read_fifo(&lis, &fifo)) {
/* error handling */ /* error handling */
} }
/* above function also writes out the qty of [x y z] sets stored in `fifo' */
for(i=0; i<fifo.size; i++) { 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]); printf("x: %d mg, y: %d mg, z: %d mg\n", fifo.x[i], fifo.y[i], fifo.z[i]);
} }

View File

@ -52,6 +52,8 @@ int main() {
printf("ADC1: %d mV\n", lis.adc.adc1); printf("ADC1: %d mV\n", lis.adc.adc1);
printf("ADC2: %d mV\n", lis.adc.adc2); printf("ADC2: %d mV\n", lis.adc.adc2);
/* no decimals, step size is 1 celsius */
printf("ADC3: %d oC\n", lis.adc.adc3); printf("ADC3: %d oC\n", lis.adc.adc3);
/* deinitalise struct */ /* deinitalise struct */

82
i2c.c
View File

@ -29,63 +29,63 @@ Example I2C use on linux/raspberry pi
static int fd; static int fd;
int i2c_init(void) { int i2c_init(void) {
fd = open(I2C_DEVICE, O_RDWR); fd = open(I2C_DEVICE, O_RDWR);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "i2c_init(): could not open device: %s\n", I2C_DEVICE); fprintf(stderr, "i2c_init(): could not open device: %s\n", I2C_DEVICE);
return 1; return 1;
} }
if (ioctl(fd, I2C_SLAVE, I2C_LIS3DH_ADDRESS) < 0) { if (ioctl(fd, I2C_SLAVE, I2C_LIS3DH_ADDRESS) < 0) {
fprintf(stderr, "i2c_init(): failed to acquire bus/talk to slave\n"); fprintf(stderr, "i2c_init(): failed to acquire bus/talk to slave\n");
close(fd); close(fd);
return 1; return 1;
} }
return 0; return 0;
} }
int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) { int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
uint8_t cmd[2]; uint8_t cmd[2];
if (size > 1) { if (size > 1) {
reg |= 0x80; /* AUTO INC */ reg |= 0x80; /* AUTO INC */
} }
cmd[0] = reg; cmd[0] = reg;
cmd[1] = 0x00; cmd[1] = 0x00;
if (write(fd, cmd, 2) != 2) { if (write(fd, cmd, 2) != 2) {
fprintf(stderr, "i2c_read(): error write()\n"); fprintf(stderr, "i2c_read(): error write()\n");
return 1; return 1;
} }
if (read(fd, dst, size) != (int)size) { if (read(fd, dst, size) != (int)size) {
fprintf(stderr, "i2c_read(): error read()\n"); fprintf(stderr, "i2c_read(): error read()\n");
return 1; return 1;
} }
return 0; return 0;
} }
int i2c_write(uint8_t reg, uint8_t value) { int i2c_write(uint8_t reg, uint8_t value) {
uint8_t cmd[2]; uint8_t cmd[2];
cmd[0] = reg; cmd[0] = reg;
cmd[1] = value; cmd[1] = value;
if (write(fd, cmd, 2) != 2) { if (write(fd, cmd, 2) != 2) {
fprintf(stderr, "i2c_write(): error write()\n"); fprintf(stderr, "i2c_write(): error write()\n");
return 1; return 1;
} }
return 0; return 0;
} }
int i2c_deinit(void) { int i2c_deinit(void) {
if (fd) { if (fd) {
close(fd); close(fd);
} }
return 0; return 0;
} }

View File

@ -1,9 +1,10 @@
#include <stddef.h> /* NULL */ #include <stddef.h>
#include <string.h> /* memset() */ #include <string.h>
#include "lis3dh.h" #include "lis3dh.h"
#include "registers.h" #include "registers.h"
#include <stdio.h>
/* initialise device struct and read WHO_AM_I register */
int lis3dh_init(lis3dh_t *lis3dh) { int lis3dh_init(lis3dh_t *lis3dh) {
uint8_t result; uint8_t result;
int err = 0; int err = 0;
@ -36,8 +37,6 @@ int lis3dh_init(lis3dh_t *lis3dh) {
return err; return err;
} }
/* write configuration options to the device */
/* then sleep 100 ms to let it set itself up properly */
int lis3dh_configure(lis3dh_t *lis3dh) { int lis3dh_configure(lis3dh_t *lis3dh) {
uint8_t ctrl_reg1, ctrl_reg2, ctrl_reg3; uint8_t ctrl_reg1, ctrl_reg2, ctrl_reg3;
uint8_t ctrl_reg4, ctrl_reg5, ctrl_reg6; uint8_t ctrl_reg4, ctrl_reg5, ctrl_reg6;
@ -178,7 +177,7 @@ int lis3dh_configure(lis3dh_t *lis3dh) {
ctrl_reg0 |= (lis3dh->cfg.sdo_pullup & 1) << 7; ctrl_reg0 |= (lis3dh->cfg.sdo_pullup & 1) << 7;
/* Registers have to be set in this order for SPI to function correctly, I think */ /* Registers have to be set in this order for SPI to function correctly */
err |= lis3dh->dev.write(REG_CTRL_REG4, ctrl_reg4); err |= lis3dh->dev.write(REG_CTRL_REG4, ctrl_reg4);
err |= lis3dh->dev.write(REG_CTRL_REG5, ctrl_reg5); err |= lis3dh->dev.write(REG_CTRL_REG5, ctrl_reg5);
err |= lis3dh->dev.write(REG_FIFO_CTRL_REG, fifo_ctrl_reg); err |= lis3dh->dev.write(REG_FIFO_CTRL_REG, fifo_ctrl_reg);
@ -207,9 +206,9 @@ int lis3dh_configure(lis3dh_t *lis3dh) {
return err; return err;
} }
/* the real size of the int you get back from reading the acc u16
/* The "real size" of the i16 accelerometer axis reading depends on the power mode. */ depends on the power mode.
/* shift down the 16 bit word by this amount: */ shift down the 16 bit word by this amount: */
static uint8_t acc_shift(uint8_t mode) { static uint8_t acc_shift(uint8_t mode) {
switch (mode) { switch (mode) {
case LIS3DH_MODE_HR: return 4; /* i12 */ case LIS3DH_MODE_HR: return 4; /* i12 */
@ -219,8 +218,8 @@ static uint8_t acc_shift(uint8_t mode) {
} }
} }
/* returns a scalar that when multiplied with axis reading */ /* returns a scalar that when multiplied with axis reading
/* turns it to a multiple of mg (1/1000 g). */ turns it to a multiple of mg. */
static uint8_t acc_sensitivity(uint8_t mode, uint8_t range) { static uint8_t acc_sensitivity(uint8_t mode, uint8_t range) {
switch (range) { switch (range) {
case LIS3DH_FS_2G: return (mode == LIS3DH_MODE_LP) ? 16 : (mode == LIS3DH_MODE_NORMAL) ? 4 : 1; case LIS3DH_FS_2G: return (mode == LIS3DH_MODE_LP) ? 16 : (mode == LIS3DH_MODE_NORMAL) ? 4 : 1;
@ -241,7 +240,6 @@ int lis3dh_read(lis3dh_t *lis3dh) {
sens = acc_sensitivity(lis3dh->cfg.mode, lis3dh->cfg.range); sens = acc_sensitivity(lis3dh->cfg.mode, lis3dh->cfg.range);
/* poll STATUS_REG until new data is available */ /* poll STATUS_REG until new data is available */
do { do {
err |= lis3dh->dev.read(REG_STATUS_REG, &status, 1); err |= lis3dh->dev.read(REG_STATUS_REG, &status, 1);
lis3dh->dev.sleep(1000); lis3dh->dev.sleep(1000);
@ -255,17 +253,18 @@ int lis3dh_read(lis3dh_t *lis3dh) {
return err; return err;
} }
/* assume fifo has been configured */ /* assume fifo has been configured and poll'd */
/* wait until FIFO is NOT empty, then */ /* wait until FIFO is NOT empty, then */
/* read groups of the 6 OUT bytes until EMPTY flag in FIFO_SRC is set */ /* 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) { int lis3dh_read_fifo(lis3dh_t *lis3dh, struct lis3dh_fifo_data *fifo) {
uint8_t data[6]; uint8_t data[6]; /* max size */
uint8_t sens, fifo_src; uint8_t sens, fifo_src;
int err = 0; int err = 0;
int idx = 0; int idx = 0;
/* wait until there is at least 1 unread sample in the FIFO */ /* 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 { do {
err |= lis3dh->dev.read(REG_FIFO_SRC_REG, &fifo_src, 1); err |= lis3dh->dev.read(REG_FIFO_SRC_REG, &fifo_src, 1);
lis3dh->dev.sleep(1000); lis3dh->dev.sleep(1000);
@ -282,9 +281,6 @@ int lis3dh_read_fifo(lis3dh_t *lis3dh, struct lis3dh_fifo_data *fifo) {
fifo->z[idx] = ((int16_t)(data[5] | data[4] << 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); } while (idx++ < lis3dh->cfg.fifo.size - 1 && !LIS3DH_FIFO_SRC_EMPTY(fifo_src) && !err);
/* the device stores FIFO offsets rather than `size' so a size-32 FIFO */
/* has an offset of 31 */
fifo->size = idx; fifo->size = idx;
return err; return err;
@ -314,8 +310,8 @@ int lis3dh_read_click(lis3dh_t *lis3dh) {
return lis3dh->dev.read(REG_CLICK_SRC, &lis3dh->src.click, 1); return lis3dh->dev.read(REG_CLICK_SRC, &lis3dh->src.click, 1);
} }
/* read REFERENCE reg to reset HP filter in REFERENCE mode */ /* read REFERENCE reg to reset HP filter in REFERENCE mode
/* it then uses the --current-- acceleration as the base in the filter */ it uses the --current-- acceleration as the base in the filter */
int lis3dh_reference(lis3dh_t *lis3dh) { int lis3dh_reference(lis3dh_t *lis3dh) {
uint8_t res; uint8_t res;
return lis3dh->dev.read(REG_REFERENCE, &res, 1); return lis3dh->dev.read(REG_REFERENCE, &res, 1);
@ -363,8 +359,8 @@ int lis3dh_reset(lis3dh_t *lis3dh) {
return err; return err;
} }
/* read all 3 ADCs and convert data depending on power mode */ /* read all 3 ADCs and convert readings depending on power mode
/* result: 1 lsb is equal to 1 millivolt */ st 1 lsb is equal to 1 millivolt */
int lis3dh_read_adc(lis3dh_t *lis3dh) { int lis3dh_read_adc(lis3dh_t *lis3dh) {
uint8_t data[6]; uint8_t data[6];
uint8_t shift; uint8_t shift;
@ -381,13 +377,13 @@ int lis3dh_read_adc(lis3dh_t *lis3dh) {
return err; return err;
} }
/* the temperature sensor only reports the difference between its current temp, */ /* the temperature sensor only reports the difference between its current temp,
/* and the factory calibrated temperature, 25 celsius. */ and the factory calibrated temperature, 25 celsius.
/* in increments of plus or negative 1 unit celsius. */ in increments of plus or negative 1 unit celsius.
/* the reported temperature is stored inplace of adc3 */ the reported temperature is stored inplace of adc3
/* temp sensing is always in 8-bit mode */ temp sensing is always in 8-bit mode
/* operating range: -40 to 85 celsius */ operating range: -40 to 85 celsius
/* 1 lsb = 1 deg C */ 1 lsb = 1 deg C */
int lis3dh_read_temp(lis3dh_t *lis3dh) { int lis3dh_read_temp(lis3dh_t *lis3dh) {
uint8_t data; uint8_t data;
int err = 0; int err = 0;

View File

@ -112,11 +112,11 @@
/* user provided functions, init and deinit can be set to NULL and won't be used */ /* user provided functions, init and deinit can be set to NULL and won't be used */
struct lis3dh_device { struct lis3dh_device {
int (*init)(void); int (*init)(void);
int (*read)(uint8_t reg, uint8_t *dst, uint32_t size); int (*read)(uint8_t reg, uint8_t *dst, uint32_t size);
int (*write)(uint8_t reg, uint8_t value); int (*write)(uint8_t reg, uint8_t value);
int (*sleep)(uint32_t dur_us); int (*sleep)(uint32_t dur_us);
int (*deinit)(void); int (*deinit)(void);
}; };
struct lis3dh_click_config { struct lis3dh_click_config {
@ -289,7 +289,7 @@ typedef struct lis3dh lis3dh_t;
/* struct for containing the FIFO data */ /* struct for containing the FIFO data */
/* 1 lsb = 1 mg */ /* 1 lsb = 1 mg */
struct lis3dh_fifo_data { struct lis3dh_fifo_data {
uint8_t size; /* up to 31 */ uint8_t size; /* up to 32 */
int16_t x[32]; int16_t x[32];
int16_t y[32]; int16_t y[32];
int16_t z[32]; int16_t z[32];

140
spi.c
View File

@ -31,111 +31,111 @@ Example SPI use on linux/raspberry pi
static int fd; static int fd;
int spi_init(void) { int spi_init(void) {
uint8_t mode = SPI_MODE_0; uint8_t mode = SPI_MODE_0;
uint8_t bits = 8; uint8_t bits = 8;
uint32_t speed = SPI_SPEED; uint32_t speed = SPI_SPEED;
if ((fd = open(SPI_DEVICE, O_RDWR)) < 0) { if ((fd = open(SPI_DEVICE, O_RDWR)) < 0) {
fprintf(stderr, "spi_init(): open(%s)\n", SPI_DEVICE); fprintf(stderr, "spi_init(): open(%s)\n", SPI_DEVICE);
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_RD_MODE, &mode) == -1) { if (ioctl(fd, SPI_IOC_RD_MODE, &mode) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_RD_MODE\n"); fprintf(stderr, "spi_init(): SPI_IOC_RD_MODE\n");
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) { if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_WR_MODE\n"); fprintf(stderr, "spi_init(): SPI_IOC_WR_MODE\n");
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) { if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_WR_BITS_PER_WORD\n"); fprintf(stderr, "spi_init(): SPI_IOC_WR_BITS_PER_WORD\n");
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) { if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_RD_BITS_PER_WORD\n"); fprintf(stderr, "spi_init(): SPI_IOC_RD_BITS_PER_WORD\n");
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) { if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_WR_MAX_SPEED_HZ\n"); fprintf(stderr, "spi_init(): SPI_IOC_WR_MAX_SPEED_HZ\n");
return 1; return 1;
} }
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) { if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) {
fprintf(stderr, "spi_init(): SPI_IOC_RD_MAX_SPEED_HZ\n"); fprintf(stderr, "spi_init(): SPI_IOC_RD_MAX_SPEED_HZ\n");
return 1; return 1;
} }
return 0; return 0;
} }
int spi_read(uint8_t reg, uint8_t *dst, uint32_t size) { int spi_read(uint8_t reg, uint8_t *dst, uint32_t size) {
uint8_t send[2]; uint8_t send[2];
struct spi_ioc_transfer tr[2] = {0}; struct spi_ioc_transfer tr[2] = {0};
/* clear 2 MSbits */ /* clear 2 MSbits */
reg &= 0x3F; reg &= 0x3F;
/* set READ bit */ /* set READ bit */
reg |= 0x80; reg |= 0x80;
if (size > 1) { if (size > 1) {
/* set AUTO INC bit */ /* set AUTO INC bit */
reg |= 0x40; reg |= 0x40;
} }
send[0] = reg; send[0] = reg;
send[1] = 0x00; send[1] = 0x00;
tr[0].tx_buf = (unsigned long) send; tr[0].tx_buf = (unsigned long) send;
tr[0].rx_buf = (unsigned long) 0; tr[0].rx_buf = (unsigned long) 0;
tr[0].len = 2; tr[0].len = 2;
tr[1].tx_buf = (unsigned long) 0; tr[1].tx_buf = (unsigned long) 0;
tr[1].rx_buf = (unsigned long) dst; tr[1].rx_buf = (unsigned long) dst;
tr[1].len = size; tr[1].len = size;
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) { if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
fprintf(stderr, "spi_read(): error ioctl()\n"); fprintf(stderr, "spi_read(): error ioctl()\n");
return 1; return 1;
} }
return 0; return 0;
} }
int spi_write(uint8_t reg, uint8_t value) { int spi_write(uint8_t reg, uint8_t value) {
struct spi_ioc_transfer tr[2] = {0}; struct spi_ioc_transfer tr[2] = {0};
/* clear 2 MSbits */ /* clear 2 MSbits */
reg &= 0x3F; reg &= 0x3F;
tr[0].tx_buf = (unsigned long) &reg; tr[0].tx_buf = (unsigned long) &reg;
tr[0].rx_buf = (unsigned long) 0; tr[0].rx_buf = (unsigned long) 0;
tr[0].len = 1; tr[0].len = 1;
tr[1].tx_buf = (unsigned long) &value; tr[1].tx_buf = (unsigned long) &value;
tr[1].rx_buf = (unsigned long) 0; tr[1].rx_buf = (unsigned long) 0;
tr[1].len = 1; tr[1].len = 1;
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) { if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
fprintf(stderr, "spi_write(): error ioctl()\n"); fprintf(stderr, "spi_write(): error ioctl()\n");
return 1; return 1;
} }
return 0; return 0;
} }
int spi_deinit(void) { int spi_deinit(void) {
if (fd) { if (fd) {
close(fd); close(fd);
} }
return 0; return 0;
} }