lsm303agr: support SPI transport

This commit is contained in:
Andrey Gusakov 2023-12-14 01:36:15 +03:00
parent 1cf5f0af49
commit 240b3ca51f
2 changed files with 165 additions and 87 deletions

View File

@ -54,6 +54,51 @@ typedef enum {
/* Driver local functions. */ /* Driver local functions. */
/*===========================================================================*/ /*===========================================================================*/
#if (LSM303AGR_USE_I2C == TRUE)
static void lsm303agrStartBus(const LSM303AGRConfig *config) {
i2cStart(config->i2cp,
config->i2ccfg);
osalDbgAssert((config->i2cp->state == I2C_READY),
"lsm303agr, channel not ready");
}
static void lsm303agrStopBus(const LSM303AGRConfig *config) {
i2cStop(config->i2cp);
}
#if (LSM303AGR_SHARED_I2C == TRUE)
static void lsm303agrAccureBus(const LSM303AGRConfig *config) {
i2cAcquireBus(config->i2cp);
}
static void lsm303agrReleaseBus(const LSM303AGRConfig *config) {
i2cReleaseBus(config->i2cp);
}
#endif
#endif
#if (LSM303AGR_USE_SPI == TRUE)
static void lsm303agrStartBus(const LSM303AGRConfig *config) {
spiStart(config->spip,
config->spicfg);
osalDbgAssert((config->spip->state == SPI_READY),
"lsm303agr, channel not ready");
}
static void lsm303agrStopBus(const LSM303AGRConfig *config) {
spiStop(config->spip);
}
#if (LSM303AGR_SHARED_SPI == TRUE)
static void lsm303agrAccureBus(const LSM303AGRConfig *config) {
spiAcquireBus(config->spip);
}
static void lsm303agrReleaseBus(const LSM303AGRConfig *config) {
spiReleaseBus(config->spip);
}
#endif
#endif
/** /**
* @brief Reads registers value using I2C. * @brief Reads registers value using I2C.
* @pre The I2C interface must be initialized and the driver started. * @pre The I2C interface must be initialized and the driver started.
@ -68,10 +113,25 @@ typedef enum {
*/ */
static msg_t lsm303agrReadRegister(const LSM303AGRConfig *config, lsm303agr_sad_t sad, static msg_t lsm303agrReadRegister(const LSM303AGRConfig *config, lsm303agr_sad_t sad,
uint8_t reg, uint8_t *rxbuf, size_t n) { uint8_t reg, uint8_t *rxbuf, size_t n) {
#if (LSM303AGR_USE_I2C == TRUE)
uint8_t txbuf = reg | LSM303AGR_MS; uint8_t txbuf = reg | LSM303AGR_MS;
return i2cMasterTransmitTimeout(config->i2cp, sad, &txbuf, 1, rxbuf, n, return i2cMasterTransmitTimeout(config->i2cp, sad, &txbuf, 1, rxbuf, n,
TIME_INFINITE); TIME_INFINITE);
#endif
#if (LSM303AGR_USE_SPI == TRUE)
uint8_t cmd = (reg & LSM303AGR_SPI_AD_MASK) | LSM303AGR_SPI_MS | LSM303AGR_SPI_RD;
/* SPI mode supports only Accel */
if (sad != LSM303AGR_SAD_ACC)
return MSG_OK;
spiSelect(config->spip);
spiSend(config->spip, 1, &cmd);
spiReceive(config->spip, n, rxbuf);
spiUnselect(config->spip);
return MSG_OK;
#endif
} }
/** /**
@ -87,11 +147,36 @@ static msg_t lsm303agrReadRegister(const LSM303AGRConfig *config, lsm303agr_sad_
* @return the operation status. * @return the operation status.
*/ */
static msg_t lsm303agrWriteRegister(const LSM303AGRConfig *config, lsm303agr_sad_t sad, static msg_t lsm303agrWriteRegister(const LSM303AGRConfig *config, lsm303agr_sad_t sad,
uint8_t *txbuf, size_t n) { uint8_t reg, uint8_t *txdata, size_t n) {
#if (LSM303AGR_USE_I2C == TRUE)
int i;
uint8_t txbuf[1 + 8];
if (n > 8)
return MSG_RESET;
txbuf[0] = reg;
if (n != 1) if (n != 1)
*txbuf |= LSM303AGR_MS; txbuf[0] |= LSM303AGR_MS;
for (i = 0; i < n; i++)
txbuf[i + 1] = txdata[i];
return i2cMasterTransmitTimeout(config->i2cp, sad, txbuf, n + 1, NULL, 0, return i2cMasterTransmitTimeout(config->i2cp, sad, txbuf, n + 1, NULL, 0,
TIME_INFINITE); TIME_INFINITE);
#endif
#if (LSM303AGR_USE_SPI == TRUE)
uint8_t cmd = (reg & LSM303AGR_SPI_AD_MASK) | LSM303AGR_SPI_MS;
/* SPI mode supports only Accel */
if (sad != LSM303AGR_SAD_ACC)
return MSG_OK;
spiSelect(config->spip);
spiSend(config->spip, 1, &cmd);
spiSend(config->spip, n, txdata);
spiUnselect(config->spip);
return MSG_OK;
#endif
} }
/** /**
@ -137,21 +222,18 @@ static msg_t acc_read_raw(void *ip, int32_t axes[]) {
osalDbgAssert((devp->state == LSM303AGR_READY), osalDbgAssert((devp->state == LSM303AGR_READY),
"acc_read_raw(), invalid state"); "acc_read_raw(), invalid state");
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cAcquireBus(devp->config->i2cp); lsm303agrAccureBus(devp->config);
i2cStart(devp->config->i2cp, lsm303agrStartBus(devp->config);
devp->config->i2ccfg); #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
#endif /* LSM303AGR_SHARED_I2C */
osalDbgAssert((devp->config->i2cp->state == I2C_READY),
"acc_read_raw(), channel not ready");
msg = lsm303agrReadRegister(devp->config, LSM303AGR_SAD_ACC, msg = lsm303agrReadRegister(devp->config, LSM303AGR_SAD_ACC,
LSM303AGR_AD_OUT_X_L_A, buff, LSM303AGR_AD_OUT_X_L_A, buff,
LSM303AGR_ACC_NUMBER_OF_AXES * 2); LSM303AGR_ACC_NUMBER_OF_AXES * 2);
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cReleaseBus(devp->config->i2cp); lsm303agrReleaseBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
if(msg == MSG_OK) if(msg == MSG_OK)
for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) {
@ -355,7 +437,7 @@ static msg_t acc_reset_sensivity(void *ip) {
static msg_t acc_set_full_scale(LSM303AGRDriver *devp, static msg_t acc_set_full_scale(LSM303AGRDriver *devp,
lsm303agr_acc_fs_t fs) { lsm303agr_acc_fs_t fs) {
float newfs, scale; float newfs, scale;
uint8_t i, buff[2]; uint8_t i, buff[1];
msg_t msg; msg_t msg;
osalDbgCheck(devp != NULL); osalDbgCheck(devp != NULL);
@ -386,13 +468,10 @@ static msg_t acc_set_full_scale(LSM303AGRDriver *devp,
scale = newfs / devp->accfullscale; scale = newfs / devp->accfullscale;
devp->accfullscale = newfs; devp->accfullscale = newfs;
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cAcquireBus(devp->config->i2cp); lsm303agrAccureBus(devp->config);
i2cStart(devp->config->i2cp, lsm303agrStartBus(devp->config);
devp->config->i2ccfg); #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
#endif /* LSM303AGR_SHARED_I2C */
osalDbgAssert((devp->config->i2cp->state == I2C_READY),
"acc_set_full_scale(), channel not ready");
/* Updating register.*/ /* Updating register.*/
msg = lsm303agrReadRegister(devp->config, msg = lsm303agrReadRegister(devp->config,
@ -403,16 +482,15 @@ static msg_t acc_set_full_scale(LSM303AGRDriver *devp,
if(msg != MSG_OK) if(msg != MSG_OK)
return msg; return msg;
buff[1] &= ~(LSM303AGR_CTRL_REG4_A_FS_MASK); buff[0] &= ~(LSM303AGR_CTRL_REG4_A_FS_MASK);
buff[1] |= fs; buff[0] |= fs;
buff[0] = LSM303AGR_AD_CTRL_REG4_A;
msg = lsm303agrWriteRegister(devp->config, msg = lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_ACC,
LSM303AGR_SAD_ACC, buff, 1); LSM303AGR_AD_CTRL_REG4_A, buff, 1);
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cReleaseBus(devp->config->i2cp); lsm303agrReleaseBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
if(msg != MSG_OK) if(msg != MSG_OK)
return msg; return msg;
@ -469,21 +547,18 @@ static msg_t comp_read_raw(void *ip, int32_t axes[]) {
osalDbgAssert((devp->state == LSM303AGR_READY), osalDbgAssert((devp->state == LSM303AGR_READY),
"comp_read_raw(), invalid state"); "comp_read_raw(), invalid state");
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cAcquireBus(devp->config->i2cp); lsm303agrAccureBus(devp->config);
i2cStart(devp->config->i2cp, lsm303agrStartBus(devp->config);
devp->config->i2ccfg); #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
#endif /* LSM303AGR_SHARED_I2C */
osalDbgAssert((devp->config->i2cp->state == I2C_READY),
"comp_read_raw(), channel not ready");
msg = lsm303agrReadRegister(devp->config, LSM303AGR_SAD_COMP, msg = lsm303agrReadRegister(devp->config, LSM303AGR_SAD_COMP,
LSM303AGR_AD_OUTX_L_REG_M, buff, LSM303AGR_AD_OUTX_L_REG_M, buff,
LSM303AGR_COMP_NUMBER_OF_AXES * 2); LSM303AGR_COMP_NUMBER_OF_AXES * 2);
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cReleaseBus(devp->config->i2cp); lsm303agrReleaseBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
if(msg == MSG_OK) if(msg == MSG_OK)
for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) {
@ -702,7 +777,7 @@ void lsm303agrObjectInit(LSM303AGRDriver *devp) {
*/ */
void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) { void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) {
uint32_t i; uint32_t i;
uint8_t cr[6]; uint8_t cr[4];
osalDbgCheck((devp != NULL) && (config != NULL)); osalDbgCheck((devp != NULL) && (config != NULL));
osalDbgAssert((devp->state == LSM303AGR_STOP) || osalDbgAssert((devp->state == LSM303AGR_STOP) ||
@ -713,36 +788,33 @@ void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) {
/* Configuring Accelerometer subsystem.*/ /* Configuring Accelerometer subsystem.*/
/* Multiple write starting address.*/
cr[0] = LSM303AGR_AD_CTRL_REG1_A;
/* Control register 1 configuration block.*/ /* Control register 1 configuration block.*/
{ {
cr[1] = LSM303AGR_ACC_AE_XYZ | devp->config->accoutdatarate; cr[0] = LSM303AGR_ACC_AE_XYZ | devp->config->accoutdatarate;
#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__)
if(devp->config->accmode == LSM303AGR_ACC_MODE_LPOW) if(devp->config->accmode == LSM303AGR_ACC_MODE_LPOW)
cr[1] |= LSM303AGR_CTRL_REG1_A_LPEN; cr[0] |= LSM303AGR_CTRL_REG1_A_LPEN;
#endif #endif
} }
/* Control register 2 configuration block.*/ /* Control register 2 configuration block.*/
{ {
cr[2] = 0; cr[1] = 0;
} }
/* Control register 3 configuration block.*/ /* Control register 3 configuration block.*/
{ {
cr[3] = 0; cr[2] = 0;
} }
/* Control register 4 configuration block.*/ /* Control register 4 configuration block.*/
{ {
cr[4] = devp->config->accfullscale; cr[3] = devp->config->accfullscale;
#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__)
cr[4] |= devp->config->accendianess | cr[3] |= devp->config->accendianess |
devp->config->accblockdataupdate; devp->config->accblockdataupdate;
if(devp->config->accmode == LSM303AGR_ACC_MODE_HRES) if(devp->config->accmode == LSM303AGR_ACC_MODE_HRES)
cr[4] |= LSM303AGR_CTRL_REG4_A_HR; cr[3] |= LSM303AGR_CTRL_REG4_A_HR;
#endif #endif
} }
@ -794,41 +866,40 @@ void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) {
for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++)
devp->accbias[i] = LSM303AGR_ACC_BIAS; devp->accbias[i] = LSM303AGR_ACC_BIAS;
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cAcquireBus((devp)->config->i2cp); lsm303agrAccureBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); lsm303agrStartBus(devp->config);
lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_ACC, cr, 4); lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_ACC,
LSM303AGR_AD_CTRL_REG1_A, cr, 4);
/* Configuring Compass subsystem */ /* Configuring Compass subsystem */
/* Multiple write starting address.*/
cr[0] = LSM303AGR_AD_CFG_REG_A_M;
/* Control register A configuration block.*/ /* Control register A configuration block.*/
{ {
cr[1] = devp->config->compoutputdatarate; cr[0] = devp->config->compoutputdatarate;
#if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__)
cr[1] |= devp->config->compmode | devp->config->complp; cr[0] |= devp->config->compmode | devp->config->complp;
#endif #endif
} }
/* Control register B configuration block.*/ /* Control register B configuration block.*/
{ {
cr[2] = 0; cr[1] = 0;
} }
/* Control register C configuration block.*/ /* Control register C configuration block.*/
{ {
cr[3] = 0; cr[2] = 0;
} }
lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_COMP, lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_COMP,
cr, 3); LSM303AGR_AD_CFG_REG_A_M, cr, 3);
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cReleaseBus((devp)->config->i2cp); lsm303agrReleaseBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
devp->compfullscale = LSM303AGR_COMP_50GA; devp->compfullscale = LSM303AGR_COMP_50GA;
for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) {
@ -854,7 +925,7 @@ void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) {
* @api * @api
*/ */
void lsm303agrStop(LSM303AGRDriver *devp) { void lsm303agrStop(LSM303AGRDriver *devp) {
uint8_t cr[2]; uint8_t cr[1];
osalDbgCheck(devp != NULL); osalDbgCheck(devp != NULL);
osalDbgAssert((devp->state == LSM303AGR_STOP) || osalDbgAssert((devp->state == LSM303AGR_STOP) ||
@ -862,27 +933,25 @@ void lsm303agrStop(LSM303AGRDriver *devp) {
"lsm303agrStop(), invalid state"); "lsm303agrStop(), invalid state");
if (devp->state == LSM303AGR_READY) { if (devp->state == LSM303AGR_READY) {
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cAcquireBus((devp)->config->i2cp); lsm303agrAccureBus(devp->config);
i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); lsm303agrStartBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
/* Disabling accelerometer. */ /* Disabling accelerometer. */
cr[0] = LSM303AGR_AD_CTRL_REG1_A; cr[0] = LSM303AGR_ACC_AE_DISABLED | LSM303AGR_ACC_ODR_PD;
cr[1] = LSM303AGR_ACC_AE_DISABLED | LSM303AGR_ACC_ODR_PD;
lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_ACC, lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_ACC,
cr, 1); LSM303AGR_AD_CTRL_REG1_A, cr, 1);
/* Disabling compass. */ /* Disabling compass. */
cr[0] = LSM303AGR_AD_CFG_REG_A_M; cr[0] = LSM303AGR_COMP_MODE_IDLE;
cr[1] = LSM303AGR_COMP_MODE_IDLE;
lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_COMP, lsm303agrWriteRegister(devp->config, LSM303AGR_SAD_COMP,
cr, 1); LSM303AGR_AD_CFG_REG_A_M, cr, 1);
i2cStop((devp)->config->i2cp); lsm303agrStopBus((devp)->config);
#if LSM303AGR_SHARED_I2C #if (LSM303AGR_SHARED_I2C == TRUE) || (LSM303AGR_SHARED_SPI == TRUE)
i2cReleaseBus((devp)->config->i2cp); lsm303agrReleaseBus(devp->config);
#endif /* LSM303AGR_SHARED_I2C */ #endif /* LSM303AGR_SHARED_I2C || LSM303AGR_SHARED_SPI */
} }
devp->state = LSM303AGR_STOP; devp->state = LSM303AGR_STOP;
} }

View File

@ -109,6 +109,10 @@
#define LSM303AGR_AD_MASK 0x7F #define LSM303AGR_AD_MASK 0x7F
#define LSM303AGR_AD(n) (1 << n) #define LSM303AGR_AD(n) (1 << n)
#define LSM303AGR_MS (1 << 7) #define LSM303AGR_MS (1 << 7)
#define LSM303AGR_SPI_AD_MASK (0x3f)
#define LSM303AGR_SPI_RD (1 << 7)
#define LSM303AGR_SPI_MS (1 << 6)
/** @} */ /** @} */
/** /**
@ -381,13 +385,6 @@
#error "LSM303AGR_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" #error "LSM303AGR_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
#endif #endif
/*
* CHTODO: Add support for LSM303AGR over SPI.
*/
#if LSM303AGR_USE_SPI
#error "LSM303AGR over SPI still not supported"
#endif
/*===========================================================================*/ /*===========================================================================*/
/* Driver data structures and types. */ /* Driver data structures and types. */
/*===========================================================================*/ /*===========================================================================*/
@ -516,6 +513,17 @@ typedef enum {
* @brief LSM303AGR configuration structure. * @brief LSM303AGR configuration structure.
*/ */
typedef struct { typedef struct {
#if (LSM303AGR_USE_SPI) || defined(__DOXYGEN__)
/**
* @brief SPI driver associated to this LSM303AGR.
*/
SPIDriver *spip;
/**
* @brief SPI configuration associated to this LSM303AGR.
*/
const SPIConfig *spicfg;
#endif /* LIS2DW12_USE_SPI */
#if (LSM303AGR_USE_I2C) || defined(__DOXYGEN__)
/** /**
* @brief I2C driver associated to this LSM303AGR. * @brief I2C driver associated to this LSM303AGR.
*/ */
@ -524,6 +532,7 @@ typedef struct {
* @brief I2C configuration associated to this LSM303AGR. * @brief I2C configuration associated to this LSM303AGR.
*/ */
const I2CConfig *i2ccfg; const I2CConfig *i2ccfg;
#endif /* LSM303AGR_USE_I2C */
/** /**
* @brief LSM303AGR accelerometer subsystem initial sensitivity. * @brief LSM303AGR accelerometer subsystem initial sensitivity.
*/ */