ChibiOS 21.11.4
adxl317.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2016..2023 Simona Di Domenico
3
4 This file is part of ChibiOS.
5
6 ChibiOS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 ChibiOS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21/**
22 * @file adxl317.c
23 * @brief ADXL317 MEMS interface module code.
24 *
25 * @addtogroup ADXL317
26 * @ingroup EX_ADI
27 * @{
28 */
29
30#include "hal.h"
31#include "adxl317.h"
32
33/*===========================================================================*/
34/* Driver local definitions. */
35/*===========================================================================*/
36
37/*===========================================================================*/
38/* Driver exported variables. */
39/*===========================================================================*/
40
41/*===========================================================================*/
42/* Driver local variables and types. */
43/*===========================================================================*/
44
45/*===========================================================================*/
46/* Driver local functions. */
47/*===========================================================================*/
48
49#if (ADXL317_USE_I2C) || defined(__DOXYGEN__)
50/**
51 * @brief Reads a generic register value using I2C.
52 * @pre The I2C interface must be initialized and the driver started.
53 *
54 * @param[in] devp pointer to @p ADXL317Driver interface.
55 * @param[in] reg starting register address
56 * @param[in] b pointer to an output buffer
57 * @param[in] n number of consecutive registers to read.
58 *
59 * @return The operation status.
60 * @retval MSG_OK if the function succeeded.
61 * @retval MSG_RESET if one or more errors occurred.
62 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
63 */
64static msg_t adxl317I2CReadRegister(ADXL317Driver *devp, uint8_t reg,
65 uint8_t *b, size_t n) {
66 msg_t ret = i2cMasterTransmitTimeout(devp->config->i2cp, ADXL317_SAD_GND,
67 &reg, 1, b, n, TIME_INFINITE);
68
69 return ret;
70}
71
72/**
73 * @brief Writes a value into a generic register using I2C.
74 * @pre The I2C interface must be initialized and the driver started.
75 *
76 * @param[in] devp pointer to @p ADXL317Driver interface.
77 * @param[in] reg starting register address
78 * @param[in] b pointer to a buffer of values
79 * @param[in] n number of adjacent registers to write.
80 *
81 * @return The operation status.
82 * @retval MSG_OK if the function succeeded.
83 * @retval MSG_RESET if one or more errors occurred.
84 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
85 */
87 uint8_t *b, size_t n) {
88 msg_t ret = MSG_OK;
89 uint8_t txbuf[ADXL317_MAX_BUFF_SIZE + 1];
90 uint8_t i;
91
92 if (n > ADXL317_MAX_BUFF_SIZE) {
94 }
95
96 txbuf [0] = reg;
97 for(i = 0; i < n; i++, b++) {
98 txbuf[i + 1] = *b;
99 }
100
101 ret = i2cMasterTransmitTimeout(devp->config->i2cp, ADXL317_SAD_GND,
102 txbuf, n + 1, NULL, 0, TIME_INFINITE);
103
104 return ret;
105}
106#endif /* ADXL317_USE_I2C*/
107
108/**
109 * @brief Return the number of axes of the BaseAccelerometer.
110 *
111 * @param[in] ip pointer to @p BaseAccelerometer interface.
112 *
113 * @return the number of axes.
114 */
115static size_t acc_get_axes_number(void *ip) {
116 (void)ip;
117
119}
120
121/**
122 * @brief Retrieves raw data from the BaseAccelerometer.
123 * @note This data is retrieved from MEMS register without any algebraical
124 * manipulation.
125 * @note The axes array must be at least the same size of the
126 * BaseAccelerometer axes number.
127 *
128 * @param[in] ip pointer to @p BaseAccelerometer interface.
129 * @param[out] axes a buffer which would be filled with raw data.
130 *
131 * @return The operation status.
132 * @retval MSG_OK if the function succeeded.
133 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
134 * be retrieved using @p i2cGetErrors().
135 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
136 */
137static msg_t acc_read_raw(void *ip, int32_t axes[]) {
138 ADXL317Driver* devp;
139 uint8_t buff [ADXL317_ACC_NUMBER_OF_AXES * 2], i;
140 int32_t tmp;
141 msg_t ret = MSG_OK;
142
143 osalDbgCheck((ip != NULL) && (axes != NULL));
144
145 /* Getting parent instance pointer.*/
147 osalDbgAssert((devp->state == ADXL317_READY),
148 "acc_read_raw(), invalid state");
149
150#if ADXL317_USE_I2C
153
154 if(ret == MSG_OK) {
155 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++) {
156 tmp = buff[2 * i] >>2 | (buff[2 * i + 1] << 6);
157 if(tmp & 0x2000) {
158 tmp |= 0xFFFFC000;
159 }
160 axes[i] = tmp;
161 }
162 }
163#endif /* ADXL317_USE_I2C*/
164
165 return ret;
166}
167
168/**
169 * @brief Retrieves cooked data from the BaseAccelerometer.
170 * @note This data is manipulated according to the formula
171 * cooked = (raw * sensitivity) - bias.
172 * @note Final data is expressed as milli-G.
173 * @note The axes array must be at least the same size of the
174 * BaseAccelerometer axes number.
175 *
176 * @param[in] ip pointer to @p BaseAccelerometer interface.
177 * @param[out] axes a buffer which would be filled with cooked data.
178 *
179 * @return The operation status.
180 * @retval MSG_OK if the function succeeded.
181 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
182 * be retrieved using @p i2cGetErrors().
183 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
184 */
185static msg_t acc_read_cooked(void *ip, float axes[]) {
186 ADXL317Driver* devp;
187 uint32_t i;
188 int32_t raw[ADXL317_ACC_NUMBER_OF_AXES];
189 msg_t ret = MSG_OK;
190
191 osalDbgCheck((ip != NULL) && (axes != NULL));
192
193 /* Getting parent instance pointer.*/
195
196 osalDbgAssert((devp->state == ADXL317_READY),
197 "acc_read_cooked(), invalid state");
198
199 ret = acc_read_raw(ip, raw);
200
201 if(ret == MSG_OK) {
202 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++) {
203 axes[i] = ((float)raw[i] * devp->accsensitivity[i]) - devp->accbias[i];
204 }
205 }
206
207 return ret;
208}
209
210/**
211 * @brief Set bias values for the BaseAccelerometer.
212 * @note Bias must be expressed as milli-G.
213 * @note The bias buffer must be at least the same size of the
214 * BaseAccelerometer axes number.
215 *
216 * @param[in] ip pointer to @p BaseAccelerometer interface.
217 * @param[in] bp a buffer which contains biases.
218 *
219 * @return The operation status.
220 * @retval MSG_OK if the function succeeded.
221 */
222static msg_t acc_set_bias(void *ip, float *bp) {
223 ADXL317Driver* devp;
224 uint32_t i;
225 msg_t ret = MSG_OK;
226
227 osalDbgCheck((ip != NULL) && (bp != NULL));
228
229 /* Getting parent instance pointer.*/
231
232 osalDbgAssert((devp->state == ADXL317_READY),
233 "acc_set_bias(), invalid state");
234
235 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++) {
236 devp->accbias[i] = bp[i];
237 }
238 return ret;
239}
240
241/**
242 * @brief Reset bias values for the BaseAccelerometer.
243 * @note Default biases value are obtained from device datasheet when
244 * available otherwise they are considered zero.
245 *
246 * @param[in] ip pointer to @p BaseAccelerometer interface.
247 *
248 * @return The operation status.
249 * @retval MSG_OK if the function succeeded.
250 */
251static msg_t acc_reset_bias(void *ip) {
252 ADXL317Driver* devp;
253 uint32_t i;
254 msg_t ret = MSG_OK;
255
256 osalDbgCheck(ip != NULL);
257
258 /* Getting parent instance pointer.*/
260
261 osalDbgAssert((devp->state == ADXL317_READY),
262 "acc_reset_bias(), invalid state");
263
264 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
265 devp->accbias[i] = ADXL317_ACC_BIAS;
266 return ret;
267}
268
269/**
270 * @brief Set sensitivity values for the BaseAccelerometer.
271 * @note Sensitivity must be expressed as milli-G/LSB.
272 * @note The sensitivity buffer must be at least the same size of the
273 * BaseAccelerometer axes number.
274 *
275 * @param[in] ip pointer to @p BaseAccelerometer interface.
276 * @param[in] sp a buffer which contains sensitivities.
277 *
278 * @return The operation status.
279 * @retval MSG_OK if the function succeeded.
280 */
281static msg_t acc_set_sensivity(void *ip, float *sp) {
282 ADXL317Driver* devp;
283 uint32_t i;
284 msg_t ret = MSG_OK;
285
286 /* Getting parent instance pointer.*/
288
289 osalDbgCheck((ip != NULL) && (sp != NULL));
290
291 osalDbgAssert((devp->state == ADXL317_READY),
292 "acc_set_sensivity(), invalid state");
293
294 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++) {
295 devp->accsensitivity[i] = sp[i];
296 }
297 return ret;
298}
299
300/**
301 * @brief Reset sensitivity values for the BaseAccelerometer.
302 * @note Default sensitivities value are obtained from device datasheet.
303 *
304 * @param[in] ip pointer to @p BaseAccelerometer interface.
305 *
306 * @return The operation status.
307 * @retval MSG_OK if the function succeeded.
308 * @retval MSG_RESET otherwise.
309 */
310static msg_t acc_reset_sensivity(void *ip) {
311 ADXL317Driver* devp;
312 uint32_t i;
313 msg_t ret = MSG_OK;
314
315 osalDbgCheck(ip != NULL);
316
317 /* Getting parent instance pointer.*/
319
320 osalDbgAssert((devp->state == ADXL317_READY),
321 "acc_reset_sensivity(), invalid state");
322
323 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
324 devp->accbias[i] = ADXL317_ACC_SENS;
325 return ret;
326}
327
328static const struct ADXL317VMT vmt_device = {
329 (size_t)0
330};
331
337
338/*===========================================================================*/
339/* Driver exported functions. */
340/*===========================================================================*/
341
342/**
343 * @brief Initializes an instance.
344 * @details The buffer should be at least large @p ADXL317_COMM_BUFF_SIZE.
345 * @note The communication buffer could be used by DMAs.
346 *
347 * @param[out] devp pointer to the @p ADXL317Driver object
348 * @param[in] txbp pointer to a buffer used as communication tx buffer
349 * @param[in] rxbp pointer to a buffer used as communication rx buffer
350 *
351 * @init
352 */
353void adxl317ObjectInit(ADXL317Driver *devp, uint8_t* txbp, uint8_t* rxbp) {
354 devp->vmt = &vmt_device;
356
357 devp->config = NULL;
358 devp->commtxp = txbp;
359 devp->commrxp = rxbp;
360
361 devp->accaxes = ADXL317_ACC_NUMBER_OF_AXES;
362
363 devp->state = ADXL317_STOP;
364}
365
366/**
367 * @brief Configures and activates ADXL317 Complex Driver peripheral.
368 *
369 * @param[in] devp pointer to the @p ADXL317Driver object
370 * @param[in] config pointer to the @p ADXL317Config object
371 *
372 * @api
373 */
375 msg_t ret = MSG_OK;
376 uint32_t i;
377 uint8_t reg_val;
378
379 osalDbgCheck((devp != NULL) && (config != NULL));
380
381 osalDbgAssert((devp->state == ADXL317_STOP) ||
382 (devp->state == ADXL317_READY),
383 "adxl317Start(), invalid state");
384
385 devp->config = config;
386
387 /* Starting the I2C driver.*/
388 i2cStart(devp->config->i2cp, devp->config->i2ccfg);
389
390 /* Checking the device ID.*/
391 ret = adxl317I2CReadRegister(devp, ADXL317_AD_DEVID_0, &reg_val, 1);
392 osalDbgAssert((reg_val == ADXL317_DEVID_0), "Invalid MEMS ID");
393
394 /* Enabling the write on the ADXL317 registers.*/
395 if(ret == MSG_OK) {
396 reg_val = ADXL317_USER_REG_KEY_0;
397 ret = adxl317I2CWriteRegister(devp, ADXL317_AD_USER_REG_KEY, &reg_val, 1);
398 }
399
400 if(ret == MSG_OK) {
401 reg_val = ADXL317_USER_REG_KEY_1;
402 ret = adxl317I2CWriteRegister(devp, ADXL317_AD_USER_REG_KEY, &reg_val, 1);
403 }
404
405 /* Filter register configuration block.*/
406 if(ret == MSG_OK) {
407 /* Filter register configuration for X axis.*/
408 reg_val = ADXL317_DEFAULT_FILTER;
409#if ADXL317_USE_ADVANCED || defined(__DOXYGEN__)
410 reg_val = devp->config->acclowpass.x | devp->config->acchighpass.x;
411#endif
412#if ADXL317_USE_I2C
413 ret = adxl317I2CWriteRegister(devp, ADXL317_AD_X_FILT, &reg_val, 1);
414#endif /* ADXL317_USE_ADVANCED*/
415 }
416
417 if(ret == MSG_OK) {
418 /* Filter register configuration for Y axis.*/
419 reg_val = ADXL317_DEFAULT_FILTER;
420#if ADXL317_USE_ADVANCED || defined(__DOXYGEN__)
421 reg_val = devp->config->acclowpass.y | devp->config->acchighpass.y;
422#endif
423#if ADXL317_USE_I2C
424 ret = adxl317I2CWriteRegister(devp, ADXL317_AD_Y_FILT, &reg_val, 1);
425#endif /* ADXL317_USE_ADVANCED*/
426 }
427
428 if(ret == MSG_OK) {
429 /* Filter register configuration for Z axis.*/
430 reg_val = ADXL317_DEFAULT_FILTER;
431#if ADXL317_USE_ADVANCED || defined(__DOXYGEN__)
432 reg_val = devp->config->acclowpass.z | devp->config->acchighpass.z;
433#endif
434#if ADXL317_USE_I2C
435 ret = adxl317I2CWriteRegister(devp, ADXL317_AD_Z_FILT, &reg_val, 1);
436#endif /* ADXL317_USE_ADVANCED*/
437 }
438
439 if(ret == MSG_OK) {
440 /* Storing sensitivity information according to user setting*/
441 if(devp->config->accsensitivity != NULL)
442 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
443 devp->accsensitivity[i] = devp->config->accsensitivity[i];
444 else
445 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
446 devp->accsensitivity[i] = ADXL317_ACC_SENS;
447
448 /* Storing bias information according to user setting*/
449 if(devp->config->accbias != NULL)
450 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
451 devp->accbias[i] = devp->config->accbias[i];
452 else
453 for(i = 0; i < ADXL317_ACC_NUMBER_OF_AXES; i++)
454 devp->accbias[i] = ADXL317_ACC_BIAS;
455
456 /* This is the Accelerometer transient recovery time*/
458
459 devp->state = ADXL317_READY;
460 }
461 else {
462 devp->state = ADXL317_STOP;
463 }
464 return ret;
465}
466
467/**
468 * @brief Deactivates the ADXL317 Complex Driver peripheral.
469 *
470 * @param[in] devp pointer to the @p ADXL317Driver object
471 *
472 * @api
473 */
475 osalDbgCheck(devp != NULL);
476
477 osalDbgAssert((devp->state == ADXL317_STOP) ||
478 (devp->state == ADXL317_READY),
479 "adxl317Stop(), invalid state");
480
481 if (devp->state == ADXL317_READY) {
482#if (ADXL317_USE_I2C)
483 /* Stopping the I2C driver.*/
484 i2cStop(devp->config->i2cp);
485#endif /* ADXL317_USE_I2C*/
486 }
487 devp->state = ADXL317_STOP;
488}
489/** @} */
ADXL317 MEMS interface module header.
#define ADXL317_USER_REG_KEY_0
Definition adxl317.h:115
static msg_t adxl317I2CWriteRegister(ADXL317Driver *devp, uint8_t reg, uint8_t *b, size_t n)
Writes a value into a generic register using I2C.
Definition adxl317.c:86
static size_t acc_get_axes_number(void *ip)
Return the number of axes of the BaseAccelerometer.
Definition adxl317.c:115
static msg_t acc_reset_sensivity(void *ip)
Reset sensitivity values for the BaseAccelerometer.
Definition adxl317.c:310
static msg_t acc_set_bias(void *ip, float *bp)
Set bias values for the BaseAccelerometer.
Definition adxl317.c:222
#define ADXL317_MAX_BUFF_SIZE
ADXL317 internal maximum communication buffer sizes.
Definition adxl317.h:201
#define ADXL317_AD_USER_REG_KEY
Definition adxl317.h:86
#define ADXL317_ACC_SENS
Definition adxl317.h:75
#define ADXL317_AD_X_DATA_LO
Definition adxl317.h:96
static msg_t acc_reset_bias(void *ip)
Reset bias values for the BaseAccelerometer.
Definition adxl317.c:251
static msg_t acc_set_sensivity(void *ip, float *sp)
Set sensitivity values for the BaseAccelerometer.
Definition adxl317.c:281
static msg_t acc_read_cooked(void *ip, float axes[])
Retrieves cooked data from the BaseAccelerometer.
Definition adxl317.c:185
void adxl317ObjectInit(ADXL317Driver *devp, uint8_t *txbp, uint8_t *rxbp)
Initializes an instance.
Definition adxl317.c:353
#define ADXL317_DEFAULT_FILTER
Definition adxl317.h:125
void adxl317Stop(ADXL317Driver *devp)
Deactivates the ADXL317 Complex Driver peripheral.
Definition adxl317.c:474
static msg_t acc_read_raw(void *ip, int32_t axes[])
Retrieves raw data from the BaseAccelerometer.
Definition adxl317.c:137
#define ADXL317_ACC_BIAS
Definition adxl317.h:76
#define ADXL317_ACC_NUMBER_OF_AXES
ADXL317 accelerometer subsystem characteristics.
Definition adxl317.h:72
#define ADXL317_DEVID_0
Definition adxl317.h:108
static msg_t adxl317I2CReadRegister(ADXL317Driver *devp, uint8_t reg, uint8_t *b, size_t n)
Reads a generic register value using I2C.
Definition adxl317.c:64
#define ADXL317_AD_Y_FILT
Definition adxl317.h:93
msg_t adxl317Start(ADXL317Driver *devp, const ADXL317Config *config)
Configures and activates ADXL317 Complex Driver peripheral.
Definition adxl317.c:374
#define ADXL317_AD_X_FILT
Definition adxl317.h:91
static const struct BaseAccelerometerVMT vmt_accelerometer
Definition adxl317.c:332
#define ADXL317_AD_Z_FILT
Definition adxl317.h:95
#define ADXL317_AD_DEVID_0
Definition adxl317.h:84
static const struct ADXL317VMT vmt_device
Definition adxl317.c:328
#define ADXL317_USER_REG_KEY_1
Definition adxl317.h:116
@ ADXL317_STOP
Definition adxl317.h:243
@ ADXL317_READY
Definition adxl317.h:244
@ ADXL317_SAD_GND
Definition adxl317.h:234
#define objGetInstance(type, ip)
Returns the instance pointer starting from an interface pointer.
Definition hal_objects.h:78
msg_t i2cStart(I2CDriver *i2cp, const I2CConfig *config)
Configures and activates the I2C peripheral.
Definition hal_i2c.c:94
msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout)
Sends data via the I2C bus.
Definition hal_i2c.c:187
void i2cStop(I2CDriver *i2cp)
Deactivates the I2C peripheral.
Definition hal_i2c.c:131
#define osalDbgAssert(c, remark)
Condition assertion.
Definition osal.h:264
#define osalDbgCheck(c)
Function parameters check.
Definition osal.h:284
#define osalThreadSleepMilliseconds(msecs)
Delays the invoking thread for the specified number of milliseconds.
Definition osal.h:522
int32_t msg_t
Definition chearly.h:88
#define MSG_OK
Normal wakeup message.
Definition chschd.h:39
#define TIME_INFINITE
Infinite interval specification for all functions with a timeout specification.
Definition chtime.h:55
HAL subsystem header.
ADXL317 configuration structure.
Definition adxl317.h:343
ADXL317 3-axis accelerometer class.
Definition adxl317.h:422
const struct ADXL317VMT * vmt
Virtual Methods Table.
Definition adxl317.h:424
BaseAccelerometer acc_if
Base accelerometer interface.
Definition adxl317.h:426
ADXL317 virtual methods table.
Definition adxl317.h:393
Base accelerometer class.
const struct BaseAccelerometerVMT * vmt
Virtual Methods Table.
BaseAccelerometer virtual methods table.