Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion drivers/sensors/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1642,17 +1642,34 @@ config SENSORS_MAX6675
config SENSORS_LIS2MDL
bool "STMicro LIS2MDL 3-Axis magnetometer support"
default n
select I2C
select SPI if SENSORS_LIS2MDL_SPI
select I2C if !SENSORS_LIS2MDL_SPI
---help---
Enable UORB driver support for the STMicro LIS2MDL 3-axis magnetometer.

if SENSORS_LIS2MDL

config SENSORS_LIS2MDL_SPI
bool "Connect LIS2MDL via SPI"
default n
---help---
Use SPI instead of I2C to communicate with the LIS2MDL.

config SENSORS_LIS2MDL_I2C_FREQUENCY
int "LIS2MDL I2C frequency"
depends on !SENSORS_LIS2MDL_SPI
default 1000000
range 1 3400000

if SENSORS_LIS2MDL_SPI

config SENSORS_LIS2MDL_SPI_FREQUENCY
int "LIS2MDL SPI frequency"
default 10000000
range 1 10000000

endif # SENSORS_LIS2MDL_SPI

config SENSORS_LIS2MDL_THREAD_STACKSIZE
int "LIS2MDL worker thread stack size"
default 1024
Expand Down
96 changes: 73 additions & 23 deletions drivers/sensors/lis2mdl_uorb.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@

#include <nuttx/clock.h>
#include <nuttx/fs/fs.h>
#include <nuttx/i2c/i2c_master.h>
#ifdef CONFIG_SENSORS_LIS2MDL_SPI
# include <nuttx/spi/spi.h>
#else
# include <nuttx/i2c/i2c_master.h>
#endif
#include <nuttx/kmalloc.h>
#include <nuttx/kthread.h>
#include <nuttx/mutex.h>
Expand Down Expand Up @@ -131,8 +135,7 @@ enum lis2mdl_mode_e
struct lis2mdl_dev_s
{
struct sensor_lowerhalf_s lower; /* UORB lower-half */
FAR struct i2c_master_s *i2c; /* I2C interface */
uint8_t addr; /* I2C address */
struct lis2mdl_config_s config; /* SPI/I2C interface config */
sem_t run; /* Polling cycle lock */
mutex_t devlock; /* Exclusive access to device */
enum lis2mdl_odr_e odr; /* Configured ODR */
Expand Down Expand Up @@ -236,65 +239,108 @@ static const struct sensor_ops_s g_sensor_ops =
****************************************************************************/

/****************************************************************************
* Name: lis2mdl_read_reg
* Name: lis2mdl_read_reg / lis2mdl_write_reg
*
* Description:
* Read `nbytes` from the register at `addr` into `buf`.
* Read/write registers over SPI or I2C depending on build configuration.
****************************************************************************/

#ifdef CONFIG_SENSORS_LIS2MDL_SPI

static int lis2mdl_read_reg(FAR struct lis2mdl_dev_s *dev, uint8_t addr,
void *buf, uint8_t nbytes)
{
FAR struct spi_dev_s *spi = dev->config.spi;
int id = dev->config.spi_devid;

SPI_LOCK(spi, true);
SPI_SETMODE(spi, SPIDEV_MODE0);
SPI_SETBITS(spi, 8);
SPI_SETFREQUENCY(spi, CONFIG_SENSORS_LIS2MDL_SPI_FREQUENCY);
SPI_SELECT(spi, id, true);
SPI_SEND(spi, addr | 0x80); /* bit 7 = read */
for (uint8_t i = 0; i < nbytes; i++)
{
((uint8_t *)buf)[i] = (uint8_t)SPI_SEND(spi, 0xff);
}

SPI_SELECT(spi, id, false);
SPI_LOCK(spi, false);
return nbytes;
}

static int lis2mdl_write_reg(FAR struct lis2mdl_dev_s *dev, uint8_t addr,
void *buf, uint8_t nbytes)
{
FAR struct spi_dev_s *spi = dev->config.spi;
int id = dev->config.spi_devid;

SPI_LOCK(spi, true);
SPI_SETMODE(spi, SPIDEV_MODE0);
SPI_SETBITS(spi, 8);
SPI_SETFREQUENCY(spi, CONFIG_SENSORS_LIS2MDL_SPI_FREQUENCY);
SPI_SELECT(spi, id, true);
SPI_SEND(spi, addr); /* bit 7 = 0, write */
for (uint8_t i = 0; i < nbytes; i++)
{
SPI_SEND(spi, ((uint8_t *)buf)[i]);
}

SPI_SELECT(spi, id, false);
SPI_LOCK(spi, false);
return nbytes;
}

#else

static int lis2mdl_read_reg(FAR struct lis2mdl_dev_s *dev, uint8_t addr,
void *buf, uint8_t nbytes)
{
struct i2c_msg_s readcmd[2] = {
{
.frequency = CONFIG_SENSORS_LIS2MDL_I2C_FREQUENCY,
.addr = dev->addr,
.addr = dev->config.addr,
.flags = I2C_M_NOSTOP,
.buffer = &addr,
.length = sizeof(addr),
},
{
.frequency = CONFIG_SENSORS_LIS2MDL_I2C_FREQUENCY,
.addr = dev->addr,
.addr = dev->config.addr,
.flags = I2C_M_READ,
.buffer = buf,
.length = nbytes,
},
};

return I2C_TRANSFER(dev->i2c, readcmd, 2);
return I2C_TRANSFER(dev->config.i2c, readcmd, 2);
}

/****************************************************************************
* Name: lis2mdl_write_reg
*
* Description:
* Write `nbytes` from `buf` to the registers starting at `addr`.
****************************************************************************/

static int lis2mdl_write_reg(FAR struct lis2mdl_dev_s *dev, uint8_t addr,
void *buf, uint8_t nbytes)
{
struct i2c_msg_s writecmd[2] = {
{
.frequency = CONFIG_SENSORS_LIS2MDL_I2C_FREQUENCY,
.addr = dev->addr,
.addr = dev->config.addr,
.flags = I2C_M_NOSTOP,
.buffer = &addr,
.length = sizeof(addr),
},
{
.frequency = CONFIG_SENSORS_LIS2MDL_I2C_FREQUENCY,
.addr = dev->addr,
.addr = dev->config.addr,
.flags = I2C_M_NOSTART,
.buffer = buf,
.length = nbytes,
},
};

return I2C_TRANSFER(dev->i2c, writecmd, 2);
return I2C_TRANSFER(dev->config.i2c, writecmd, 2);
}

#endif /* CONFIG_SENSORS_LIS2MDL_SPI */

/****************************************************************************
* Name: lis2mdl_read_data
*
Expand Down Expand Up @@ -1253,16 +1299,21 @@ static int lis2mdl_thread(int argc, char **argv)
*
****************************************************************************/

int lis2mdl_register(FAR struct i2c_master_s *i2c, int devno, uint8_t addr,
int lis2mdl_register(FAR struct lis2mdl_config_s *config, int devno,
lis2mdl_attach attach)
{
FAR struct lis2mdl_dev_s *priv;
int err;
FAR char *argv[2];
char arg1[32];

DEBUGASSERT(i2c != NULL);
DEBUGASSERT(addr == 0x1e);
DEBUGASSERT(config != NULL);
#ifdef CONFIG_SENSORS_LIS2MDL_SPI
DEBUGASSERT(config->spi != NULL);
#else
DEBUGASSERT(config->i2c != NULL);
DEBUGASSERT(config->addr == 0x1e);
#endif

/* High priority work queue is required for interrupt driven mode */

Expand All @@ -1286,8 +1337,7 @@ int lis2mdl_register(FAR struct i2c_master_s *i2c, int devno, uint8_t addr,

memset(priv, 0, sizeof(struct lis2mdl_dev_s));

priv->i2c = i2c;
priv->addr = addr;
priv->config = *config;

err = nxmutex_init(&priv->devlock);
if (err < 0)
Expand Down
22 changes: 18 additions & 4 deletions include/nuttx/sensors/lis2mdl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,33 @@
* Included Files
****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/sensors/ioctl.h>
#include <nuttx/irq.h>

/****************************************************************************
* Public Types
****************************************************************************/

#ifdef CONFIG_SENSORS_LIS2MDL_SPI
struct spi_dev_s; /* Forward reference */
#else
struct i2c_master_s; /* Forward reference */
#endif

typedef int (*lis2mdl_attach)(xcpt_t, FAR void *arg);

struct lis2mdl_config_s
{
#ifdef CONFIG_SENSORS_LIS2MDL_SPI
FAR struct spi_dev_s *spi;
int spi_devid;
#else
FAR struct i2c_master_s *i2c;
uint8_t addr;
#endif
};

/****************************************************************************
* Public Function Prototypes
****************************************************************************/
Expand All @@ -46,9 +62,7 @@ typedef int (*lis2mdl_attach)(xcpt_t, FAR void *arg);
* Register the LIS2MDL device as a UORB sensor.
*
* Input Parameters:
* i2c - An instance of the I2C interface to use to communicate with
* the LIS2MDL.
* addr - The I2C address of the LIS2MDL. Should always be 0x1e.
* config - SPI or I2C interface configuration.
* devno - The device number to use for the topic (i.e. /dev/mag0)
* attach - A function which is called by this driver to attach the
* LIS2MDL interrupt handler to an IRQ. Pass NULL to operate
Expand All @@ -60,5 +74,5 @@ typedef int (*lis2mdl_attach)(xcpt_t, FAR void *arg);
*
****************************************************************************/

int lis2mdl_register(FAR struct i2c_master_s *i2c, int devno, uint8_t addr,
int lis2mdl_register(FAR struct lis2mdl_config_s *config, int devno,
lis2mdl_attach attach);
Loading