SPI working! when using SPI, the order of writing out ctrl_reg's matters....but seemingly not when using i2c

This commit is contained in:
William Clark 2024-01-06 00:52:37 +00:00
parent f6020e9d15
commit 485922d898
5 changed files with 93 additions and 121 deletions

View File

@ -21,7 +21,7 @@ See the `examples/` dir for complete code examples
## Implementation
This driver requires the user to implement the following interface functions:
This project has example interface code for I2C and SPI (broken) used on Raspberry Pi 4.
This project has example interface code for I2C and SPI used on Raspberry Pi 4.
```c
/* initialise the "interface" */
int init(void);
@ -52,6 +52,9 @@ int i2c_write(uint8_t reg, uint8_t value) {
}
int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
if (size > 1) {
reg |= 0x80; /* auto-increment bit */
}
uint8_t send[2] = { reg, 0x00 };
HAL_I2C_Master_Transmit(&hi2c2, LIS3DH_I2C_ADDR << 1, send, 2, HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c2, LIS3DH_I2C_ADDR << 1, dst, size, HAL_MAX_DELAY);

19
i2c.c
View File

@ -24,19 +24,19 @@ Example I2C use on linux/raspberry pi
*/
#define I2C_DEVICE "/dev/i2c-1"
#define I2C_LIS3DH_ADDRESS 0x18
#define I2C_LIS3DH_ADDRESS 0x18 /* Can also be 0x19 */
static int fd;
int i2c_init(void) {
fd = open(I2C_DEVICE, O_RDWR);
if (fd < 0) {
fprintf(stderr, "[i2c] could not open device: %s\n", I2C_DEVICE);
fprintf(stderr, "i2c_init(): could not open device: %s\n", I2C_DEVICE);
return 1;
}
if (ioctl(fd, I2C_SLAVE, I2C_LIS3DH_ADDRESS) < 0) {
fprintf(stderr, "[i2c] failed to acquire bus/talk to slave\n");
fprintf(stderr, "i2c_init(): failed to acquire bus/talk to slave\n");
close(fd);
return 1;
}
@ -44,7 +44,6 @@ int i2c_init(void) {
return 0;
}
int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
uint8_t cmd[2];
@ -55,10 +54,13 @@ int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
cmd[0] = reg;
cmd[1] = 0x00;
write(fd, cmd, 2);
if (write(fd, cmd, 2) != 2) {
fprintf(stderr, "i2c_read(): error write()\n");
return 1;
}
if (read(fd, dst, size) != (ssize_t)size) {
fprintf(stderr, "[i2c] error read()\n");
if (read(fd, dst, size) != (int)size) {
fprintf(stderr, "i2c_read(): error read()\n");
return 1;
}
@ -66,7 +68,6 @@ int i2c_read(uint8_t reg, uint8_t *dst, uint32_t size) {
return 0;
}
int i2c_write(uint8_t reg, uint8_t value) {
uint8_t cmd[2];
@ -74,7 +75,7 @@ int i2c_write(uint8_t reg, uint8_t value) {
cmd[1] = value;
if (write(fd, cmd, 2) != 2) {
fprintf(stderr, "[i2c] error write()\n");
fprintf(stderr, "i2c_write(): error write()\n");
return 1;
}

View File

@ -175,7 +175,9 @@ int lis3dh_configure(lis3dh_t *lis3dh) {
ctrl_reg0 |= 0x10;
ctrl_reg0 |= (lis3dh->cfg.sdo_pullup & 1) << 7;
/* write these before the control regs that start the device */
err |= lis3dh->dev.write(REG_CTRL_REG4, ctrl_reg4);
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_INT1_CFG, int1_cfg);
err |= lis3dh->dev.write(REG_INT1_THS, int1_ths);
@ -193,16 +195,15 @@ int lis3dh_configure(lis3dh_t *lis3dh) {
err |= lis3dh->dev.write(REG_TEMP_CFG_REG, temp_cfg_reg);
err |= lis3dh->dev.write(REG_REFERENCE, lis3dh->cfg.reference);
err |= lis3dh->dev.write(REG_CTRL_REG0, ctrl_reg0);
err |= lis3dh->dev.write(REG_CTRL_REG1, ctrl_reg1);
err |= lis3dh->dev.write(REG_CTRL_REG6, ctrl_reg6);
err |= lis3dh->dev.write(REG_CTRL_REG0, ctrl_reg0);
err |= lis3dh->dev.write(REG_CTRL_REG2, ctrl_reg2);
err |= lis3dh->dev.write(REG_CTRL_REG3, ctrl_reg3);
err |= lis3dh->dev.write(REG_CTRL_REG4, ctrl_reg4);
err |= lis3dh->dev.write(REG_CTRL_REG5, ctrl_reg5);
err |= lis3dh->dev.write(REG_CTRL_REG6, ctrl_reg6);
/* sleep for a period TBD ~ ODR */
lis3dh->dev.sleep(50000); /* 50 ms */
lis3dh->dev.sleep(1000); /* 50 ms */
return err;
}
@ -335,6 +336,9 @@ int lis3dh_reset(lis3dh_t *lis3dh) {
/* set BOOT bit so device reloads internal trim parameters */
err |= lis3dh->dev.write(REG_CTRL_REG5, 0x80);
/* wait 30 ms */
lis3dh->dev.sleep(30000);
/* write default values to rw regs */
err |= lis3dh->dev.write(REG_CTRL_REG0, 0x10);
err |= lis3dh->dev.write(REG_CTRL_REG1, 0x07);
@ -358,6 +362,12 @@ int lis3dh_reset(lis3dh_t *lis3dh) {
err |= lis3dh->dev.write(REG_ACT_THS, 0x00);
err |= lis3dh->dev.write(REG_ACT_DUR, 0x00);
/* set BOOT bit again so device reloads internal trim parameters */
err |= lis3dh->dev.write(REG_CTRL_REG5, 0x80);
/* wait 30 ms */
lis3dh->dev.sleep(30000);
return err;
}

96
main.c
View File

@ -1,107 +1,65 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include "lis3dh.h"
#include "interrupt.h"
#include "i2c.h"
/* GPIO 12 or Pin 32 */
#define GPIO_INTERRUPT_PIN 12
static void quit(const char *msg, lis3dh_t *lis) {
lis->dev.deinit();
fprintf(stderr, "%s\n", msg);
exit(1);
}
static float mag(float x, float y, float z) {
return (float) sqrt(x*x + y*y + z*z);
}
#include "spi.h"
int main() {
lis3dh_t lis;
struct lis3dh_fifo_data fifo;
int k;
struct lis3dh_fifo_data data;
int i;
lis.dev.init = i2c_init;
lis.dev.read = i2c_read;
lis.dev.write = i2c_write;
lis.dev.init = spi_init;
lis.dev.read = spi_read;
lis.dev.write = spi_write;
lis.dev.sleep = usleep;
lis.dev.deinit = i2c_deinit;
lis.dev.deinit = spi_deinit;
/* initalise LIS3DH struct */
/* initialise LIS3DH struct */
if (lis3dh_init(&lis)) {
quit("init()", &lis);
puts("init()");
}
/* reset device just in case */
if (lis3dh_reset(&lis)) {
quit("reset()", &lis);
}
/* register interrupt */
if (int_register(GPIO_INTERRUPT_PIN)) {
quit("int_register()", &lis);
puts("reset()");
}
lis.cfg.mode = LIS3DH_MODE_HR;
lis.cfg.range = LIS3DH_FS_2G;
lis.cfg.rate = LIS3DH_ODR_400_HZ;
lis.cfg.fifo.mode = LIS3DH_FIFO_MODE_STREAM_TO_FIFO;
lis.cfg.fifo.trig = LIS3DH_FIFO_TRIG_INT1; /* trigger interrupt into int pin1 */
lis.cfg.pin1.wtm = 1; /* trigger upon FIFO watermark level reached */
lis.cfg.en_adc =1;
lis.cfg.en_temp = 1;
lis.cfg.fifo.size = 20;
/* write device config */
if (lis3dh_configure(&lis)) {
quit("configure()", &lis);
puts("configure()");
}
/* wait for interrupt from LIS3DH */
if (int_poll(GPIO_INTERRUPT_PIN)) {
quit("int_poll()", &lis);
A:
/* 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)) {
puts("poll_fifo()");
}
/* 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)) {
quit("read_fifo()", &lis);
if (lis3dh_read_fifo(&lis, &data)) {
puts("read_fifo()");
}
/* above function also writes out the qty of [x y z] sets stored in `fifo' */
for(k=0; k<fifo.size; k++) {
printf("x: %d, y: %d z: %d\n",
fifo.x[k], fifo.y[k], fifo.z[k]);
/* read out fifo buffer data */
for(i=0; i<data.size; i++) {
printf("x: %d mg, y: %d mg, z: %d mg\n", data.x[i], data.y[i], data.z[i]);
}
printf("mag: %04.04f\n", mag(100.0, 45.0, 120.0));
if (lis3dh_read_adc(&lis)) {
quit("adc()", &lis);
}
if (lis3dh_read_temp(&lis)) {
quit("temp()", &lis);
}
printf("ADC1: %d mV, temp: %d\n", lis.adc.adc1, lis.adc.adc3);
/* unregister interrupt */
if (int_unregister(GPIO_INTERRUPT_PIN)) {
quit("int_unregister()", &lis);
}
/* deinitalise struct */
goto A;
/* deinitialise struct */
if (lis3dh_deinit(&lis)) {
quit("deinit()", &lis);
puts("deinit()");
}
return 0;

70
spi.c
View File

@ -16,81 +16,68 @@ Example SPI use on linux/raspberry pi
#include "spi.h"
#define SPI_DEVICE "/dev/spidev0.0"
#define SPI_SPEED 1000 * 1000 /* 1 MHz */
/*
* Pinout config for this example
*
* MOSI - GPIO 10 (physical pin 19) => LIS3DH "SDA" or "SDI"
* MISO - GPIO 9 (physical pin 21) => LIS3DH "SDO"
* SCLK - GPIO 11 (physical pin 23) => LIS3DH "SCK"
* SCLK - GPIO 11 (physical pin 23) => LIS3DH "SCL"
* CE0 - GPIO 8 (physical pin 24) => LIS3DH "!CS"
*
* Broken for unknown reason on Pi 4
*
*/
#define SPI_SPEED 500 * 1000 /* 500 KHz */
static int fd;
static uint8_t rx[256];
static uint8_t tx[256];
int spi_init(void) {
uint8_t mode = SPI_MODE_3;
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
uint32_t speed = SPI_SPEED;
if ((fd = open(SPI_DEVICE, O_RDWR)) < 0) {
fprintf(stderr, "spi open(%s)\n", SPI_DEVICE);
fprintf(stderr, "spi_init(): open(%s)\n", SPI_DEVICE);
return 1;
}
if (ioctl(fd, SPI_IOC_RD_MODE, &mode) == -1) {
fprintf(stderr, "SPI_IOC_RD_MODE\n");
fprintf(stderr, "spi_init(): SPI_IOC_RD_MODE\n");
return 1;
}
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
fprintf(stderr, "SPI_IOC_WR_MODE\n");
fprintf(stderr, "spi_init(): SPI_IOC_WR_MODE\n");
return 1;
}
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
fprintf(stderr, "SPI_IOC_WR_BITS_PER_WORD\n");
fprintf(stderr, "spi_init(): SPI_IOC_WR_BITS_PER_WORD\n");
return 1;
}
if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) == -1) {
fprintf(stderr, "SPI_IOC_RD_BITS_PER_WORD\n");
fprintf(stderr, "spi_init(): SPI_IOC_RD_BITS_PER_WORD\n");
return 1;
}
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
fprintf(stderr, "SPI_IOC_WR_MAX_SPEED_HZ\n");
fprintf(stderr, "spi_init(): SPI_IOC_WR_MAX_SPEED_HZ\n");
return 1;
}
if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1) {
fprintf(stderr, "SPI_IOC_RD_MAX_SPEED_HZ\n");
fprintf(stderr, "spi_init(): SPI_IOC_RD_MAX_SPEED_HZ\n");
return 1;
}
return 0;
}
static int spi_transaction(uint8_t *tx, uint8_t *rx, uint32_t size) {
struct spi_ioc_transfer tr = {0};
tr.tx_buf = (unsigned long) tx;
tr.rx_buf = (unsigned long) rx;
tr.len = size;
return ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
}
int spi_read(uint8_t reg, uint8_t *dst, uint32_t size) {
uint8_t send[2];
struct spi_ioc_transfer tr[2] = {0};
/* clear 2 MSbits */
reg &= 0x3F;
@ -102,28 +89,41 @@ int spi_read(uint8_t reg, uint8_t *dst, uint32_t size) {
reg |= 0x40;
}
tx[0] = reg;
send[0] = reg;
send[1] = 0x00;
if (spi_transaction(tx, rx, size + 1) < 0) {
fprintf(stderr, "spi_read()\n");
tr[0].tx_buf = (unsigned long) send;
tr[0].rx_buf = (unsigned long) 0;
tr[0].len = 2;
tr[1].tx_buf = (unsigned long) 0;
tr[1].rx_buf = (unsigned long) dst;
tr[1].len = size;
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
fprintf(stderr, "spi_read(): error ioctl()\n");
return 1;
}
memcpy(dst, rx + 1, size);
return 0;
}
int spi_write(uint8_t reg, uint8_t value) {
struct spi_ioc_transfer tr[2] = {0};
/* clear 2 MSbits */
reg &= 0x3F;
tx[0] = reg;
tx[1] = value;
tr[0].tx_buf = (unsigned long) &reg;
tr[0].rx_buf = (unsigned long) 0;
tr[0].len = 1;
if (spi_transaction(tx, rx, 2) < 0) {
fprintf(stderr, "spi_write()\n");
tr[1].tx_buf = (unsigned long) &value;
tr[1].rx_buf = (unsigned long) 0;
tr[1].len = 1;
if (ioctl(fd, SPI_IOC_MESSAGE(2), tr) < 0) {
fprintf(stderr, "spi_write(): error ioctl()\n");
return 1;
}