aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/ex/devices
diff options
context:
space:
mode:
authorAkshay <[email protected]>2022-04-10 12:13:40 +0100
committerAkshay <[email protected]>2022-04-10 12:13:40 +0100
commitdc90387ce7d8ba7b607d9c48540bf6d8b560f14d (patch)
tree4ccb8fa5886b66fa9d480edef74236c27f035e16 /lib/chibios/os/ex/devices
Diffstat (limited to 'lib/chibios/os/ex/devices')
-rw-r--r--lib/chibios/os/ex/devices/Bosch/bmp085.c788
-rw-r--r--lib/chibios/os/ex/devices/Bosch/bmp085.h403
-rw-r--r--lib/chibios/os/ex/devices/Bosch/bmp085.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/hts221.c781
-rw-r--r--lib/chibios/os/ex/devices/ST/hts221.h707
-rw-r--r--lib/chibios/os/ex/devices/ST/hts221.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/l3gd20.c642
-rw-r--r--lib/chibios/os/ex/devices/ST/l3gd20.h725
-rw-r--r--lib/chibios/os/ex/devices/ST/l3gd20.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lis302dl.c554
-rw-r--r--lib/chibios/os/ex/devices/ST/lis302dl.h566
-rw-r--r--lib/chibios/os/ex/devices/ST/lis302dl.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3dsh.c641
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3dsh.h708
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3dsh.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3mdl.c627
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3mdl.h670
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3mdl.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lps22hb.c686
-rw-r--r--lib/chibios/os/ex/devices/ST/lps22hb.h724
-rw-r--r--lib/chibios/os/ex/devices/ST/lps22hb.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lps25h.c696
-rw-r--r--lib/chibios/os/ex/devices/ST/lps25h.h740
-rw-r--r--lib/chibios/os/ex/devices/ST/lps25h.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303agr.c906
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303agr.h921
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303agr.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303dlhc.c1175
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303dlhc.h958
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm303dlhc.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6ds0.c1109
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6ds0.h1034
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6ds0.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6dsl.c1119
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6dsl.h1055
-rw-r--r--lib/chibios/os/ex/devices/ST/lsm6dsl.mk10
-rw-r--r--lib/chibios/os/ex/devices/ST/vl53l0x.h443
-rw-r--r--lib/chibios/os/ex/devices/ST/vl53l0x.mk10
38 files changed, 19508 insertions, 0 deletions
diff --git a/lib/chibios/os/ex/devices/Bosch/bmp085.c b/lib/chibios/os/ex/devices/Bosch/bmp085.c
new file mode 100644
index 000000000..61f6d1374
--- /dev/null
+++ b/lib/chibios/os/ex/devices/Bosch/bmp085.c
@@ -0,0 +1,788 @@
1/*
2 ChibiOS - Copyright (C) 2016..2017 Theodore Ateba
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 bmp085.c
23 * @brief BMP085 Digital pressure sensor interface module code.
24 *
25 * @addtogroup BMP085
26 * @ingroup EX_BOSCH
27 * @{
28 */
29
30#include "hal.h"
31#include "bmp085.h"
32
33/*==========================================================================*/
34/* Driver local definitions. */
35/*==========================================================================*/
36
37#define BMP085_SAD 0x77
38
39#define BMP085_CR_P_VAL0 0x34
40#define BMP085_CR_P_VAL1 0x74
41#define BMP085_CR_P_VAL2 0xB4
42#define BMP085_CR_P_VAL3 0xF4
43
44#define BMP085_CR_T_VAL 0x2E
45
46/*==========================================================================*/
47/* Driver exported variables. */
48/*==========================================================================*/
49
50/*==========================================================================*/
51/* Driver local variables and types. */
52/*==========================================================================*/
53
54/*==========================================================================*/
55/* Driver local functions. */
56/*==========================================================================*/
57
58#if (BMP085_USE_I2C) || defined(__DOXYGEN__)
59/**
60 * @brief Reads registers value using I2C.
61 * @pre The I2C interface must be initialized and the driver started.
62 *
63 * @param[in] i2cp pointer to the I2C interface
64 * @param[in] reg first sub-register address
65 * @param[out] rxbufp pointer to an output buffer
66 * @param[in] n number of consecutive register to read
67 *
68 * @return the operation status
69 * @notapi
70 */
71msg_t bmp085I2CReadRegister(I2CDriver *i2cp, uint8_t reg, uint8_t *rxbufp,
72 size_t n) {
73 uint8_t txbuf = reg;
74
75 return i2cMasterTransmitTimeout(i2cp, BMP085_SAD, &txbuf, 1, rxbufp, n,
76 TIME_INFINITE);
77}
78
79/**
80 * @brief Writes a value into a register using I2C.
81 * @pre The I2C interface must be initialized and the driver started.
82 *
83 * @param[in] i2cp pointer to the I2C interface
84 * @param[in] txbufp buffer containing sub-address value in first position
85 * and values to write
86 * @param[in] n size of txbuf less one (not considering the first
87 * element)
88 *
89 * @return the operation status
90 * @notapi
91 */
92msg_t bmp085I2CWriteRegister(I2CDriver *i2cp, uint8_t *txbufp, size_t n) {
93
94 return i2cMasterTransmitTimeout(i2cp, BMP085_SAD, txbufp, n + 1, NULL, 0,
95 TIME_INFINITE);
96}
97#endif /* BMP085_USE_I2C */
98
99/**
100 * @brief Read all the calibration data from the BMP085 EEPROM.
101 * @pre The I2C interface must be initialized and the driver started.
102 *
103 * @param[in] devp pointer to the BMP085 device driver sensor
104 * @param[in] reg first calibration coefficient register to read
105 *
106 * @return msg the operation status
107 */
108static msg_t bmp085ReadCoefficient(BMP085Driver *devp, uint8_t reg) {
109
110 uint8_t rxbuf[22];
111
112#if BMP085_SHARED_I2C
113 i2cAcquireBus(devp->config->i2cp);
114#endif /* BMP085_SHARED_I2C */
115
116 msg_t msg = bmp085I2CReadRegister(devp->config->i2cp, reg, rxbuf, 22);
117
118#if BMP085_SHARED_I2C
119 i2cReleaseBus(devp->config->i2cp);
120#endif /* BMP085_SHARED_I2C */
121
122 if (msg == MSG_OK) {
123 devp->calibrationdata.ac1 = ((rxbuf[ 0] << 8) | rxbuf[ 1]);
124 devp->calibrationdata.ac2 = ((rxbuf[ 2] << 8) | rxbuf[ 3]);
125 devp->calibrationdata.ac3 = ((rxbuf[ 4] << 8) | rxbuf[ 5]);
126 devp->calibrationdata.ac4 = ((rxbuf[ 6] << 8) | rxbuf[ 7]);
127 devp->calibrationdata.ac5 = ((rxbuf[ 8] << 8) | rxbuf[ 9]);
128 devp->calibrationdata.ac6 = ((rxbuf[10] << 8) | rxbuf[11]);
129 devp->calibrationdata.b1 = ((rxbuf[12] << 8) | rxbuf[13]);
130 devp->calibrationdata.b2 = ((rxbuf[14] << 8) | rxbuf[15]);
131 devp->calibrationdata.mb = ((rxbuf[16] << 8) | rxbuf[17]);
132 devp->calibrationdata.mc = ((rxbuf[18] << 8) | rxbuf[19]);
133 devp->calibrationdata.md = ((rxbuf[20] << 8) | rxbuf[21]);
134 }
135
136 return msg;
137}
138
139/**
140 * @brief Calcul the true temperature.
141 *
142 * @param[in] devp pointer to the BMP085 device driver sensor
143 * @param[in] ut uncompensated temperature
144 * @param[out] ctp pointer of the compensated temperature
145 */
146static void calcul_t(BMP085Driver *devp, int32_t ut, float *ctp) {
147
148 int32_t x1, x2;
149
150 /* Converting the temperature value. */
151 x1 = ((ut - devp->calibrationdata.ac6) * devp->calibrationdata.ac5) >> 15;
152 x2 = (devp->calibrationdata.mc << 11) / (x1 + devp->calibrationdata.md);
153 devp->calibrationdata.b5 = x1 + x2;
154 *ctp = (float)((devp->calibrationdata.b5 + 8) >> 4)*BMP085_T_RES;
155}
156
157/**
158 * @brief Calcul the true pressure.
159 *
160 * @param[in] devp pointer to the BMP085 device driver sensor
161 * @param[in] up uncompensated pressure
162 * @param[in] oss over sampling setting
163 * @param[out] cpp pointer of the compensated pressure
164 */
165static void calcul_p(BMP085Driver *devp, int32_t up, uint8_t oss, float *cpp) {
166
167 int32_t press;
168 int32_t x1,x2,x3;
169 int32_t b3,b6;
170 uint32_t b4,b7;
171
172 /* Converting the pressure value. */
173 b6 = devp->calibrationdata.b5 - 4000;
174 x1 = (devp->calibrationdata.b2 * ((b6 * b6) >> 12)) >> 11;
175 x2 = (devp->calibrationdata.ac2 * b6) >> 11;
176 x3 = x1 + x2;
177 b3 = ((((int32_t)devp->calibrationdata.ac1 * 4 + x3) << oss) + 2) >> 2;
178 x1 = ((devp->calibrationdata.ac3)*b6) >> 13;
179 x2 = (devp->calibrationdata.b1 * (b6*b6 >> 12)) >> 16;
180 x3 = ((x1 + x2) + 2) >> 2;
181 b4 = devp->calibrationdata.ac4 * (uint32_t)(x3 + 32768) >> 15;
182 b7 = ((uint32_t)up - b3)*(50000 >> oss);
183
184 if (b7 < 0x80000000)
185 press = (b7*2)/b4;
186 else
187 press = (b7/b4)*2;
188
189 x1 = (press >> 8)*(press >> 8);
190 x1 = (x1*3038) >> 16;
191 x2 = (-7357*press) >> 16;
192 *cpp =(float)((press + ((x1 + x2 + 3791) >> 4))*BMP085_P_RES);
193}
194
195/**
196 * @brief Start temperature measurement.
197 *
198 * @param[in] devp pointer to the BMP085 device driver
199 *
200 * @return the operation status
201 */
202static msg_t start_t_measurement(BMP085Driver *devp) {
203
204 uint8_t txbuf[2] = {BMP085_AD_CR, BMP085_CR_T_VAL};
205
206 i2cAcquireBus(devp->config->i2cp);
207 msg_t msg = bmp085I2CWriteRegister(devp->config->i2cp, txbuf, 2);
208 i2cReleaseBus(devp->config->i2cp);
209
210 /* Conversion time for the temperature. */
211 chThdSleepMilliseconds(BMP085_THERMO_CT_LOW);
212 //chThdSleepMilliseconds(devp->config.tct); // TODO: use this instead of the top line:
213
214 return msg;
215}
216
217/**
218 * @brief Start the pressure measurment.
219 *
220 * @param[in] devp pointer to the BMP085 driver
221 * @return msg the operation status
222 */
223static msg_t start_p_measurement(BMP085Driver *devp) {
224
225 uint8_t oss, delay;
226 uint8_t txbuf[2];
227
228 oss = devp->config->oss;
229 txbuf[0] = BMP085_AD_CR;
230
231 /* Check the oss according the bmp085 mode. */
232 if (oss == BMP085_BARO_OSS_0) {
233 txbuf[1] = BMP085_CR_P_VAL0 + (oss << 6);
234 delay = BMP085_BARO_CT_LOW;
235 }
236 else if (oss == BMP085_BARO_OSS_1) {
237 txbuf[1] = BMP085_CR_P_VAL1 + (oss << 6);
238 delay = BMP085_BARO_CT_STD;
239 }
240 else if (oss == BMP085_BARO_OSS_2) {
241 txbuf[1] = BMP085_CR_P_VAL2 + (oss << 6);
242 delay = BMP085_BARO_CT_HR;
243 }
244 else {
245 txbuf[1] = BMP085_CR_P_VAL3 + (oss << 6);
246 delay = BMP085_BARO_CT_LUHR;
247 }
248
249 /* Start the sensor for sampling. */
250#if BMP085_SHARED_I2C
251 i2cAcquireBus(devp->config->i2cp);
252#endif /* BMP085_SHARED_I2C */
253
254 msg_t msg = bmp085I2CWriteRegister(devp->config->i2cp, txbuf, 2);
255
256#if BMP085_SHARED_I2C
257 i2cReleaseBus(devp->config->i2cp);
258#endif /* BMP085_SHARED_I2C */
259
260 /* Conversion time for the pressure, max time for the moment. */
261 chThdSleepMilliseconds(delay);
262
263 return msg;
264}
265
266/**
267 * @brief Read the uncompensated temperature from the BMP085 register.
268 *
269 * @param[in] devp pointer to the BMP085 driver
270 * @param[out] utemp uncompensated temperature read from the sensor register
271 *
272 * @return msg the operation status
273 */
274static msg_t acquire_ut(BMP085Driver *devp, int32_t *utemp) {
275
276 uint8_t rxbuf[2];
277 msg_t msg;
278
279 /* Start the temperature measurement. */
280 start_t_measurement(devp);
281
282 /* Start the sensor for sampling. */
283#if BMP085_SHARED_I2C
284 i2cAcquireBus(devp->config->i2cp);
285#endif /* BMP085_SHARED_I2C */
286
287 /* Get the temperature. */
288 msg = bmp085I2CReadRegister(devp->config->i2cp, BMP085_AD_T_DR_MSB, rxbuf,
289 2);
290
291#if BMP085_SHARED_I2C
292 i2cReleaseBus(devp->config->i2cp);
293#endif /* BMP085_SHARED_I2C */
294
295 if(msg == MSG_OK){
296 /* Building the uncompensated temperature value. */
297 *utemp = (int32_t)((rxbuf[0] << 8) | rxbuf[1]);
298 }
299
300 return msg;
301}
302
303/**
304 * @brief Read the uncompensated pressure from the BMP085 register.
305 *
306 * @param[in] devp pointer to the BMP085 driver
307 * @param[out] upress uncompensated pressure read from the sensor register
308 *
309 * @return msg the operation status
310 */
311static msg_t acquire_up(BMP085Driver *devp, int32_t *upress) {
312
313 uint8_t rxbuf[3];
314 uint8_t oss;
315 msg_t msg;
316
317 /* Get the oversampling setting from the driver configuratioin. */
318 oss = devp->config->oss;
319
320 /* Start the pressure measurement. */
321 start_p_measurement(devp);
322
323 /* Start the sensor for sampling. */
324#if BMP085_SHARED_I2C
325 i2cAcquireBus(devp->config->i2cp);
326#endif /* BMP085_SHARED_I2C */
327
328 /* Get the pressure */
329 msg = bmp085I2CReadRegister(devp->config->i2cp, BMP085_AD_P_DR_MSB, rxbuf,
330 3);
331
332#if BMP085_SHARED_I2C
333 i2cReleaseBus(devp->config->i2cp);
334#endif /* BMP085_SHARED_I2C */
335
336 if (msg == MSG_OK) {
337 /* Building the uncompensated pressure value. */
338 *upress = (int32_t)((rxbuf[0] << 16)|(rxbuf[1] << 8)|rxbuf[2]);
339 *upress = *upress >> (8-oss);
340 }
341
342 return msg;
343}
344
345/*==========================================================================*/
346/* Interface implementation. */
347/*==========================================================================*/
348
349/**
350 * @brief Get the barometer number of axes.
351 *
352 * @param[in] ip interface pointer of the BMP085 sensor
353 *
354 * @return barometer number of axes
355 */
356static size_t baro_get_axes_number(void *ip) {
357
358 osalDbgCheck(ip != NULL);
359
360 return BMP085_BARO_NUMBER_OF_AXES;
361}
362
363/**
364 * @brief Get the thermometer number of axes.
365 *
366 * @param[in] ip interface pointer of the BMP085 sensor
367 *
368 * @return thermometer number of axes
369 */
370static size_t thermo_get_axes_number(void *ip) {
371
372 osalDbgCheck(ip != NULL);
373
374 return BMP085_THERMO_NUMBER_OF_AXES;
375}
376
377/**
378 * @brief Get the sensor number of axes.
379 *
380 * @param[in] ip interface pointer of the BMP085 sensor
381 *
382 * @return sensor number of axes
383 */
384static size_t sens_get_axes_number(void *ip) {
385
386 osalDbgCheck(ip != NULL);
387
388 return (baro_get_axes_number(ip) + thermo_get_axes_number(ip));
389}
390
391/**
392 * @brief Read baromether raw data.
393 *
394 * @param[in] ip interface pointer of the sensor
395 * @param[in] axes buffer for various axes data
396 *
397 * @return msg the result of the reading operation
398 */
399static msg_t baro_read_raw(void *ip, int32_t axes[]) {
400
401 osalDbgCheck((ip != NULL) && (axes != NULL));
402 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
403 "baro_read_raw(), invalid state");
404
405#if BMP085_USE_I2C
406 osalDbgAssert((((BMP085Driver *)ip)->config->i2cp->state == I2C_READY),
407 "baro_read_raw(), channel not ready");
408#if BMP085_SHARED_I2C
409 i2cAcquireBus(((BMP085Driver *)ip)->config->i2cp);
410 i2cStart(((BMP085Driver *)ip)->config->i2cp,
411 ((BMP085Driver *)ip)->config->i2ccfg);
412#endif /* BMP085_SHARED_I2C. */
413
414 /* Measure the uncompensated pressure. */
415 msg_t msg = acquire_up(((BMP085Driver *)ip), axes);
416
417#if BMP085_SHARED_I2C
418 i2cReleaseBus(((BMP085Driver *)ip)->config->i2cp);
419#endif /* BMP085_SHARED_I2C. */
420#endif /* BMP085_USE_I2C. */
421
422 return msg;
423}
424
425/**
426 * @brief Read thermometer raw data.
427 *
428 * @param[in] ip interface pointer of the BMP085 sensor
429 * @param[in] axes buffer for various axes data
430 *
431 * @return msg the result of the reading operation
432 */
433static msg_t thermo_read_raw(void *ip, int32_t axes[]) {
434
435 osalDbgCheck((ip != NULL) && (axes != NULL));
436 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
437 "thermo_read_raw(), invalid state");
438
439#if BMP085_USE_I2C
440 osalDbgAssert((((BMP085Driver *)ip)->config->i2cp->state == I2C_READY),
441 "thermo_read_raw(), channel not ready");
442#if BMP085_SHARED_I2C
443 i2cAcquireBus(((BMP085Driver *)ip)->config->i2cp);
444 i2cStart(((BMP085Driver *)ip)->config->i2cp,
445 ((BMP085Driver *)ip)->config->i2ccfg);
446#endif /* BMP085_SHARED_I2C. */
447
448 /* Measure the uncompensated temperature. */
449 msg_t msg = acquire_ut(((BMP085Driver *)ip), axes);
450
451#if BMP085_SHARED_I2C
452 i2cReleaseBus(((LSM303DLHCDriver *)ip)->config->i2cp);
453#endif /* BMP085_SHARED_I2C. */
454#endif /* BMP085_USE_I2C. */
455
456 return msg;
457}
458
459/**
460 * @brief Read BMP085 sensor raw data.
461 *
462 * @param[in] ip interface pointer of the BMP085 sensor
463 * @param[in] axes buffer for various axes data
464 *
465 * @return msg the result of the reading operation
466 */
467static msg_t sens_read_raw(void *ip, int32_t axes[]) {
468
469 int32_t* bp = axes;
470 msg_t msg;
471
472 msg = baro_read_raw(ip, bp);
473
474 if (msg != MSG_OK)
475 return msg;
476
477 bp += BMP085_BARO_NUMBER_OF_AXES;
478
479 msg = thermo_read_raw(ip, bp);
480
481 return msg;
482}
483
484/**
485 * @brief Read barometer cooked data.
486 *
487 * @param[in] ip interface pointer of the BMP085 sensor
488 * @param[in] axes buffer for various axes data
489 *
490 * @return msg the result of the reading operation
491 */
492static msg_t baro_read_cooked(void *ip, float axes[]) {
493
494 uint32_t i;
495 int32_t raw[BMP085_BARO_NUMBER_OF_AXES];
496 msg_t msg;
497 uint8_t oss;
498
499 osalDbgCheck((ip != NULL) && (axes != NULL));
500 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
501 "baro_read_cooked(), invalid state");
502
503 msg = baro_read_raw(ip, raw);
504 oss = ((BMP085Driver *)ip)->config->oss;
505
506 for (i = 0; i < BMP085_BARO_NUMBER_OF_AXES; i++)
507 calcul_p(ip, raw[i], oss, &axes[i]);
508
509 return msg;
510}
511
512/**
513 * @brief Read thermometer cooked data.
514 *
515 * @param[in] ip interface pointer of the BMP085 sensor
516 * @param[in] axes buffer for various axes data
517 *
518 * @return msg the result of the reading operation
519 */
520static msg_t thermo_read_cooked(void *ip, float axes[]) {
521
522 uint32_t i;
523 int32_t raw[BMP085_THERMO_NUMBER_OF_AXES];
524 msg_t msg;
525
526 osalDbgCheck(((ip != NULL) && (axes != NULL)));
527 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
528 "thermo_read_cooked(), invalid state");
529 msg = thermo_read_raw(ip, raw);
530
531 for (i = 0; i < BMP085_THERMO_NUMBER_OF_AXES; i++)
532 calcul_t(ip, raw[i], &axes[i]);
533
534 return msg;
535}
536
537/**
538 * @brief Read BMP085 sensor cooked data.
539 *
540 * @param[in] ip interface pointer of the BMP085 sensor
541 * @param[in] axes buffer for various axes data
542 *
543 * @return msg the result of the reading operation
544 */
545static msg_t sens_read_cooked(void *ip, float axes[]) {
546
547 float* bp = axes;
548 msg_t msg;
549
550 msg = baro_read_cooked(ip, bp);
551
552 if (msg != MSG_OK)
553 return msg;
554
555 bp += BMP085_BARO_NUMBER_OF_AXES;
556 msg = thermo_read_cooked(ip, bp);
557
558 return msg;
559}
560
561/**
562 * @brief Set the barometer bias.
563 *
564 * @param[in] ip interface pointer of the BMP085 sensor
565 * @param[in] bp pointer to the bias value
566 *
567 * @return msg the result of the setting operation
568 */
569static msg_t baro_set_bias(void *ip, float *bp) {
570
571 osalDbgCheck((ip != NULL) && (bp !=NULL));
572 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) ||
573 (((BMP085Driver *)ip)->state == BMP085_STOP),
574 "baro_set_bias(), invalid state");
575 return MSG_OK;
576}
577
578/**
579 * @brief Set the thermometer bias.
580 *
581 * @param[in] ip interface pointer of the BMP085 sensor
582 * @param[in] bp pointer to the bias value
583 *
584 * @return msg the result of the setting operation
585 */
586static msg_t thermo_set_bias(void *ip, float *bp) {
587
588 osalDbgCheck((ip != NULL) && (bp !=NULL));
589 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) ||
590 (((BMP085Driver *)ip)->state == BMP085_STOP),
591 "thermo_set_bias(), invalid state");
592 return MSG_OK;
593}
594
595/**
596 * @brief Reset the barometer bias.
597 *
598 * @param[in] ip interface pointer of the BMP085 sensor
599 *
600 * @return msg the result of the reset operation
601 */
602static msg_t baro_reset_bias(void *ip) {
603
604 osalDbgCheck(ip != NULL);
605 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) ||
606 (((BMP085Driver *)ip)->state == BMP085_STOP),
607 "baro_reset_bias(), invalid state");
608
609 return MSG_OK;
610}
611
612/**
613 * @brief Reset the thermometer bias.
614 *
615 * @param[in] ip interface pointer of the BMP085 sensor
616 *
617 * @return msg the result of the reset operation
618 */
619static msg_t thermo_reset_bias(void *ip) {
620
621 osalDbgCheck(ip != NULL);
622 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY) ||
623 (((BMP085Driver *)ip)->state == BMP085_STOP),
624 "thermo_reset_bias(), invalid state");
625
626 return MSG_OK;
627}
628
629/**
630 * @brief Set the barometer sensivity.
631 *
632 * @param[in] ip interface pointer of the BMP085 sensor
633 * @param[in] sp pointer to the sensivity value
634 *
635 * @return msg the result of the setting operation
636 */
637static msg_t baro_set_sensivity(void *ip, float *sp) {
638
639 osalDbgCheck((ip != NULL) && (sp !=NULL));
640 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
641 "baro_set_sensivity(), invalid state");
642
643 return MSG_OK;
644}
645
646/**
647 * @brief Set the thermometer sensivity.
648 *
649 * @param[in] ip interface pointer of the BMP085 sensor
650 * @param[in] sp pointer to the sensivity value
651 *
652 * @return msg the result of the setting operation
653 */
654static msg_t thermo_set_sensivity(void *ip, float *sp) {
655
656 osalDbgCheck((ip != NULL) && (sp !=NULL));
657 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
658 "thermo_set_sensivity(), invalid state");
659
660 return MSG_OK;
661}
662
663/**
664 * @brief Reset the barometer sensivity.
665 *
666 * @param[in] ip interface pointer of the BMP085 sensor
667 *
668 * @return msg the result of the reset operation
669 */
670static msg_t baro_reset_sensivity(void *ip) {
671
672 osalDbgCheck(ip != NULL);
673 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
674 "baro_reset_sensivity(), invalid state");
675
676 return MSG_OK;
677}
678
679/**
680 * @brief Reset the thermometer sensivity.
681 *
682 * @param[in] ip interface pointer of the BMP085 sensor
683 *
684 * @return msg the result of the reset operation
685 */
686static msg_t thermo_reset_sensivity(void *ip) {
687
688 osalDbgCheck(ip != NULL);
689 osalDbgAssert((((BMP085Driver *)ip)->state == BMP085_READY),
690 "thermo_reset_sensivity(), invalid state");
691
692 return MSG_OK;
693}
694
695static const struct BaseSensorVMT vmt_basesensor = {
696 sens_get_axes_number, sens_read_raw, sens_read_cooked
697};
698
699static const struct BaseBarometerVMT vmt_basebarometer = {
700 baro_get_axes_number, baro_read_raw, baro_read_cooked,
701 baro_set_bias, baro_reset_bias,
702 baro_set_sensivity, baro_reset_sensivity
703};
704
705static const struct BaseThermometerVMT vmt_basethermometer = {
706 thermo_get_axes_number, thermo_read_raw, thermo_read_cooked,
707 thermo_set_bias, thermo_reset_bias,
708 thermo_set_sensivity, thermo_reset_sensivity
709};
710
711/*==========================================================================*/
712/* Driver exported functions. */
713/*==========================================================================*/
714
715/**
716 * @brief Initializes an instance.
717 *
718 * @param[out] devp pointer to the @p BMP085Driver object
719 *
720 * @init
721 */
722void bmp085ObjectInit(BMP085Driver *devp) {
723
724 devp->vmt_basesensor = &vmt_basesensor;
725 devp->vmt_basebarometer = &vmt_basebarometer;
726 devp->vmt_basethermometer = &vmt_basethermometer;
727 devp->config = NULL;
728 devp->state = BMP085_STOP;
729}
730
731/**
732 * @brief Configures and activates BMP085 Complex Driver peripheral.
733 *
734 * @param[in] devp pointer to the @p BMP085Driver object
735 * @param[in] config pointer to the @p BMP085Config object
736 *
737 * @api
738 */
739void bmp085Start(BMP085Driver *devp, const BMP085Config *config) {
740
741 osalDbgCheck((devp != NULL) && (config != NULL));
742 osalDbgAssert((devp->state == BMP085_STOP) ||
743 (devp->state == BMP085_READY),
744 "bmp085cStart(), invalid state");
745 devp->config = config;
746#if BMP085_USE_I2C
747#if BMP085_SHARED_I2C
748 i2cAcquireBus((devp)->config->i2cp);
749#endif /* BMP085_SHARED_I2C. */
750 /* Read the Calibrations data. */
751 i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg);
752 bmp085ReadCoefficient(devp, BMP085_AD_CC_AC1_MSB);
753#if BMP085_SHARED_I2C
754 i2cReleaseBus((devp)->config->i2cp);
755#endif /* BMP085_SHARED_I2C. */
756#endif /* BMP085_USE_I2C. */
757 if(devp->state != BMP085_READY)
758 devp->state = BMP085_READY;
759}
760
761/**
762 * @brief Deactivates the BMP085 Complex Driver peripheral.
763 *
764 * @param[in] devp pointer to the @p BMP085Driver object
765 *
766 * @api
767 */
768void bmp085Stop(BMP085Driver *devp) {
769
770 osalDbgCheck(devp != NULL);
771 osalDbgAssert((devp->state == BMP085_STOP) ||
772 (devp->state == BMP085_READY),
773 "bmp085Stop(), invalid state");
774#if (BMP085_USE_I2C)
775 if (devp->state == BMP085_STOP) {
776#if BMP085_SHARED_I2C
777 i2cAcquireBus((devp)->config->i2cp);
778 i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg);
779#endif /* BMP085_SHARED_I2C. */
780#if BMP085_SHARED_I2C
781 i2cReleaseBus((devp)->config->i2cp);
782#endif /* BMP085_SHARED_I2C. */
783 }
784#endif /* BMP085_USE_I2C. */
785 if (devp->state != BMP085_STOP)
786 devp->state = BMP085_STOP;
787}
788/** @} */
diff --git a/lib/chibios/os/ex/devices/Bosch/bmp085.h b/lib/chibios/os/ex/devices/Bosch/bmp085.h
new file mode 100644
index 000000000..f188c6bd8
--- /dev/null
+++ b/lib/chibios/os/ex/devices/Bosch/bmp085.h
@@ -0,0 +1,403 @@
1/*
2 ChibiOS - Copyright (C) 2016..2017 Theodore Ateba
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 bmp085.h
23 * @brief BMP085 Digital pressure sensor interface module header.
24 *
25 * @addtogroup BMP085
26 * @ingroup EX_BOSCH
27 * @{
28 */
29
30#ifndef BMP085_H
31#define BMP085_H
32
33#include "ex_barometer.h"
34#include "ex_thermometer.h"
35
36/*==========================================================================*/
37/* Driver constants. */
38/*==========================================================================*/
39
40/**
41 * @name Version identification
42 * @{
43 */
44
45/**
46 * @brief BMP085 driver version string.
47 */
48#define EX_BMP085_VERSION "1.0.1"
49
50/**
51 * @brief BMP085 driver version major number.
52 */
53#define EX_BMP085_MAJOR 1
54
55/**
56 * @brief BMP085 driver version minor number.
57 */
58#define EX_BMP085_MINOR 0
59
60/**
61 * @brief BMP085 driver version patch number.
62 */
63#define EX_BMP085_PATCH 1
64/** @}*/
65
66/**
67 * @brief BMP085 barometer subsystem characteristics.
68 * @{
69 */
70#define BMP085_BARO_NUMBER_OF_AXES 1U /**< Number of axes */
71
72#define BMP085_P_RES 0.01 /**< LSB/hP */
73/** @} */
74
75/**
76 * @brief BMP085 thermometer subsystem characteristics.
77 * @{
78 */
79#define BMP085_THERMO_NUMBER_OF_AXES 1U /**< Number of axes */
80
81#define BMP085_T_RES 0.1 /**< LSB/C° */
82/** @} */
83
84/**
85 * @name BMP085 Registers addresses.
86 * @{
87 */
88#define BMP085_AD_CR 0xF4 /**< Control register address. */
89#define BMP085_AD_T_DR_MSB 0xF6 /**< Temp MSB data register addr. */
90#define BMP085_AD_T_DR_LSB 0xF7 /**< Temp LSB data register addr. */
91#define BMP085_AD_P_DR_MSB 0xF6 /**< Press MSB data register addr. */
92#define BMP085_AD_P_DR_LSB 0xF7 /**< Press LSB data register addr. */
93#define BMP085_AD_P_DR_XLSB 0xF8 /**< Press XLSB data register addr.*/
94#define BMP085_AD_CC_AC1_MSB 0xAA /**< AC1 MSB calib coef reg addr. */
95#define BMP085_AD_CC_AC1_LSB 0xAB /**< AC1 LSB calib coef reg addr. */
96#define BMP085_AD_CC_AC2_MSB 0xAC /**< AC2 MSB calib coef reg addr. */
97#define BMP085_AD_CC_AC2_LSB 0xAD /**< AC2 LSB calib coef reg addr. */
98#define BMP085_AD_CC_AC3_MSB 0xAE /**< AC3 MSB calib coef reg addr. */
99#define BMP085_AD_CC_AC3_LSB 0xAF /**< AC3 LSB calib coef reg addr. */
100#define BMP085_AD_CC_AC4_MSB 0xB0 /**< AC4 MSB calib coef reg addr. */
101#define BMP085_AD_CC_AC4_LSB 0xB1 /**< AC4 LSB calib coef reg addr. */
102#define BMP085_AD_CC_AC5_MSB 0xB2 /**< AC5 MSB calib coef reg addr. */
103#define BMP085_AD_CC_AC5_LSB 0xB3 /**< AC5 LSB calib coef reg addr. */
104#define BMP085_AD_CC_AC6_MSB 0xB4 /**< AC6 MSB calib coef reg addr. */
105#define BMP085_AD_CC_AC6_LSB 0xB5 /**< AC6 LSB calib coef reg addr. */
106#define BMP085_AD_CC_B1_MSB 0xB6 /**< B1 MSB calib coef reg addr. */
107#define BMP085_AD_CC_B1_LSB 0xB7 /**< B1 LSB calib coef reg addr. */
108#define BMP085_AD_CC_B2_MSB 0xB8 /**< B2 MSB calib coef reg addr. */
109#define BMP085_AD_CC_B2_LSB 0xB9 /**< B2 LSB calib coef reg addr. */
110#define BMP085_AD_CC_MB_MSB 0xBA /**< MB MSB calib coef reg addr. */
111#define BMP085_AD_CC_MB_LSB 0xBB /**< MB LSB calib coef reg addr. */
112#define BMP085_AD_CC_MC_MSB 0xBC /**< MC MSB calib coef reg addr. */
113#define BMP085_AD_CC_MC_LSB 0xBD /**< MC LSB calib coef reg addr. */
114#define BMP085_AD_CC_MD_MSB 0xBE /**< MD MSB calib coef reg addr. */
115#define BMP085_AD_CC_MD_LSB 0xBF /**< MD LSB calib coef reg addr. */
116/** @} */
117
118/*==========================================================================*/
119/* Driver pre-compile time settings. */
120/*==========================================================================*/
121
122/**
123 * @name Configuration options
124 * @{
125 */
126
127/**
128 * @brief BMP085 I2C interface selector.
129 * @details If set to @p TRUE the support for I2C is included.
130 * @note The default is @p TRUE.
131 */
132#if !defined(BMP085_USE_I2C) || defined(__DOXYGEN__)
133#define BMP085_USE_I2C TRUE
134#endif
135
136/**
137 * @brief BMP085 sensor subsystem advanced configurations switch.
138 * @details If set to @p TRUE more configurations are available.
139 * @note The default is @p TRUE.
140 */
141#if !defined(BMP085_USE_ADVANCED) || defined(__DOXYGEN__)
142#define BMP085_USE_ADVANCED TRUE
143#endif
144
145/**
146 * @brief BMP085 shared I2C switch.
147 * @details If set to @p TRUE the device acquires I2C bus ownership
148 * on each transaction.
149 * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION.
150 */
151#if !defined(BMP085_SHARED_I2C) || defined(__DOXYGEN__)
152#define BMP085_SHARED_I2C FALSE
153#endif
154/** @} */
155
156/*==========================================================================*/
157/* Derived constants and error checks. */
158/*==========================================================================*/
159
160#if !HAL_USE_I2C
161#error "BMP085_USE_I2C requires HAL_USE_I2C"
162#endif
163
164#if BMP085_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
165#error "BMP085_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
166#endif
167
168/*==========================================================================*/
169/* Driver data structures and types. */
170/*==========================================================================*/
171
172/**
173 * @name BMP085 barometer subsystem data structures and types.
174 * @{
175 */
176
177/**
178 * @brief BMP085 barometer subsystem pressure conversion time.
179 */
180typedef enum {
181 BMP085_BARO_CT_LOW = 0x05, /**< Convers time in ultra low power mode. */
182 BMP085_BARO_CT_STD = 0x18, /**< Convers time in standard mode. */
183 BMP085_BARO_CT_HR = 0x0E, /**< Convers time in high resolution mode. */
184 BMP085_BARO_CT_LUHR = 0x1A /**< Convers time in ultra high res. mode. */
185} bmp085_baro_ct_t;
186
187/**
188 * @brief BMP085 barometer subsystem mode.
189 */
190typedef enum {
191 BMP085_BARO_MODE_LOW = 0x00, /**< BMP085 ultra low power mode. */
192 BMP085_BARO_MODE_STD = 0x01, /**< BMP085 standard mode. */
193 BMP085_BARO_MODE_HR = 0x02, /**< BMP085 high resolution mode. */
194 BMP085_BARO_MODE_LUHR = 0x03 /**< BMP085 ultra high res. mode. */
195} bmp085_baro_mode_t;
196
197/**
198 * @brief BMP085 barometer oversampling setting.
199 */
200typedef enum {
201 BMP085_BARO_OSS_0 = 0x00, /**< Ultra low power sampling rate. */
202 BMP085_BARO_OSS_1 = 0x01, /**< Standard mode sampling rate. */
203 BMP085_BARO_OSS_2 = 0x02, /**< High resolution sampling rate. */
204 BMP085_BARO_OSS_3 = 0x04 /**< ultra high resolution sampling rate. */
205}bmp085_baro_oss_t;
206
207/**
208 * @brief BMP085 barometer subsystem calibration data.
209 */
210typedef struct {
211 int16_t ac1;
212 int16_t ac2;
213 int16_t ac3;
214 int16_t b1;
215 int16_t b2;
216 int16_t mb;
217 int16_t mc;
218 int16_t md;
219 uint16_t ac4;
220 uint16_t ac5;
221 uint16_t ac6;
222 int32_t b5;
223} bmp085_cd_t;
224
225/** @} */
226
227/**
228 * @name BMP085 thermometer subsystem data structures and types.
229 * @{
230 */
231
232/**
233 * @brief BMP085 thermometer subsystem temperature conversion time.
234 */
235typedef enum {
236 BMP085_THERMO_CT_LOW = 0x05, /**< Conv time in ultra low power mode. */
237 BMP085_THERMO_CT_STD = 0x18, /**< Conv time in standard mode. */
238 BMP085_THERMO_CT_HR = 0x0E, /**< Conv time in high resolution mode. */
239 BMP085_THERMO_CT_LUHR = 0x1A /**< Conv time in ultra high res. mode. */
240} bmp085_thermo_ct_t;
241
242/** @} */
243
244/**
245 * @name BMP085 main system data structures and types.
246 * @{
247 */
248
249/**
250 * @brief Driver state machine possible states.
251 */
252typedef enum {
253 BMP085_UNINIT = 0, /**< Not initialized. */
254 BMP085_STOP = 1, /**< Stopped. */
255 BMP085_READY = 2 /**< Ready. */
256} bmp085_state_t;
257
258/**
259 * @brief BMP085 configuration structure.
260 */
261typedef struct {
262#if BMP085_USE_I2C || defined(__DOXYGEN__)
263 /**
264 * @brief I2C driver associated to this BMP085.
265 */
266 I2CDriver *i2cp;
267
268 /**
269 * @brief I2C configuration associated to this BMP085 subsystem.
270 */
271 const I2CConfig *i2ccfg;
272#endif /* BMP085_USE_I2C */
273 /**
274 * @brief HTS221 initial sensitivity.
275 * @note Value are respectively related to hygrometer
276 * and thermometer.
277 */
278 float* sensitivity;
279 /**
280 * @brief HTS221 initial bias.
281 * @note Value are respectively related to hygrometer
282 * and thermometer.
283 */
284 float* bias;
285 /**
286 * @brief HTS221 output data rate selection.
287 */
288 float* outputdatarate;
289#if BMP085_USE_ADVANCED || defined(__DOXYGEN__)
290 /**
291 * @brief BMP085 barometer subsystem pressure conversion time.
292 */
293 bmp085_baro_ct_t bct;
294
295 /**
296 * @brief BMP085 barometer subsystem mode.
297 */
298 bmp085_baro_mode_t mode;
299
300 /**
301 * @brief BMP085 barometer subsystem oversampling setting.
302 */
303 bmp085_baro_oss_t oss;
304
305 /**
306 * @brief BMP085 thermometer subsystem temperature conversion time.
307 */
308 bmp085_thermo_ct_t tct;
309#endif /* BMP085_USE_ADVANCED */
310} BMP085Config;
311
312/**
313 * @brief Structure representing a BMP085 driver.
314 */
315typedef struct BMP085Driver BMP085Driver;
316
317/**
318 * @brief @p BMP085 barometer subsystem specific methods.
319 */
320#define _bmp085_baro_methods \
321 _base_barometer_methods
322
323/**
324 * @brief @p BMP085 thermometer subsystem specific methods.
325 */
326#define _bmp085_thermo_methods \
327 _base_thermometer_methods
328
329/**
330 * @extends BaseBarometerVMT
331 *
332 * @brief @p BMP085 barometer virtual methods table.
333 */
334struct BMP085BAROVMT {
335 _bmp085_baro_methods
336};
337
338/**
339 * @extends BaseThermometerVMT
340 *
341 * @brief @p BMP085 thermometer virtual methods table.
342 */
343struct BMP085THERMOVMT {
344 _bmp085_thermo_methods
345};
346
347/**
348 * @brief @p BMP085Driver specific data.
349 */
350#define _bmp085_data \
351 _base_barometer_data \
352 _base_thermometer_data \
353 /* Driver state. */ \
354 bmp085_state_t state; \
355 /* Current configuration data. */ \
356 const BMP085Config *config; \
357 /* Current barometer sensitivity. */ \
358 float barosensitivity[BMP085_BARO_NUMBER_OF_AXES]; \
359 /* Barometer bias data. */ \
360 int32_t barobias[BMP085_BARO_NUMBER_OF_AXES]; \
361 /* Current thermometer sensitivity. */ \
362 float thermosensitivity[BMP085_THERMO_NUMBER_OF_AXES]; \
363 /* Thermometer bias data. */ \
364 int32_t thermobias[BMP085_THERMO_NUMBER_OF_AXES]; \
365 /* BMP085 calibration data. */ \
366 bmp085_cd_t calibrationdata;
367
368/**
369 * @brief BMP085 driver structure.
370 */
371struct BMP085Driver {
372 /** @brief BaseSensor Virtual Methods Table. */
373 const struct BaseSensorVMT *vmt_basesensor;
374 /** @brief BaseBarometer Virtual Methods Table. */
375 const struct BaseBarometerVMT *vmt_basebarometer;
376 /** @brief BaseThermometer Virtual Methods Table. */
377 const struct BaseThermometerVMT *vmt_basethermometer;
378 _bmp085_data;
379};
380
381/** @} */
382
383/*==========================================================================*/
384/* Driver macros. */
385/*==========================================================================*/
386
387/*==========================================================================*/
388/* External declarations. */
389/*==========================================================================*/
390
391#ifdef __cplusplus
392extern "C" {
393#endif
394 void bmp085ObjectInit(BMP085Driver *devp);
395 void bmp085Start(BMP085Driver *devp, const BMP085Config *config);
396 void bmp085Stop(BMP085Driver *devp);
397#ifdef __cplusplus
398}
399#endif
400
401#endif /* BMP085_H */
402
403/** @} */
diff --git a/lib/chibios/os/ex/devices/Bosch/bmp085.mk b/lib/chibios/os/ex/devices/Bosch/bmp085.mk
new file mode 100644
index 000000000..ac77a056b
--- /dev/null
+++ b/lib/chibios/os/ex/devices/Bosch/bmp085.mk
@@ -0,0 +1,10 @@
1# List of all the BMP085 device files.
2BMP085SRC := $(CHIBIOS)/os/ex/devices/Bosch/bmp085.c
3
4# Required include directories
5BMP085INC := $(CHIBIOS)/os/ex/include \
6 $(CHIBIOS)/os/ex/devices/Bosch
7
8# Shared variables
9ALLCSRC += $(BMP085SRC)
10ALLINC += $(BMP085INC) \ No newline at end of file
diff --git a/lib/chibios/os/ex/devices/ST/hts221.c b/lib/chibios/os/ex/devices/ST/hts221.c
new file mode 100644
index 000000000..32963d968
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/hts221.c
@@ -0,0 +1,781 @@
1/*
2 ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi
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 hts221.c
23 * @brief HTS221 MEMS interface module code.
24 *
25 * @addtogroup HTS221
26 * @ingroup EX_ST
27 * @{
28 */
29
30#include "hal.h"
31#include "hts221.h"
32
33/*===========================================================================*/
34/* Driver local definitions. */
35/*===========================================================================*/
36
37#define HTS221_SEL(mask, offset) (int16_t)(mask << offset)
38
39#define HTS221_FLAG_HYGRO_BIAS 0x01
40#define HTS221_FLAG_HYGRO_SENS 0x02
41#define HTS221_FLAG_THERMO_BIAS 0x04
42#define HTS221_FLAG_THERMO_SENS 0x08
43
44/*===========================================================================*/
45/* Driver exported variables. */
46/*===========================================================================*/
47
48/*===========================================================================*/
49/* Driver local variables and types. */
50/*===========================================================================*/
51
52/*===========================================================================*/
53/* Driver local functions. */
54/*===========================================================================*/
55
56#if (HTS221_USE_I2C) || defined(__DOXYGEN__)
57/**
58 * @brief Reads registers value using I2C.
59 * @pre The I2C interface must be initialized and the driver started.
60 *
61 * @param[in] i2cp pointer to the I2C interface
62 * @param[in] reg first sub-register address
63 * @param[out] rxbuf pointer to an output buffer
64 * @param[in] n number of consecutive register to read
65 * @return the operation status.
66 *
67 * @notapi
68 */
69static msg_t hts221I2CReadRegister(I2CDriver *i2cp, uint8_t reg, uint8_t* rxbuf,
70 size_t n) {
71 uint8_t txbuf = reg;
72 if (n > 1)
73 txbuf |= HTS221_SUB_MS;
74
75 return i2cMasterTransmitTimeout(i2cp, HTS221_SAD, &txbuf, 1, rxbuf, n,
76 TIME_INFINITE);
77}
78
79/**
80 * @brief Writes a value into a register using I2C.
81 * @pre The I2C interface must be initialized and the driver started.
82 *
83 * @param[in] i2cp pointer to the I2C interface
84 * @param[in] txbuf buffer containing sub-address value in first position
85 * and values to write
86 * @param[in] n size of txbuf less one (not considering the first
87 * element)
88 * @return the operation status.
89 *
90 * @notapi
91 */
92static msg_t hts221I2CWriteRegister(I2CDriver *i2cp, uint8_t* txbuf, size_t n) {
93 if (n > 1)
94 (*txbuf) |= HTS221_SUB_MS;
95
96 return i2cMasterTransmitTimeout(i2cp, HTS221_SAD, txbuf, n + 1, NULL, 0,
97 TIME_INFINITE);
98}
99#endif /* HTS221_USE_I2C */
100
101/**
102 * @brief Computes biases and sensitivities starting from data stored in
103 * calibration registers.
104 * @note Factory bias and sensitivity values are stored into the driver
105 * structure.
106 *
107 * @param[in] devp pointer to the HTS221 interface
108 * @return the operation status.
109 *
110 * @notapi
111 */
112static msg_t hts221Calibrate(HTS221Driver *devp) {
113 msg_t msg;
114 uint8_t calib[16], H0_rH_x2, H1_rH_x2, msb;
115 int16_t H0_T0_OUT, H1_T0_OUT, T0_degC_x8, T1_degC_x8, T0_OUT, T1_OUT;
116
117 /* Retrieving rH values from Calibration registers */
118 msg = hts221I2CReadRegister(devp->config->i2cp,
119 HTS221_AD_CALIB_0, calib, 16);
120
121 H0_rH_x2 = calib[0];
122 H1_rH_x2 = calib[1];
123 H0_T0_OUT = calib[6];
124 H0_T0_OUT += calib[7] << 8;
125 H1_T0_OUT = calib[10];
126 H1_T0_OUT += calib[11] << 8;
127
128 T0_degC_x8 = calib[2];
129
130 /* Completing T0_degC_x8 value */
131 msb = (calib[5] & HTS221_SEL(0x03, 0));
132 if (msb & HTS221_SEL(0x01, 1)) {
133 msb |= HTS221_SEL(0x3F, 2);
134 }
135 T0_degC_x8 += msb << 8;
136
137 T1_degC_x8 = calib[3];
138 /* Completing T1_degC_x8 value */
139 msb = ((calib[5] & HTS221_SEL(0x03, 2)) >> 2);
140 if (msb & HTS221_SEL(0x01, 1)) {
141 msb |= HTS221_SEL(0x3F, 2);
142 }
143 T1_degC_x8 += msb << 8;
144
145 T0_OUT = calib[12];
146 T0_OUT += calib[13] << 8;
147 T1_OUT = calib[14];
148 T1_OUT += calib[15] << 8;
149
150 devp->hygrofactorysensitivity = ((float)H1_rH_x2 - (float)H0_rH_x2) /
151 (((float)H1_T0_OUT - (float)H0_T0_OUT) * 2.0f);
152
153
154 devp->hygrofactorybias = (devp->hygrofactorysensitivity * (float)H0_T0_OUT) -
155 ((float)H0_rH_x2 / 2.0f);
156
157 devp->thermofactorysensitivity = ((float)T1_degC_x8 - (float)T0_degC_x8) /
158 (((float)T1_OUT - (float)T0_OUT) * 8.0f);
159
160 devp->thermofactorybias = (devp->thermofactorysensitivity * (float)T0_OUT) -
161 ((float)T0_degC_x8 / 8.0f);
162
163 return msg;
164}
165
166/**
167 * @brief Return the number of axes of the BaseHygrometer.
168 *
169 * @param[in] ip pointer to @p BaseHygrometer interface.
170 *
171 * @return the number of axes.
172 */
173static size_t hygro_get_axes_number(void *ip) {
174 (void)ip;
175
176 return HTS221_HYGRO_NUMBER_OF_AXES;
177}
178
179/**
180 * @brief Retrieves raw data from the BaseHygrometer.
181 * @note This data is retrieved from MEMS register without any algebraical
182 * manipulation.
183 * @note The axes array must be at least the same size of the
184 * BaseHygrometer axes number.
185 *
186 * @param[in] ip pointer to @p BaseHygrometer interface.
187 * @param[out] axes a buffer which would be filled with raw data.
188 *
189 * @return The operation status.
190 * @retval MSG_OK if the function succeeded.
191 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
192 * be retrieved using @p i2cGetErrors().
193 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
194 */
195static msg_t hygro_read_raw(void *ip, int32_t axes[]) {
196 HTS221Driver* devp;
197 uint8_t buff[2];
198 int16_t tmp;
199 msg_t msg;
200
201 osalDbgCheck((ip != NULL) && (axes != NULL));
202
203 /* Getting parent instance pointer.*/
204 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
205
206 osalDbgAssert((devp->state == HTS221_READY),
207 "hygro_read_raw(), invalid state");
208
209 osalDbgAssert((devp->config->i2cp->state == I2C_READY),
210 "hygro_read_raw(), channel not ready");
211
212#if HTS221_SHARED_I2C
213 i2cAcquireBus(devp->config->i2cp);
214 i2cStart(devp->config->i2cp,
215 devp->config->i2ccfg);
216#endif /* HTS221_SHARED_I2C */
217
218 msg = hts221I2CReadRegister(devp->config->i2cp, HTS221_AD_HUMIDITY_OUT_L,
219 buff, 2);
220
221#if HTS221_SHARED_I2C
222 i2cReleaseBus(devp->config->i2cp);
223#endif /* HTS221_SHARED_I2C */
224
225 if (msg == MSG_OK) {
226 tmp = buff[0] + (buff[1] << 8);
227 *axes = (int32_t)tmp;
228 }
229 return msg;
230}
231
232/**
233 * @brief Retrieves cooked data from the BaseHygrometer.
234 * @note This data is manipulated according to the formula
235 * cooked = (raw * sensitivity) - bias.
236 * @note Final data is expressed as %rH.
237 * @note The axes array must be at least the same size of the
238 * BaseHygrometer axes number.
239 *
240 * @param[in] ip pointer to @p BaseHygrometer interface.
241 * @param[out] axes a buffer which would be filled with cooked data.
242 *
243 * @return The operation status.
244 * @retval MSG_OK if the function succeeded.
245 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
246 * be retrieved using @p i2cGetErrors().
247 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
248 */
249static msg_t hygro_read_cooked(void *ip, float axes[]) {
250 HTS221Driver* devp;
251 int32_t raw;
252 msg_t msg;
253
254 osalDbgCheck((ip != NULL) && (axes != NULL));
255
256 /* Getting parent instance pointer.*/
257 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
258
259 osalDbgAssert((devp->state == HTS221_READY),
260 "hygro_read_cooked(), invalid state");
261
262 msg = hygro_read_raw(ip, &raw);
263
264 *axes = (raw * devp->hygrosensitivity) - devp->hygrobias;
265
266 return msg;
267}
268
269/**
270 * @brief Set bias values for the BaseHygrometer.
271 * @note Bias must be expressed as %rH.
272 * @note The bias buffer must be at least the same size of the
273 * BaseHygrometer axes number.
274 *
275 * @param[in] ip pointer to @p BaseHygrometer interface.
276 * @param[in] bp a buffer which contains biases.
277 *
278 * @return The operation status.
279 * @retval MSG_OK if the function succeeded.
280 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
281 * be retrieved using @p i2cGetErrors().
282 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
283 */
284static msg_t hygro_set_bias(void *ip, float *bp) {
285 HTS221Driver* devp;
286 msg_t msg = MSG_OK;
287
288 osalDbgCheck((ip != NULL) && (bp != NULL));
289
290 /* Getting parent instance pointer.*/
291 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
292
293 osalDbgAssert((devp->state == HTS221_READY),
294 "hygro_set_bias(), invalid state");
295
296 devp->hygrobias = *bp;
297 return msg;
298}
299
300/**
301 * @brief Reset bias values for the BaseHygrometer.
302 * @note Default biases value are obtained from device datasheet when
303 * available otherwise they are considered zero.
304 *
305 * @param[in] ip pointer to @p BaseHygrometer interface.
306 *
307 * @return The operation status.
308 * @retval MSG_OK if the function succeeded.
309 */
310static msg_t hygro_reset_bias(void *ip) {
311 HTS221Driver* devp;
312 msg_t msg = MSG_OK;
313
314 osalDbgCheck(ip != NULL);
315
316 /* Getting parent instance pointer.*/
317 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
318
319 osalDbgAssert((devp->state == HTS221_READY),
320 "hygro_reset_bias(), invalid state");
321
322 devp->hygrobias = devp->hygrofactorybias;
323 return msg;
324}
325
326/**
327 * @brief Set sensitivity values for the BaseHygrometer.
328 * @note Sensitivity must be expressed as %rH/LSB.
329 * @note The sensitivity buffer must be at least the same size of the
330 * BaseHygrometer axes number.
331 *
332 * @param[in] ip pointer to @p BaseHygrometer interface.
333 * @param[in] sp a buffer which contains sensitivities.
334 *
335 * @return The operation status.
336 * @retval MSG_OK if the function succeeded.
337 */
338static msg_t hygro_set_sensitivity(void *ip, float *sp) {
339 HTS221Driver* devp;
340 msg_t msg = MSG_OK;
341
342 osalDbgCheck((ip != NULL) && (sp != NULL));
343
344 /* Getting parent instance pointer.*/
345 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
346
347 osalDbgAssert((devp->state == HTS221_READY),
348 "hygro_set_sensitivity(), invalid state");
349
350 devp->hygrosensitivity = *sp;
351 return msg;
352}
353
354/**
355 * @brief Reset sensitivity values for the BaseHygrometer.
356 * @note Default sensitivities value are obtained from device datasheet.
357 *
358 * @param[in] ip pointer to @p BaseHygrometer interface.
359 *
360 * @return The operation status.
361 * @retval MSG_OK if the function succeeded.
362 */
363static msg_t hygro_reset_sensitivity(void *ip) {
364 HTS221Driver* devp;
365 msg_t msg = MSG_OK;
366
367 osalDbgCheck(ip != NULL);
368
369 /* Getting parent instance pointer.*/
370 devp = objGetInstance(HTS221Driver*, (BaseHygrometer*)ip);
371
372 osalDbgAssert((devp->state == HTS221_READY),
373 "hygro_reset_sensitivity(), invalid state");
374
375 devp->hygrosensitivity = devp->hygrofactorysensitivity;
376 return msg;
377}
378
379/**
380 * @brief Return the number of axes of the BaseThermometer.
381 *
382 * @param[in] ip pointer to @p BaseThermometer interface.
383 *
384 * @return the number of axes.
385 */
386static size_t thermo_get_axes_number(void *ip) {
387 (void)ip;
388
389 return HTS221_THERMO_NUMBER_OF_AXES;
390}
391
392/**
393 * @brief Retrieves raw data from the BaseThermometer.
394 * @note This data is retrieved from MEMS register without any algebraical
395 * manipulation.
396 * @note The axes array must be at least the same size of the
397 * BaseThermometer axes number.
398 *
399 * @param[in] ip pointer to @p BaseThermometer interface.
400 * @param[out] axes a buffer which would be filled with raw data.
401 *
402 * @return The operation status.
403 * @retval MSG_OK if the function succeeded.
404 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
405 * be retrieved using @p i2cGetErrors().
406 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
407 */
408static msg_t thermo_read_raw(void *ip, int32_t axes[]) {
409 HTS221Driver* devp;
410 int16_t tmp;
411 uint8_t buff[2];
412 msg_t msg;
413
414 osalDbgCheck((ip != NULL) && (axes != NULL));
415
416 /* Getting parent instance pointer.*/
417 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
418
419 osalDbgAssert((devp->state == HTS221_READY),
420 "thermo_read_raw(), invalid state");
421
422 osalDbgAssert((devp->config->i2cp->state == I2C_READY),
423 "thermo_read_raw(), channel not ready");
424
425#if HTS221_SHARED_I2C
426 i2cAcquireBus(devp->config->i2cp);
427 i2cStart(devp->config->i2cp,
428 devp->config->i2ccfg);
429#endif /* HTS221_SHARED_I2C */
430
431 msg = hts221I2CReadRegister(devp->config->i2cp, HTS221_AD_TEMP_OUT_L,
432 buff, 2);
433
434#if HTS221_SHARED_I2C
435 i2cReleaseBus(devp->config->i2cp);
436#endif /* HTS221_SHARED_I2C */
437
438 if (msg == MSG_OK) {
439 tmp = buff[0] + (buff[1] << 8);
440 *axes = (int32_t)tmp;
441 }
442 return msg;
443}
444
445/**
446 * @brief Retrieves cooked data from the BaseThermometer.
447 * @note This data is manipulated according to the formula
448 * cooked = (raw * sensitivity) - bias.
449 * @note Final data is expressed as °C.
450 * @note The axes array must be at least the same size of the
451 * BaseThermometer axes number.
452 *
453 * @param[in] ip pointer to @p BaseThermometer interface.
454 * @param[out] axis a buffer which would be filled with cooked data.
455 *
456 * @return The operation status.
457 * @retval MSG_OK if the function succeeded.
458 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
459 * be retrieved using @p i2cGetErrors().
460 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
461 */
462static msg_t thermo_read_cooked(void *ip, float* axis) {
463 HTS221Driver* devp;
464 int32_t raw;
465 msg_t msg;
466
467 osalDbgCheck((ip != NULL) && (axis != NULL));
468
469 /* Getting parent instance pointer.*/
470 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
471
472 osalDbgAssert((devp->state == HTS221_READY),
473 "thermo_read_cooked(), invalid state");
474
475 msg = thermo_read_raw(devp, &raw);
476
477 *axis = (raw * devp->thermosensitivity) - devp->thermobias;
478
479 return msg;
480}
481
482/**
483 * @brief Set bias values for the BaseThermometer.
484 * @note Bias must be expressed as °C.
485 * @note The bias buffer must be at least the same size of the
486 * BaseThermometer axes number.
487 *
488 * @param[in] ip pointer to @p BaseThermometer interface.
489 * @param[in] bp a buffer which contains biases.
490 *
491 * @return The operation status.
492 * @retval MSG_OK if the function succeeded.
493 */
494static msg_t thermo_set_bias(void *ip, float *bp) {
495 HTS221Driver* devp;
496 msg_t msg = MSG_OK;
497
498 osalDbgCheck((ip != NULL) && (bp != NULL));
499
500 /* Getting parent instance pointer.*/
501 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
502
503 osalDbgAssert((devp->state == HTS221_READY),
504 "thermo_set_bias(), invalid state");
505
506 devp->thermobias = *bp;
507
508 return msg;
509}
510
511/**
512 * @brief Reset bias values for the BaseThermometer.
513 * @note Default biases value are obtained from device datasheet when
514 * available otherwise they are considered zero.
515 *
516 * @param[in] ip pointer to @p BaseThermometer interface.
517 *
518 * @return The operation status.
519 * @retval MSG_OK if the function succeeded.
520 */
521static msg_t thermo_reset_bias(void *ip) {
522 HTS221Driver* devp;
523 msg_t msg = MSG_OK;
524
525 osalDbgCheck(ip != NULL);
526
527 /* Getting parent instance pointer.*/
528 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
529
530 osalDbgAssert((devp->state == HTS221_READY),
531 "thermo_reset_bias(), invalid state");
532
533 devp->thermobias = devp->thermofactorybias;
534
535 return msg;
536}
537
538/**
539 * @brief Set sensitivity values for the BaseThermometer.
540 * @note Sensitivity must be expressed as °C/LSB.
541 * @note The sensitivity buffer must be at least the same size of the
542 * BaseThermometer axes number.
543 *
544 * @param[in] ip pointer to @p BaseThermometer interface.
545 * @param[in] sp a buffer which contains sensitivities.
546 *
547 * @return The operation status.
548 * @retval MSG_OK if the function succeeded.
549 */
550static msg_t thermo_set_sensitivity(void *ip, float *sp) {
551 HTS221Driver* devp;
552 msg_t msg = MSG_OK;
553
554 osalDbgCheck((ip != NULL) && (sp != NULL));
555
556 /* Getting parent instance pointer.*/
557 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
558
559 osalDbgAssert((devp->state == HTS221_READY),
560 "thermo_set_sensitivity(), invalid state");
561
562 devp->thermosensitivity = *sp;
563
564 return msg;
565}
566
567/**
568 * @brief Reset sensitivity values for the BaseThermometer.
569 * @note Default sensitivities value are obtained from device datasheet.
570 *
571 * @param[in] ip pointer to @p BaseThermometer interface.
572 *
573 * @return The operation status.
574 * @retval MSG_OK if the function succeeded.
575 */
576static msg_t thermo_reset_sensitivity(void *ip) {
577 HTS221Driver* devp;
578 msg_t msg = MSG_OK;
579
580 osalDbgCheck(ip != NULL);
581
582 /* Getting parent instance pointer.*/
583 devp = objGetInstance(HTS221Driver*, (BaseThermometer*)ip);
584
585 osalDbgAssert((devp->state == HTS221_READY),
586 "thermo_reset_sensitivity(), invalid state");
587
588 devp->thermosensitivity = devp->thermofactorysensitivity;
589
590 return msg;
591}
592
593static const struct HTS221VMT vmt_device = {
594 (size_t)0
595};
596
597static const struct BaseHygrometerVMT vmt_hygrometer = {
598 sizeof(struct HTS221VMT*),
599 hygro_get_axes_number, hygro_read_raw, hygro_read_cooked,
600 hygro_set_bias, hygro_reset_bias, hygro_set_sensitivity,
601 hygro_reset_sensitivity
602};
603
604static const struct BaseThermometerVMT vmt_thermometer = {
605 sizeof(struct HTS221VMT*) + sizeof(BaseHygrometer),
606 thermo_get_axes_number, thermo_read_raw, thermo_read_cooked,
607 thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity,
608 thermo_reset_sensitivity
609};
610
611/*===========================================================================*/
612/* Driver exported functions. */
613/*===========================================================================*/
614
615/**
616 * @brief Initializes an instance.
617 *
618 * @param[out] devp pointer to the @p HTS221Driver object
619 *
620 * @init
621 */
622void hts221ObjectInit(HTS221Driver *devp) {
623
624 devp->vmt = &vmt_device;
625 devp->hygro_if.vmt = &vmt_hygrometer;
626 devp->thermo_if.vmt = &vmt_thermometer;
627
628 devp->config = NULL;
629
630 devp->hygroaxes = HTS221_HYGRO_NUMBER_OF_AXES;
631 devp->thermoaxes = HTS221_THERMO_NUMBER_OF_AXES;
632
633 devp->hygrobias = 0.0f;
634 devp->thermobias = 0.0f;
635
636 devp->state = HTS221_STOP;
637}
638
639/**
640 * @brief Configures and activates HTS221 Complex Driver peripheral.
641 *
642 * @param[in] devp pointer to the @p HTS221Driver object
643 * @param[in] config pointer to the @p HTS221Config object
644 *
645 * @api
646 */
647void hts221Start(HTS221Driver *devp, const HTS221Config *config) {
648 uint8_t cr[2];
649 osalDbgCheck((devp != NULL) && (config != NULL));
650
651 osalDbgAssert((devp->state == HTS221_STOP) || (devp->state == HTS221_READY),
652 "hts221Start(), invalid state");
653
654 devp->config = config;
655
656#if HTS221_SHARED_I2C
657 i2cAcquireBus(devp->config->i2cp);
658#endif /* HTS221_SHARED_I2C */
659
660 /* Intializing the I2C. */
661 i2cStart(devp->config->i2cp, devp->config->i2ccfg);
662
663 hts221Calibrate(devp);
664
665#if HTS221_SHARED_I2C
666 i2cReleaseBus(devp->config->i2cp);
667#endif /* HTS221_SHARED_I2C */
668
669
670 if(devp->config->hygrosensitivity == NULL) {
671 devp->hygrosensitivity = devp->hygrofactorysensitivity;
672 }
673 else{
674 /* Taking hygrometer sensitivity from user configurations */
675 devp->hygrosensitivity = *(devp->config->hygrosensitivity);
676 }
677
678 if(devp->config->hygrobias == NULL) {
679 devp->hygrobias = devp->hygrofactorybias;
680 }
681 else{
682 /* Taking hygrometer bias from user configurations */
683 devp->hygrobias = *(devp->config->hygrobias);
684 }
685
686 if(devp->config->thermosensitivity == NULL) {
687 devp->thermosensitivity = devp->thermofactorysensitivity;
688 }
689 else{
690 /* Taking thermometer sensitivity from user configurations */
691 devp->thermosensitivity = *(devp->config->thermosensitivity);
692 }
693
694 if(devp->config->thermobias == NULL) {
695 devp->thermobias = devp->thermofactorybias;
696 }
697 else{
698 /* Taking thermometer bias from user configurations */
699 devp->thermobias = *(devp->config->thermobias);
700 }
701
702 /* Control register 1 configuration block.*/
703 {
704 cr[0] = HTS221_AD_CTRL_REG1;
705 cr[1] = devp->config->outputdatarate | HTS221_CTRL_REG1_PD;
706#if HTS221_USE_ADVANCED || defined(__DOXYGEN__)
707 cr[1] |= devp->config->blockdataupdate;
708#endif
709
710#if HTS221_SHARED_I2C
711 i2cAcquireBus(devp->config->i2cp);
712 i2cStart(devp->config->i2cp, devp->config->i2ccfg);
713#endif /* HTS221_SHARED_I2C */
714
715 hts221I2CWriteRegister(devp->config->i2cp, cr, 1);
716
717#if HTS221_SHARED_I2C
718 i2cReleaseBus(devp->config->i2cp);
719#endif /* HTS221_SHARED_I2C */
720 }
721
722 /* Average register configuration block.*/
723 {
724 cr[0] = HTS221_AD_AV_CONF;
725 cr[1] = 0x05;
726#if HTS221_USE_ADVANCED || defined(__DOXYGEN__)
727 cr[1] = devp->config->hygroresolution | devp->config->thermoresolution;
728#endif
729
730#if HTS221_SHARED_I2C
731 i2cAcquireBus(devp->config->i2cp);
732 i2cStart(devp->config->i2cp, devp->config->i2ccfg);
733#endif /* HTS221_SHARED_I2C */
734
735 hts221I2CWriteRegister(devp->config->i2cp, cr, 1);
736
737#if HTS221_SHARED_I2C
738 i2cReleaseBus(devp->config->i2cp);
739#endif /* HTS221_SHARED_I2C */
740 }
741
742 /* This is the MEMS transient recovery time */
743 osalThreadSleepMilliseconds(5);
744
745 devp->state = HTS221_READY;
746}
747
748/**
749 * @brief Deactivates the HTS221 Complex Driver peripheral.
750 *
751 * @param[in] devp pointer to the @p HTS221Driver object
752 *
753 * @api
754 */
755void hts221Stop(HTS221Driver *devp) {
756 uint8_t cr[2];
757
758 osalDbgCheck(devp != NULL);
759
760 osalDbgAssert((devp->state == HTS221_STOP) || (devp->state == HTS221_READY),
761 "hts221Stop(), invalid state");
762
763 if (devp->state == HTS221_READY) {
764
765#if HTS221_SHARED_I2C
766 i2cAcquireBus(devp->config->i2cp);
767 i2cStart(devp->config->i2cp, devp->config->i2ccfg);
768#endif /* HTS221_SHARED_I2C */
769
770 cr[0] = HTS221_AD_CTRL_REG1;
771 cr[1] = 0;
772 hts221I2CWriteRegister(devp->config->i2cp, cr, 1);
773
774 i2cStop(devp->config->i2cp);
775#if HTS221_SHARED_I2C
776 i2cReleaseBus(devp->config->i2cp);
777#endif /* HTS221_SHARED_I2C */
778 }
779 devp->state = HTS221_STOP;
780}
781/** @} */
diff --git a/lib/chibios/os/ex/devices/ST/hts221.h b/lib/chibios/os/ex/devices/ST/hts221.h
new file mode 100644
index 000000000..263978ecf
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/hts221.h
@@ -0,0 +1,707 @@
1/*
2 ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi
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 hts221.h
23 * @brief HTS221 MEMS interface module header.
24 *
25 *
26 * @addtogroup HTS221
27 * @ingroup EX_ST
28 * @{
29 */
30#ifndef _HTS221_H_
31#define _HTS221_H_
32
33#include "ex_hygrometer.h"
34#include "ex_thermometer.h"
35
36/*===========================================================================*/
37/* Driver constants. */
38/*===========================================================================*/
39
40/**
41 * @name Version identification
42 * @{
43 */
44/**
45 * @brief HTS221 driver version string.
46 */
47#define EX_HTS221_VERSION "1.1.2"
48
49/**
50 * @brief HTS221 driver version major number.
51 */
52#define EX_HTS221_MAJOR 1
53
54/**
55 * @brief HTS221 driver version minor number.
56 */
57#define EX_HTS221_MINOR 1
58
59/**
60 * @brief HTS221 driver version patch number.
61 */
62#define EX_HTS221_PATCH 2
63/** @} */
64
65/**
66 * @brief HTS221 hygrometer subsystem characteristics.
67 * @note Sensitivity is expressed as %rH/LSB whereas %rH stand for percentage
68 * of relative humidity.
69 * @note Bias is expressed as %rH.
70 * @{
71 */
72#define HTS221_HYGRO_NUMBER_OF_AXES 1U
73
74#define HTS221_HYGRO_SENS 0.00390625f
75#define HTS221_HYGRO_BIAS 0.0f
76/** @} */
77
78/**
79 * @brief HTS221 thermometer subsystem characteristics.
80 * @note Sensitivity is expressed as �C/LSB.
81 * @note Bias is expressed as �C.
82 *
83 * @{
84 */
85#define HTS221_THERMO_NUMBER_OF_AXES 1U
86
87#define HTS221_THERMO_SENS 0.0015625f
88#define HTS221_THERMO_BIAS 0.0f
89/** @} */
90
91/**
92 * @name HTS221 communication interfaces related bit masks
93 * @{
94 */
95#define HTS221_DI_MASK 0xFF
96#define HTS221_DI(n) (1 << n)
97#define HTS221_AD_MASK 0x3F
98#define HTS221_AD(n) (1 << n)
99#define HTS221_MS (1 << 6)
100#define HTS221_RW (1 << 7)
101
102#define HTS221_SUB_MS (1 << 7)
103
104#define HTS221_SAD 0x5F
105/** @} */
106
107/**
108 * @name HTS221 register addresses
109 * @{
110 */
111#define HTS221_AD_WHO_AM_I 0x0F
112#define HTS221_AD_AV_CONF 0x10
113#define HTS221_AD_CTRL_REG1 0x20
114#define HTS221_AD_CTRL_REG2 0x21
115#define HTS221_AD_CTRL_REG3 0x22
116#define HTS221_AD_STATUS_REG 0x27
117#define HTS221_AD_HUMIDITY_OUT_L 0x28
118#define HTS221_AD_HUMIDITY_OUT_H 0x29
119#define HTS221_AD_TEMP_OUT_L 0x2A
120#define HTS221_AD_TEMP_OUT_H 0x2B
121#define HTS221_AD_CALIB_0 0x30
122#define HTS221_AD_CALIB_1 0x31
123#define HTS221_AD_CALIB_2 0x32
124#define HTS221_AD_CALIB_3 0x33
125#define HTS221_AD_CALIB_4 0x34
126#define HTS221_AD_CALIB_5 0x35
127#define HTS221_AD_CALIB_6 0x36
128#define HTS221_AD_CALIB_7 0x37
129#define HTS221_AD_CALIB_8 0x38
130#define HTS221_AD_CALIB_9 0x39
131#define HTS221_AD_CALIB_A 0x3A
132#define HTS221_AD_CALIB_B 0x3B
133#define HTS221_AD_CALIB_C 0x3C
134#define HTS221_AD_CALIB_D 0x3D
135#define HTS221_AD_CALIB_E 0x3E
136#define HTS221_AD_CALIB_F 0x3F
137/** @} */
138
139/**
140 * @name HTS221_CTRL_REG1 register bits definitions
141 * @{
142 */
143#define HTS221_CTRL_REG1_MASK 0x87
144#define HTS221_CTRL_REG1_ODR0 (1 << 0)
145#define HTS221_CTRL_REG1_ODR1 (1 << 1)
146#define HTS221_CTRL_REG1_BDU (1 << 2)
147#define HTS221_CTRL_REG1_PD (1 << 7)
148/** @} */
149
150/**
151 * @name HTS221_CTRL_REG2 register bits definitions
152 * @{
153 */
154#define HTS221_CTRL_REG2_MASK 0x83
155#define HTS221_CTRL_REG2_ONE_SHOT (1 << 0)
156#define HTS221_CTRL_REG2_HEATER (1 << 1)
157#define HTS221_CTRL_REG2_BOOT (1 << 7)
158/** @} */
159
160/**
161 * @name HTS221_CTRL_REG3 register bits definitions
162 * @{
163 */
164#define HTS221_CTRL_REG3_MASK 0xC4
165#define HTS221_CTRL_REG3_DRDY (1 << 2)
166#define HTS221_CTRL_REG3_PP_OD (1 << 6)
167#define HTS221_CTRL_REG3_INT_H_L (1 << 7)
168/** @} */
169
170/*===========================================================================*/
171/* Driver pre-compile time settings. */
172/*===========================================================================*/
173
174/**
175 * @name Configuration options
176 * @{
177 */
178/**
179 * @brief HTS221 SPI interface switch.
180 * @details If set to @p TRUE the support for SPI is included.
181 * @note The default is @p FALSE.
182 */
183#if !defined(HTS221_USE_SPI) || defined(__DOXYGEN__)
184#define HTS221_USE_SPI FALSE
185#endif
186
187/**
188 * @brief HTS221 shared SPI switch.
189 * @details If set to @p TRUE the device acquires SPI bus ownership
190 * on each transaction.
191 * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION
192 */
193#if !defined(HTS221_SHARED_SPI) || defined(__DOXYGEN__)
194#define HTS221_SHARED_SPI FALSE
195#endif
196
197/**
198 * @brief HTS221 I2C interface switch.
199 * @details If set to @p TRUE the support for I2C is included.
200 * @note The default is @p TRUE.
201 */
202#if !defined(HTS221_USE_I2C) || defined(__DOXYGEN__)
203#define HTS221_USE_I2C TRUE
204#endif
205
206/**
207 * @brief HTS221 shared I2C switch.
208 * @details If set to @p TRUE the device acquires I2C bus ownership
209 * on each transaction.
210 * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION
211 */
212#if !defined(HTS221_SHARED_I2C) || defined(__DOXYGEN__)
213#define HTS221_SHARED_I2C FALSE
214#endif
215
216/**
217 * @brief HTS221 advanced configurations switch.
218 * @details If set to @p TRUE more configurations are available.
219 * @note The default is @p FALSE.
220 */
221#if !defined(HTS221_USE_ADVANCED) || defined(__DOXYGEN__)
222#define HTS221_USE_ADVANCED FALSE
223#endif
224/** @} */
225
226/*===========================================================================*/
227/* Derived constants and error checks. */
228/*===========================================================================*/
229
230#if !(HTS221_USE_SPI ^ HTS221_USE_I2C)
231#error "HTS221_USE_SPI and HTS221_USE_I2C cannot be both true or both false"
232#endif
233
234#if HTS221_USE_SPI && !HAL_USE_SPI
235#error "HTS221_USE_SPI requires HAL_USE_SPI"
236#endif
237
238#if HTS221_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
239#error "HTS221_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
240#endif
241
242#if HTS221_USE_I2C && !HAL_USE_I2C
243#error "HTS221_USE_I2C requires HAL_USE_I2C"
244#endif
245
246#if HTS221_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
247#error "HTS221_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
248#endif
249
250/*
251 * CHTODO: Add support for HTS221 over SPI.
252 */
253#if HTS221_USE_SPI
254#error "HTS221 over SPI still not supported."
255#endif
256
257/*===========================================================================*/
258/* Driver data structures and types. */
259/*===========================================================================*/
260
261/**
262 * @name HTS221 data structures and types.
263 * @{
264 */
265/**
266 * @brief Structure representing a HTS221 driver.
267 */
268typedef struct HTS221Driver HTS221Driver;
269
270/**
271 * @brief HTS221 output data rate and bandwidth.
272 */
273typedef enum {
274 HTS221_ODR_ONE_SHOT = 0x00, /**< One shot. */
275 HTS221_ODR_1HZ = 0x01, /**< Output data rate 1 Hz. */
276 HTS221_ODR_7HZ = 0x02, /**< Output data rate 7 Hz. */
277 HTS221_ODR_12P5HZ = 0x03, /**< Output data rate 12.5 Hz. */
278}hts221_odr_t;
279
280/**
281 * @brief HTS221 humidity resolution.
282 */
283typedef enum {
284 HTS221_AVGH_4 = 0x00, /**< Number of internal average is 4. */
285 HTS221_AVGH_8 = 0x01, /**< Number of internal average is 8. */
286 HTS221_AVGH_16 = 0x02, /**< Number of internal average is 16. */
287 HTS221_AVGH_32 = 0x03, /**< Number of internal average is 32. */
288 HTS221_AVGH_64 = 0x04, /**< Number of internal average is 64. */
289 HTS221_AVGH_128 = 0x05, /**< Number of internal average is 128. */
290 HTS221_AVGH_256 = 0x06, /**< Number of internal average is 256. */
291 HTS221_AVGH_512 = 0x07 /**< Number of internal average is 512. */
292}hts221_avgh_t;
293
294/**
295 * @brief HTS221 temperature resolution.
296 */
297typedef enum {
298 HTS221_AVGT_2 = 0x00, /**< Number of internal average is 2. */
299 HTS221_AVGT_4 = 0x08, /**< Number of internal average is 4. */
300 HTS221_AVGT_8 = 0x10, /**< Number of internal average is 8. */
301 HTS221_AVGT_16 = 0x18, /**< Number of internal average is 16. */
302 HTS221_AVGT_32 = 0x20, /**< Number of internal average is 32. */
303 HTS221_AVGT_64 = 0x28, /**< Number of internal average is 64. */
304 HTS221_AVGT_128 = 0x30, /**< Number of internal average is 128. */
305 HTS221_AVGT_256 = 0x38, /**< Number of internal average is 256. */
306}hts221_avgt_t;
307
308/**
309 * @brief HTS221 block data update.
310 */
311typedef enum {
312 HTS221_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
313 HTS221_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */
314}hts221_bdu_t;
315
316/**
317 * @brief Driver state machine possible states.
318 */
319typedef enum {
320 HTS221_UNINIT = 0, /**< Not initialized. */
321 HTS221_STOP = 1, /**< Stopped. */
322 HTS221_READY = 2, /**< Ready. */
323} hts221_state_t;
324
325/**
326 * @brief HTS221 configuration structure.
327 */
328typedef struct {
329
330#if HTS221_USE_SPI || defined(__DOXYGEN__)
331 /**
332 * @brief SPI driver associated to this HTS221.
333 */
334 SPIDriver *spip;
335 /**
336 * @brief SPI configuration associated to this HTS221.
337 */
338 const SPIConfig *spicfg;
339#endif /* HTS221_USE_SPI */
340#if HTS221_USE_I2C || defined(__DOXYGEN__)
341 /**
342 * @brief I2C driver associated to this HTS221.
343 */
344 I2CDriver *i2cp;
345 /**
346 * @brief I2C configuration associated to this HTS221.
347 */
348 const I2CConfig *i2ccfg;
349#endif /* HTS221_USE_I2C */
350 /**
351 * @brief HTS221 hygrometer subsystem initial sensitivity.
352 */
353 float *hygrosensitivity;
354 /**
355 * @brief HTS221 hygrometer subsystem initial bias.
356 */
357 float *hygrobias;
358 /**
359 * @brief HTS221 thermometer subsystem initial sensitivity.
360 */
361 float *thermosensitivity;
362 /**
363 * @brief HTS221 thermometer subsystem initial bias.
364 */
365 float *thermobias;
366 /**
367 * @brief HTS221 output data rate selection.
368 */
369 hts221_odr_t outputdatarate;
370#if HTS221_USE_ADVANCED || defined(__DOXYGEN__)
371 /**
372 * @brief HTS221 block data update.
373 */
374 hts221_bdu_t blockdataupdate;
375 /**
376 * @brief HTS221 hygrometer subsystem resolution.
377 */
378 hts221_avgh_t hygroresolution;
379 /**
380 * @brief HTS221 thermometer subsystem resolution.
381 */
382 hts221_avgt_t thermoresolution;
383#endif
384} HTS221Config;
385
386/**
387 * @brief @p HTS221 specific methods.
388 * @note No methods so far, just a common ancestor interface.
389 */
390#define _hts221_methods_alone
391
392/**
393 * @brief @p HTS221 specific methods with inherited ones.
394 */
395#define _hts221_methods \
396 _base_object_methods \
397 _hts221_methods_alone
398
399/**
400 * @extends BaseObjectVMT
401 *
402 * @brief @p HTS221 virtual methods table.
403 */
404struct HTS221VMT {
405 _hts221_methods
406};
407
408/**
409 * @brief @p HTS221Driver specific data.
410 */
411#define _hts221_data \
412 /* Driver state.*/ \
413 hts221_state_t state; \
414 /* Current configuration data.*/ \
415 const HTS221Config *config; \
416 /* Hygrometer subsystem axes number.*/ \
417 size_t hygroaxes; \
418 /* Hygrometer subsystem current sensitivity.*/ \
419 float hygrosensitivity; \
420 /* Hygrometer subsystem current bias .*/ \
421 float hygrobias; \
422 /* Hygrometer subsystem factory sensitivity.*/ \
423 float hygrofactorysensitivity; \
424 /* Hygrometer subsystem factory bias .*/ \
425 float hygrofactorybias; \
426 /* Thermometer subsystem axes number.*/ \
427 size_t thermoaxes; \
428 /* Thermometer subsystem current sensitivity.*/ \
429 float thermosensitivity; \
430 /* Thermometer subsystem current bias.*/ \
431 float thermobias; \
432 /* Thermometer subsystem factory sensitivity.*/ \
433 float thermofactorysensitivity; \
434 /* Thermometer subsystem factory bias.*/ \
435 float thermofactorybias;
436
437/**
438 * @brief HTS221 2-axis hygrometer/thermometer class.
439 */
440struct HTS221Driver {
441 /** @brief Virtual Methods Table.*/
442 const struct HTS221VMT *vmt;
443 /** @brief Base hygrometer interface.*/
444 BaseHygrometer hygro_if;
445 /** @brief Base thermometer interface.*/
446 BaseThermometer thermo_if;
447 _hts221_data
448};
449/** @} */
450
451/*===========================================================================*/
452/* Driver macros. */
453/*===========================================================================*/
454
455/**
456 * @brief Return the number of axes of the BaseHygrometer.
457 *
458 * @param[in] devp pointer to @p HTS221Driver.
459 *
460 * @return the number of axes.
461 *
462 * @api
463 */
464#define hts221HygrometerGetAxesNumber(devp) \
465 hygrometerGetAxesNumber(&((devp)->hygro_if))
466
467/**
468 * @brief Retrieves raw data from the BaseHygrometer.
469 * @note This data is retrieved from MEMS register without any algebraical
470 * manipulation.
471 * @note The axes array must be at least the same size of the
472 * BaseHygrometer axes number.
473 *
474 * @param[in] devp pointer to @p HTS221Driver.
475 * @param[out] axes a buffer which would be filled with raw data.
476 *
477 * @return The operation status.
478 * @retval MSG_OK if the function succeeded.
479 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
480 * be retrieved using @p i2cGetErrors().
481 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
482 *
483 * @api
484 */
485#define hts221HygrometerReadRaw(devp, axes) \
486 hygrometerReadRaw(&((devp)->hygro_if), axes)
487
488/**
489 * @brief Retrieves cooked data from the BaseHygrometer.
490 * @note This data is manipulated according to the formula
491 * cooked = (raw * sensitivity) - bias.
492 * @note Final data is expressed as %rH.
493 * @note The axes array must be at least the same size of the
494 * BaseHygrometer axes number.
495 *
496 * @param[in] devp pointer to @p HTS221Driver.
497 * @param[out] axes a buffer which would be filled with cooked data.
498 *
499 * @return The operation status.
500 * @retval MSG_OK if the function succeeded.
501 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
502 * be retrieved using @p i2cGetErrors().
503 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
504 *
505 * @api
506 */
507#define hts221HygrometerReadCooked(devp, axes) \
508 hygrometerReadCooked(&((devp)->hygro_if), axes)
509
510/**
511 * @brief Set bias values for the BaseHygrometer.
512 * @note Bias must be expressed as %rH.
513 * @note The bias buffer must be at least the same size of the
514 * BaseHygrometer axes number.
515 *
516 * @param[in] devp pointer to @p HTS221Driver.
517 * @param[in] bp a buffer which contains biases.
518 *
519 * @return The operation status.
520 * @retval MSG_OK if the function succeeded.
521 *
522 * @api
523 */
524#define hts221HygrometerSetBias(devp, bp) \
525 hygrometerSetBias(&((devp)->hygro_if), bp)
526
527/**
528 * @brief Reset bias values for the BaseHygrometer.
529 * @note Default biases value are obtained from device datasheet when
530 * available otherwise they are considered zero.
531 *
532 * @param[in] devp pointer to @p HTS221Driver.
533 *
534 * @return The operation status.
535 * @retval MSG_OK if the function succeeded.
536 *
537 * @api
538 */
539#define hts221HygrometerResetBias(devp) \
540 hygrometerResetBias(&((devp)->hygro_if))
541
542/**
543 * @brief Set sensitivity values for the BaseHygrometer.
544 * @note Sensitivity must be expressed as %rH/LSB.
545 * @note The sensitivity buffer must be at least the same size of the
546 * BaseHygrometer axes number.
547 *
548 * @param[in] devp pointer to @p HTS221Driver.
549 * @param[in] sp a buffer which contains sensitivities.
550 *
551 * @return The operation status.
552 * @retval MSG_OK if the function succeeded.
553 *
554 * @api
555 */
556#define hts221HygrometerSetSensitivity(devp, sp) \
557 hygrometerSetSensitivity(&((devp)->hygro_if), sp)
558
559/**
560 * @brief Reset sensitivity values for the BaseHygrometer.
561 * @note Default sensitivities value are obtained from device datasheet.
562 *
563 * @param[in] devp pointer to @p HTS221Driver.
564 *
565 * @return The operation status.
566 * @retval MSG_OK if the function succeeded.
567 *
568 * @api
569 */
570#define hts221HygrometerResetSensitivity(devp) \
571 hygrometerResetSensitivity(&((devp)->hygro_if))
572
573/**
574 * @brief Return the number of axes of the BaseThermometer.
575 *
576 * @param[in] devp pointer to @p HTS221Driver.
577 *
578 * @return the number of axes.
579 *
580 * @api
581 */
582#define hts221ThermometerGetAxesNumber(devp) \
583 thermometerGetAxesNumber(&((devp)->thermo_if))
584
585/**
586 * @brief Retrieves raw data from the BaseThermometer.
587 * @note This data is retrieved from MEMS register without any algebraical
588 * manipulation.
589 * @note The axes array must be at least the same size of the
590 * BaseThermometer axes number.
591 *
592 * @param[in] devp pointer to @p HTS221Driver.
593 * @param[out] axes a buffer which would be filled with raw data.
594 *
595 * @return The operation status.
596 * @retval MSG_OK if the function succeeded.
597 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
598 * be retrieved using @p i2cGetErrors().
599 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
600 *
601 * @api
602 */
603#define hts221ThermometerReadRaw(devp, axes) \
604 thermometerReadRaw(&((devp)->thermo_if), axes)
605
606/**
607 * @brief Retrieves cooked data from the BaseThermometer.
608 * @note This data is manipulated according to the formula
609 * cooked = (raw * sensitivity) - bias.
610 * @note Final data is expressed as �C.
611 * @note The axes array must be at least the same size of the
612 * BaseThermometer axes number.
613 *
614 * @param[in] devp pointer to @p HTS221Driver.
615 * @param[out] axes a buffer which would be filled with cooked data.
616 *
617 * @return The operation status.
618 * @retval MSG_OK if the function succeeded.
619 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
620 * be retrieved using @p i2cGetErrors().
621 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
622 *
623 * @api
624 */
625#define hts221ThermometerReadCooked(devp, axes) \
626 thermometerReadCooked(&((devp)->thermo_if), axes)
627
628/**
629 * @brief Set bias values for the BaseThermometer.
630 * @note Bias must be expressed as �C.
631 * @note The bias buffer must be at least the same size of the
632 * BaseThermometer axes number.
633 *
634 * @param[in] devp pointer to @p HTS221Driver.
635 * @param[in] bp a buffer which contains biases.
636 *
637 * @return The operation status.
638 * @retval MSG_OK if the function succeeded.
639 *
640 * @api
641 */
642#define hts221ThermometerSetBias(devp, bp) \
643 thermometerSetBias(&((devp)->thermo_if), bp)
644
645/**
646 * @brief Reset bias values for the BaseThermometer.
647 * @note Default biases value are obtained from device datasheet when
648 * available otherwise they are considered zero.
649 *
650 * @param[in] devp pointer to @p HTS221Driver.
651 *
652 * @return The operation status.
653 * @retval MSG_OK if the function succeeded.
654 *
655 * @api
656 */
657#define hts221ThermometerResetBias(devp) \
658 thermometerResetBias(&((devp)->thermo_if))
659
660/**
661 * @brief Set sensitivity values for the BaseThermometer.
662 * @note Sensitivity must be expressed as �C/LSB.
663 * @note The sensitivity buffer must be at least the same size of the
664 * BaseThermometer axes number.
665 *
666 * @param[in] devp pointer to @p HTS221Driver.
667 * @param[in] sp a buffer which contains sensitivities.
668 *
669 * @return The operation status.
670 * @retval MSG_OK if the function succeeded.
671 *
672 * @api
673 */
674#define hts221ThermometerSetSensitivity(devp, sp) \
675 thermometerSetSensitivity(&((devp)->thermo_if), sp)
676
677/**
678 * @brief Reset sensitivity values for the BaseThermometer.
679 * @note Default sensitivities value are obtained from device datasheet.
680 *
681 * @param[in] devp pointer to @p HTS221Driver.
682 *
683 * @return The operation status.
684 * @retval MSG_OK if the function succeeded.
685 *
686 * @api
687 */
688#define hts221ThermometerResetSensitivity(devp) \
689 thermometerResetSensitivity(&((devp)->thermo_if))
690
691/*===========================================================================*/
692/* External declarations. */
693/*===========================================================================*/
694
695#ifdef __cplusplus
696extern "C" {
697#endif
698 void hts221ObjectInit(HTS221Driver *devp);
699 void hts221Start(HTS221Driver *devp, const HTS221Config *config);
700 void hts221Stop(HTS221Driver *devp);
701#ifdef __cplusplus
702}
703#endif
704
705#endif /* _HTS221_H_ */
706
707/** @} */
diff --git a/lib/chibios/os/ex/devices/ST/hts221.mk b/lib/chibios/os/ex/devices/ST/hts221.mk
new file mode 100644
index 000000000..49bcfeb08
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/hts221.mk
@@ -0,0 +1,10 @@
1# List of all the HTS221 device files.
2HTS221SRC := $(CHIBIOS)/os/ex/devices/ST/hts221.c
3
4# Required include directories
5HTS221INC := $(CHIBIOS)/os/ex/include \
6 $(CHIBIOS)/os/ex/devices/ST
7
8# Shared variables
9ALLCSRC += $(HTS221SRC)
10ALLINC += $(HTS221INC) \ No newline at end of file
diff --git a/lib/chibios/os/ex/devices/ST/l3gd20.c b/lib/chibios/os/ex/devices/ST/l3gd20.c
new file mode 100644
index 000000000..82f5d544d
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/l3gd20.c
@@ -0,0 +1,642 @@
1/*
2 ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi
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 l3gd20.c
23 * @brief L3GD20 MEMS interface module code.
24 *
25 * @addtogroup L3GD20
26 * @ingroup EX_ST
27 * @{
28 */
29
30#include "hal.h"
31#include "l3gd20.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 (L3GD20_USE_SPI) || defined(__DOXYGEN__)
50/**
51 * @brief Reads a generic register value using SPI.
52 * @pre The SPI interface must be initialized and the driver started.
53 *
54 * @param[in] spip pointer to the SPI interface
55 * @param[in] reg starting register address
56 * @param[in] n number of consecutive registers to read
57 * @param[in] b pointer to an output buffer.
58 */
59static void l3gd20SPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n,
60 uint8_t* b) {
61 uint8_t cmd;
62 (n == 1) ? (cmd = reg | L3GD20_RW) : (cmd = reg | L3GD20_RW | L3GD20_MS);
63 spiSelect(spip);
64 spiSend(spip, 1, &cmd);
65 spiReceive(spip, n, b);
66 spiUnselect(spip);
67}
68
69/**
70 * @brief Writes a value into a generic register using SPI.
71 * @pre The SPI interface must be initialized and the driver started.
72 *
73 * @param[in] spip pointer to the SPI interface
74 * @param[in] reg starting register address
75 * @param[in] n number of adjacent registers to write
76 * @param[in] b pointer to a buffer of values.
77 */
78static void l3gd20SPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n,
79 uint8_t* b) {
80 uint8_t cmd;
81 (n == 1) ? (cmd = reg) : (cmd = reg | L3GD20_MS);
82 spiSelect(spip);
83 spiSend(spip, 1, &cmd);
84 spiSend(spip, n, b);
85 spiUnselect(spip);
86}
87#endif /* L3GD20_USE_SPI */
88
89/**
90 * @brief Return the number of axes of the BaseGyroscope.
91 *
92 * @param[in] ip pointer to @p BaseGyroscope interface.
93 *
94 * @return the number of axes.
95 */
96static size_t gyro_get_axes_number(void *ip) {
97 (void)ip;
98
99 return L3GD20_GYRO_NUMBER_OF_AXES;
100}
101
102/**
103 * @brief Retrieves raw data from the BaseGyroscope.
104 * @note This data is retrieved from MEMS register without any algebraical
105 * manipulation.
106 * @note The axes array must be at least the same size of the
107 * BaseGyroscope axes number.
108 *
109 * @param[in] ip pointer to @p BaseGyroscope interface.
110 * @param[out] axes a buffer which would be filled with raw data.
111 *
112 * @return The operation status.
113 * @retval MSG_OK if the function succeeded.
114 */
115static msg_t gyro_read_raw(void *ip, int32_t axes[L3GD20_GYRO_NUMBER_OF_AXES]) {
116 L3GD20Driver* devp;
117 int16_t tmp;
118 uint8_t i, buff [2 * L3GD20_GYRO_NUMBER_OF_AXES];
119 msg_t msg = MSG_OK;
120
121 osalDbgCheck((ip != NULL) && (axes != NULL));
122
123 /* Getting parent instance pointer.*/
124 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
125
126 osalDbgAssert((devp->state == L3GD20_READY),
127 "gyro_read_raw(), invalid state");
128#if L3GD20_USE_SPI
129 osalDbgAssert((devp->config->spip->state == SPI_READY),
130 "gyro_read_raw(), channel not ready");
131
132#if L3GD20_SHARED_SPI
133 spiAcquireBus(devp->config->spip);
134 spiStart(devp->config->spip,
135 devp->config->spicfg);
136#endif /* L3GD20_SHARED_SPI */
137
138 l3gd20SPIReadRegister(devp->config->spip, L3GD20_AD_OUT_X_L,
139 L3GD20_GYRO_NUMBER_OF_AXES * 2, buff);
140
141#if L3GD20_SHARED_SPI
142 spiReleaseBus(devp->config->spip);
143#endif /* L3GD20_SHARED_SPI */
144#endif /* L3GD20_USE_SPI */
145
146 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
147 tmp = buff[2 * i] + (buff[2 * i + 1] << 8);
148 axes[i] = (int32_t)tmp;
149 }
150 return msg;
151}
152
153/**
154 * @brief Retrieves cooked data from the BaseGyroscope.
155 * @note This data is manipulated according to the formula
156 * cooked = (raw * sensitivity) - bias.
157 * @note Final data is expressed as DPS.
158 * @note The axes array must be at least the same size of the
159 * BaseGyroscope axes number.
160 *
161 * @param[in] ip pointer to @p BaseGyroscope interface.
162 * @param[out] axes a buffer which would be filled with cooked data.
163 *
164 * @return The operation status.
165 * @retval MSG_OK if the function succeeded.
166 */
167static msg_t gyro_read_cooked(void *ip, float axes[]) {
168 L3GD20Driver* devp;
169 uint32_t i;
170 int32_t raw[L3GD20_GYRO_NUMBER_OF_AXES];
171 msg_t msg;
172
173 osalDbgCheck((ip != NULL) && (axes != NULL));
174
175 /* Getting parent instance pointer.*/
176 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
177
178 osalDbgAssert((devp->state == L3GD20_READY),
179 "gyro_read_cooked(), invalid state");
180
181 msg = gyro_read_raw(ip, raw);
182 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++){
183 axes[i] = (raw[i] * devp->gyrosensitivity[i]) - devp->gyrobias[i];
184 }
185 return msg;
186}
187
188/**
189 * @brief Samples bias values for the BaseGyroscope.
190 * @note The L3GD20 shall not be moved during the whole procedure.
191 * @note After this function internal bias is automatically updated.
192 * @note The behavior of this function depends on @p L3GD20_BIAS_ACQ_TIMES
193 * and @p L3GD20_BIAS_SETTLING_US.
194 *
195 * @param[in] ip pointer to @p BaseGyroscope interface.
196 *
197 * @return The operation status.
198 * @retval MSG_OK if the function succeeded.
199 */
200static msg_t gyro_sample_bias(void *ip) {
201 L3GD20Driver* devp;
202 uint32_t i, j;
203 int32_t raw[L3GD20_GYRO_NUMBER_OF_AXES];
204 int32_t buff[L3GD20_GYRO_NUMBER_OF_AXES] = {0, 0, 0};
205 msg_t msg;
206
207 osalDbgCheck(ip != NULL);
208
209 /* Getting parent instance pointer.*/
210 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
211
212 osalDbgAssert((devp->state == L3GD20_READY),
213 "gyro_sample_bias(), invalid state");
214#if L3GD20_USE_SPI
215 osalDbgAssert((devp->config->spip->state == SPI_READY),
216 "gyro_sample_bias(), channel not ready");
217#endif
218
219 for(i = 0; i < L3GD20_BIAS_ACQ_TIMES; i++){
220 msg = gyro_read_raw(ip, raw);
221 if(msg != MSG_OK)
222 return msg;
223 for(j = 0; j < L3GD20_GYRO_NUMBER_OF_AXES; j++){
224 buff[j] += raw[j];
225 }
226 osalThreadSleepMicroseconds(L3GD20_BIAS_SETTLING_US);
227 }
228
229 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++){
230 devp->gyrobias[i] = (buff[i] / L3GD20_BIAS_ACQ_TIMES);
231 devp->gyrobias[i] *= devp->gyrosensitivity[i];
232 }
233 return msg;
234}
235
236/**
237 * @brief Set bias values for the BaseGyroscope.
238 * @note Bias must be expressed as DPS.
239 * @note The bias buffer must be at least the same size of the BaseGyroscope
240 * axes number.
241 *
242 * @param[in] ip pointer to @p BaseGyroscope interface.
243 * @param[in] bp a buffer which contains biases.
244 *
245 * @return The operation status.
246 * @retval MSG_OK if the function succeeded.
247 */
248static msg_t gyro_set_bias(void *ip, float *bp) {
249 L3GD20Driver* devp;
250 uint32_t i;
251 msg_t msg = MSG_OK;
252
253 osalDbgCheck((ip != NULL) && (bp != NULL));
254
255 /* Getting parent instance pointer.*/
256 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
257
258 osalDbgAssert((devp->state == L3GD20_READY),
259 "gyro_set_bias(), invalid state");
260
261 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
262 devp->gyrobias[i] = bp[i];
263 }
264 return msg;
265}
266
267/**
268 * @brief Reset bias values for the BaseGyroscope.
269 * @note Default biases value are obtained from device datasheet when
270 * available otherwise they are considered zero.
271 *
272 * @param[in] ip pointer to @p BaseGyroscope interface.
273 *
274 * @return The operation status.
275 * @retval MSG_OK if the function succeeded.
276 */
277static msg_t gyro_reset_bias(void *ip) {
278 L3GD20Driver* devp;
279 uint32_t i;
280 msg_t msg = MSG_OK;
281
282 osalDbgCheck(ip != NULL);
283
284 /* Getting parent instance pointer.*/
285 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
286
287 osalDbgAssert((devp->state == L3GD20_READY),
288 "gyro_reset_bias(), invalid state");
289
290 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++)
291 devp->gyrobias[i] = L3GD20_GYRO_BIAS;
292 return msg;
293}
294
295/**
296 * @brief Set sensitivity values for the BaseGyroscope.
297 * @note Sensitivity must be expressed as DPS/LSB.
298 * @note The sensitivity buffer must be at least the same size of the
299 * BaseGyroscope axes number.
300 *
301 * @param[in] ip pointer to @p BaseGyroscope interface.
302 * @param[in] sp a buffer which contains sensitivities.
303 *
304 * @return The operation status.
305 * @retval MSG_OK if the function succeeded.
306 */
307static msg_t gyro_set_sensivity(void *ip, float *sp) {
308 L3GD20Driver* devp;
309 uint32_t i;
310 msg_t msg = MSG_OK;
311
312 osalDbgCheck((ip != NULL) && (sp !=NULL));
313
314 /* Getting parent instance pointer.*/
315 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
316
317 osalDbgAssert((devp->state == L3GD20_READY),
318 "gyro_set_sensivity(), invalid state");
319
320 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
321 devp->gyrosensitivity[i] = sp[i];
322 }
323 return msg;
324}
325
326/**
327 * @brief Reset sensitivity values for the BaseGyroscope.
328 * @note Default sensitivities value are obtained from device datasheet.
329 *
330 * @param[in] ip pointer to @p BaseGyroscope interface.
331 *
332 * @return The operation status.
333 * @retval MSG_OK if the function succeeded.
334 * @retval MSG_RESET otherwise.
335 */
336static msg_t gyro_reset_sensivity(void *ip) {
337 L3GD20Driver* devp;
338 uint32_t i;
339 msg_t msg = MSG_OK;
340
341 osalDbgCheck(ip != NULL);
342
343 /* Getting parent instance pointer.*/
344 devp = objGetInstance(L3GD20Driver*, (BaseGyroscope*)ip);
345
346 osalDbgAssert((devp->state == L3GD20_READY),
347 "gyro_reset_sensivity(), invalid state");
348
349 if(devp->config->gyrofullscale == L3GD20_FS_250DPS)
350 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++)
351 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_250DPS;
352 else if(devp->config->gyrofullscale == L3GD20_FS_500DPS)
353 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++)
354 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_500DPS;
355 else if(devp->config->gyrofullscale == L3GD20_FS_2000DPS)
356 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++)
357 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_2000DPS;
358 else {
359 osalDbgAssert(FALSE, "gyro_reset_sensivity(), full scale issue");
360 return MSG_RESET;
361 }
362 return msg;
363}
364
365/**
366 * @brief Changes the L3GD20Driver gyroscope fullscale value.
367 * @note This function also rescale sensitivities and biases based on
368 * previous and next fullscale value.
369 * @note A recalibration is highly suggested after calling this function.
370 *
371 * @param[in] devp pointer to @p BaseGyroscope interface.
372 * @param[in] fs new fullscale value.
373 *
374 * @return The operation status.
375 * @retval MSG_OK if the function succeeded.
376 * @retval MSG_RESET otherwise.
377 */
378static msg_t gyro_set_full_scale(L3GD20Driver *devp, l3gd20_fs_t fs) {
379 float newfs, scale;
380 uint8_t i, cr;
381 msg_t msg = MSG_OK;
382
383 osalDbgCheck(devp != NULL);
384
385 osalDbgAssert((devp->state == L3GD20_READY),
386 "gyro_set_full_scale(), invalid state");
387#if L3GD20_USE_SPI
388 osalDbgAssert((devp->config->spip->state == SPI_READY),
389 "gyro_set_full_scale(), channel not ready");
390#endif
391
392 if(fs == L3GD20_FS_250DPS) {
393 newfs = L3GD20_250DPS;
394 }
395 else if(fs == L3GD20_FS_500DPS) {
396 newfs = L3GD20_500DPS;
397 }
398 else if(fs == L3GD20_FS_2000DPS) {
399 newfs = L3GD20_2000DPS;
400 }
401 else {
402 return MSG_RESET;
403 }
404
405 if(newfs != devp->gyrofullscale) {
406 scale = newfs / devp->gyrofullscale;
407 devp->gyrofullscale = newfs;
408
409#if L3GD20_USE_SPI
410#if L3GD20_SHARED_SPI
411 spiAcquireBus(devp->config->spip);
412 spiStart(devp->config->spip,
413 devp->config->spicfg);
414#endif /* L3GD20_SHARED_SPI */
415
416 /* Updating register.*/
417 l3gd20SPIReadRegister(devp->config->spip,
418 L3GD20_AD_CTRL_REG4, 1, &cr);
419
420#if L3GD20_SHARED_SPI
421 spiReleaseBus(devp->config->spip);
422#endif /* L3GD20_SHARED_SPI */
423#endif /* L3GD20_USE_SPI */
424 cr &= ~(L3GD20_CTRL_REG4_FS_MASK);
425 cr |= fs;
426
427#if L3GD20_USE_SPI
428#if L3GD20_SHARED_SPI
429 spiAcquireBus(devp->config->spip);
430 spiStart(devp->config->spip,
431 devp->config->spicfg);
432#endif /* L3GD20_SHARED_SPI */
433
434 l3gd20SPIWriteRegister(devp->config->spip,
435 L3GD20_AD_CTRL_REG4, 1, &cr);
436#if L3GD20_SHARED_SPI
437 spiReleaseBus(devp->config->spip);
438#endif /* L3GD20_SHARED_SPI */
439#endif /* L3GD20_USE_SPI */
440
441 /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */
442 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
443 devp->gyrosensitivity[i] *= scale;
444 devp->gyrobias[i] *= scale;
445 }
446 }
447 return msg;
448}
449
450static const struct L3GD20VMT vmt_device = {
451 (size_t)0,
452 gyro_set_full_scale
453};
454
455static const struct BaseGyroscopeVMT vmt_gyroscope = {
456 sizeof(struct L3GD20VMT*),
457 gyro_get_axes_number, gyro_read_raw, gyro_read_cooked,
458 gyro_sample_bias, gyro_set_bias, gyro_reset_bias,
459 gyro_set_sensivity, gyro_reset_sensivity
460};
461
462/*===========================================================================*/
463/* Driver exported functions. */
464/*===========================================================================*/
465
466/**
467 * @brief Initializes an instance.
468 *
469 * @param[out] devp pointer to the @p L3GD20Driver object
470 *
471 * @init
472 */
473void l3gd20ObjectInit(L3GD20Driver *devp) {
474 devp->vmt = &vmt_device;
475 devp->gyro_if.vmt = &vmt_gyroscope;
476
477 devp->config = NULL;
478
479 devp->state = L3GD20_STOP;
480}
481
482/**
483 * @brief Configures and activates L3GD20 Complex Driver peripheral.
484 *
485 * @param[in] devp pointer to the @p L3GD20Driver object
486 * @param[in] config pointer to the @p L3GD20Config object
487 *
488 * @api
489 */
490void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config) {
491 uint32_t i;
492 uint8_t cr[5] = {0, 0, 0, 0, 0};
493 osalDbgCheck((devp != NULL) && (config != NULL));
494
495 osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
496 "l3gd20Start(), invalid state");
497
498 devp->config = config;
499
500 /* Control register 1 configuration block.*/
501 {
502 cr[0] = L3GD20_CTRL_REG1_XEN | L3GD20_CTRL_REG1_YEN |
503 L3GD20_CTRL_REG1_ZEN | L3GD20_CTRL_REG1_PD |
504 devp->config->gyrooutputdatarate;
505#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__)
506 cr[0] |= devp->config->gyrobandwidth;
507#endif
508 }
509
510 /* Control register 2 configuration block.*/
511 {
512#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__)
513 if(devp->config->gyrohpmode != L3GD20_HPM_BYPASSED)
514 cr[1] = devp->config->gyrohpmode | devp->config->gyrohpconfiguration;
515#endif
516 }
517
518 /* Control register 4 configuration block.*/
519 {
520 cr[3] = devp->config->gyrofullscale;
521#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__)
522 cr[3] |= devp->config->gyroblockdataupdate |
523 devp->config->gyroendianness;
524#endif
525 }
526
527 /* Control register 5 configuration block.*/
528 {
529#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__)
530 if((devp->config->gyrohpmode != L3GD20_HPM_BYPASSED)) {
531 cr[4] = L3GD20_CTRL_REG5_HPEN;
532 if(devp->config->gyrolp2mode != L3GD20_LP2M_BYPASSED) {
533 cr[4] |= L3GD20_CTRL_REG5_INT1_SEL1 |
534 L3GD20_CTRL_REG5_OUT_SEL1;
535 }
536 else {
537 cr[4] |= L3GD20_CTRL_REG5_INT1_SEL0 |
538 L3GD20_CTRL_REG5_OUT_SEL0;
539 }
540 }
541#endif
542 }
543
544#if L3GD20_USE_SPI
545#if L3GD20_SHARED_SPI
546 spiAcquireBus(devp->config->spip);
547#endif /* L3GD20_SHARED_SPI */
548 spiStart(devp->config->spip,
549 devp->config->spicfg);
550
551 l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
552 5, cr);
553#if L3GD20_SHARED_SPI
554 spiReleaseBus(devp->config->spip);
555#endif /* L3GD20_SHARED_SPI */
556#endif /* L3GD20_USE_SPI */
557
558 /* Storing sensitivity information according to full scale.*/
559 if(devp->config->gyrofullscale == L3GD20_FS_250DPS) {
560 devp->gyrofullscale = L3GD20_250DPS;
561 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
562 if (devp->config->gyrosensitivity == NULL)
563 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_250DPS;
564 else
565 devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i];
566 }
567 }
568 else if(devp->config->gyrofullscale == L3GD20_FS_500DPS) {
569 devp->gyrofullscale = L3GD20_500DPS;
570 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
571 if (devp->config->gyrosensitivity == NULL)
572 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_500DPS;
573 else
574 devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i];
575 }
576 }
577 else if(devp->config->gyrofullscale == L3GD20_FS_2000DPS) {
578 devp->gyrofullscale = L3GD20_2000DPS;
579 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
580 if (devp->config->gyrosensitivity == NULL)
581 devp->gyrosensitivity[i] = L3GD20_GYRO_SENS_2000DPS;
582 else
583 devp->gyrosensitivity[i] = devp->config->gyrosensitivity[i];
584 }
585 }
586 else
587 osalDbgAssert(FALSE, "l3gd20Start(), full scale issue");
588
589 /* Storing bias information.*/
590 if(devp->config->gyrobias != NULL) {
591 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++) {
592 devp->gyrobias[i] = devp->config->gyrobias[i];
593 }
594 }
595 else {
596 for(i = 0; i < L3GD20_GYRO_NUMBER_OF_AXES; i++)
597 devp->gyrobias[i] = L3GD20_GYRO_BIAS;
598 }
599
600 /* This is the Gyroscope transient recovery time.*/
601 osalThreadSleepMilliseconds(10);
602
603 devp->state = L3GD20_READY;
604}
605
606/**
607 * @brief Deactivates the L3GD20 Complex Driver peripheral.
608 *
609 * @param[in] devp pointer to the @p L3GD20Driver object
610 *
611 * @api
612 */
613void l3gd20Stop(L3GD20Driver *devp) {
614 uint8_t cr1;
615 osalDbgCheck(devp != NULL);
616
617 osalDbgAssert((devp->state == L3GD20_STOP) || (devp->state == L3GD20_READY),
618 "l3gd20Stop(), invalid state");
619
620 if (devp->state == L3GD20_READY) {
621 /* Disabling all axes and enabling power down mode.*/
622 cr1 = 0;
623
624#if L3GD20_USE_SPI
625#if L3GD20_SHARED_SPI
626 spiAcquireBus(devp->config->spip);
627 spiStart(devp->config->spip,
628 devp->config->spicfg);
629#endif /* L3GD20_SHARED_SPI */
630
631 l3gd20SPIWriteRegister(devp->config->spip, L3GD20_AD_CTRL_REG1,
632 1, &cr1);
633 spiStop(devp->config->spip);
634
635#if L3GD20_SHARED_SPI
636 spiReleaseBus(devp->config->spip);
637#endif /* L3GD20_SHARED_SPI */
638#endif /* L3GD20_USE_SPI */
639 }
640 devp->state = L3GD20_STOP;
641}
642/** @} */
diff --git a/lib/chibios/os/ex/devices/ST/l3gd20.h b/lib/chibios/os/ex/devices/ST/l3gd20.h
new file mode 100644
index 000000000..5528ecc05
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/l3gd20.h
@@ -0,0 +1,725 @@
1/*
2 ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi
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 l3gd20.h
23 * @brief L3GD20 MEMS interface module header.
24 *
25 * @addtogroup L3GD20
26 * @ingroup EX_ST
27 * @{
28 */
29#ifndef _L3GD20_H_
30#define _L3GD20_H_
31
32#include "ex_gyroscope.h"
33
34/*===========================================================================*/
35/* Driver constants. */
36/*===========================================================================*/
37
38/**
39 * @name Version identification
40 * @{
41 */
42/**
43 * @brief L3GD20 driver version string.
44 */
45#define EX_L3GD20_VERSION "1.1.2"
46
47/**
48 * @brief L3GD20 driver version major number.
49 */
50#define EX_L3GD20_MAJOR 1
51
52/**
53 * @brief L3GD20 driver version minor number.
54 */
55#define EX_L3GD20_MINOR 1
56
57/**
58 * @brief L3GD20 driver version patch number.
59 */
60#define EX_L3GD20_PATCH 2
61/** @} */
62
63/**
64 * @brief L3GD20 gyroscope system characteristics.
65 * @note Sensitivity is expressed as DPS/LSB whereas DPS stand for Degree
66 * per second [°/s].
67 * @note Bias is expressed as DPS.
68 *
69 * @{
70 */
71#define L3GD20_GYRO_NUMBER_OF_AXES 3U
72
73#define L3GD20_250DPS 250.0f
74#define L3GD20_500DPS 500.0f
75#define L3GD20_2000DPS 2000.0f
76
77#define L3GD20_GYRO_SENS_250DPS 0.00875f
78#define L3GD20_GYRO_SENS_500DPS 0.01750f
79#define L3GD20_GYRO_SENS_2000DPS 0.07000f
80
81#define L3GD20_GYRO_BIAS 0.0f
82/** @} */
83
84/**
85 * @name L3GD20 communication interfaces related bit masks
86 * @{
87 */
88#define L3GD20_DI_MASK 0xFF
89#define L3GD20_DI(n) (1 << n)
90#define L3GD20_AD_MASK 0x3F
91#define L3GD20_AD(n) (1 << n)
92#define L3GD20_MS (1 << 6)
93#define L3GD20_RW (1 << 7)
94/** @} */
95
96/**
97 * @name L3GD20 register addresses
98 * @{
99 */
100#define L3GD20_AD_WHO_AM_I 0x0F
101#define L3GD20_AD_CTRL_REG1 0x20
102#define L3GD20_AD_CTRL_REG2 0x21
103#define L3GD20_AD_CTRL_REG3 0x22
104#define L3GD20_AD_CTRL_REG4 0x23
105#define L3GD20_AD_CTRL_REG5 0x24
106#define L3GD20_AD_REFERENCE 0x25
107#define L3GD20_AD_OUT_TEMP 0x26
108#define L3GD20_AD_STATUS_REG 0x27
109#define L3GD20_AD_OUT_X_L 0x28
110#define L3GD20_AD_OUT_X_H 0x29
111#define L3GD20_AD_OUT_Y_L 0x2A
112#define L3GD20_AD_OUT_Y_H 0x2B
113#define L3GD20_AD_OUT_Z_L 0x2C
114#define L3GD20_AD_OUT_Z_H 0x2D
115#define L3GD20_AD_FIFO_CTRL_REG 0x2E
116#define L3GD20_AD_FIFO_SRC_REG 0x2F
117#define L3GD20_AD_INT1_CFG 0x30
118#define L3GD20_AD_INT1_SRC 0x31
119#define L3GD20_AD_INT1_THS_XH 0x32
120#define L3GD20_AD_INT1_THS_XL 0x33
121#define L3GD20_AD_INT1_THS_YH 0x34
122#define L3GD20_AD_INT1_THS_YL 0x35
123#define L3GD20_AD_INT1_THS_ZH 0x36
124#define L3GD20_AD_INT1_THS_ZL 0x37
125#define L3GD20_AD_INT1_DURATION 0x38
126/** @} */
127
128/**
129 * @name L3GD20_CTRL_REG1 register bits definitions
130 * @{
131 */
132#define L3GD20_CTRL_REG1_MASK 0xFF
133#define L3GD20_CTRL_REG1_XEN (1 << 0)
134#define L3GD20_CTRL_REG1_YEN (1 << 1)
135#define L3GD20_CTRL_REG1_ZEN (1 << 2)
136#define L3GD20_CTRL_REG1_PD (1 << 3)
137#define L3GD20_CTRL_REG1_BW0 (1 << 4)
138#define L3GD20_CTRL_REG1_BW1 (1 << 5)
139#define L3GD20_CTRL_REG1_DR0 (1 << 6)
140#define L3GD20_CTRL_REG1_DR1 (1 << 7)
141/** @} */
142
143/**
144 * @name L3GD20_CTRL_REG2 register bits definitions
145 * @{
146 */
147#define L3GD20_CTRL_REG2_MASK 0x3F
148#define L3GD20_CTRL_REG2_HPCF0 (1 << 0)
149#define L3GD20_CTRL_REG2_HPCF1 (1 << 1)
150#define L3GD20_CTRL_REG2_HPCF2 (1 << 2)
151#define L3GD20_CTRL_REG2_HPCF3 (1 << 3)
152#define L3GD20_CTRL_REG2_HPM0 (1 << 4)
153#define L3GD20_CTRL_REG2_HPM1 (1 << 5)
154/** @} */
155
156/**
157 * @name L3GD20_CTRL_REG3 register bits definitions
158 * @{
159 */
160#define L3GD20_CTRL_REG3_MASK 0xFF
161#define L3GD20_CTRL_REG3_I2_EMPTY (1 << 0)
162#define L3GD20_CTRL_REG3_I2_ORUN (1 << 1)
163#define L3GD20_CTRL_REG3_I2_WTM (1 << 2)
164#define L3GD20_CTRL_REG3_I2_DRDY (1 << 3)
165#define L3GD20_CTRL_REG3_PP_OD (1 << 4)
166#define L3GD20_CTRL_REG3_H_LACTIVE (1 << 5)
167#define L3GD20_CTRL_REG3_I1_BOOT (1 << 6)
168#define L3GD20_CTRL_REG3_I1_INT1 (1 << 7)
169/** @} */
170
171/**
172 * @name L3GD20_CTRL_REG4 register bits definitions
173 * @{
174 */
175#define L3GD20_CTRL_REG4_MASK 0xF1
176#define L3GD20_CTRL_REG4_SIM (1 << 0)
177#define L3GD20_CTRL_REG4_FS_MASK 0x30
178#define L3GD20_CTRL_REG4_FS0 (1 << 4)
179#define L3GD20_CTRL_REG4_FS1 (1 << 5)
180#define L3GD20_CTRL_REG4_BLE (1 << 6)
181#define L3GD20_CTRL_REG4_BDU (1 << 7)
182/** @} */
183
184/**
185 * @name L3GD20_CTRL_REG5 register bits definitions
186 * @{
187 */
188#define L3GD20_CTRL_REG5_MASK 0xDF
189#define L3GD20_CTRL_REG5_OUT_SEL0 (1 << 0)
190#define L3GD20_CTRL_REG5_OUT_SEL1 (1 << 1)
191#define L3GD20_CTRL_REG5_INT1_SEL0 (1 << 2)
192#define L3GD20_CTRL_REG5_INT1_SEL1 (1 << 3)
193#define L3GD20_CTRL_REG5_HPEN (1 << 4)
194#define L3GD20_CTRL_REG5_FIFO_EN (1 << 6)
195#define L3GD20_CTRL_REG5_BOOT (1 << 7)
196/** @} */
197
198/**
199 * @name L3GD20_INT1_CFG register bits definitions
200 * @{
201 */
202#define L3GD20_INT1_CFG_MASK 0xFF
203#define L3GD20_INT1_CFG_XLIE (1 << 0)
204#define L3GD20_INT1_CFG_XHIE (1 << 1)
205#define L3GD20_INT1_CFG_YLIE (1 << 2)
206#define L3GD20_INT1_CFG_YHIE (1 << 3)
207#define L3GD20_INT1_CFG_ZLIE (1 << 4)
208#define L3GD20_INT1_CFG_ZHIE (1 << 5)
209#define L3GD20_INT1_CFG_LIR (1 << 6)
210#define L3GD20_INT1_CFG_AND_OR (1 << 7)
211/** @} */
212
213/**
214 * @name L3GD20_INT1_SRC register bits definitions
215 * @{
216 */
217#define L3GD20_INT1_SRC_MASK 0x7F
218#define L3GD20_INT1_SRC_XL (1 << 0)
219#define L3GD20_INT1_SRC_XH (1 << 1)
220#define L3GD20_INT1_SRC_YL (1 << 2)
221#define L3GD20_INT1_SRC_YH (1 << 3)
222#define L3GD20_INT1_SRC_ZL (1 << 4)
223#define L3GD20_INT1_SRC_ZH (1 << 5)
224#define L3GD20_INT1_SRC_IA (1 << 6)
225/** @} */
226
227/*===========================================================================*/
228/* Driver pre-compile time settings. */
229/*===========================================================================*/
230
231/**
232 * @name Configuration options
233 * @{
234 */
235/**
236 * @brief L3GD20 SPI interface switch.
237 * @details If set to @p TRUE the support for SPI is included.
238 * @note The default is @p TRUE.
239 */
240#if !defined(L3GD20_USE_SPI) || defined(__DOXYGEN__)
241#define L3GD20_USE_SPI TRUE
242#endif
243
244/**
245 * @brief L3GD20 shared SPI switch.
246 * @details If set to @p TRUE the device acquires SPI bus ownership
247 * on each transaction.
248 * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION.
249 */
250#if !defined(L3GD20_SHARED_SPI) || defined(__DOXYGEN__)
251#define L3GD20_SHARED_SPI FALSE
252#endif
253
254/**
255 * @brief L3GD20 I2C interface switch.
256 * @details If set to @p TRUE the support for I2C is included.
257 * @note The default is @p FALSE.
258 */
259#if !defined(L3GD20_USE_I2C) || defined(__DOXYGEN__)
260#define L3GD20_USE_I2C FALSE
261#endif
262
263/**
264 * @brief L3GD20 shared I2C switch.
265 * @details If set to @p TRUE the device acquires I2C bus ownership
266 * on each transaction.
267 * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION.
268 */
269#if !defined(L3GD20_SHARED_I2C) || defined(__DOXYGEN__)
270#define L3GD20_SHARED_I2C FALSE
271#endif
272
273/**
274 * @brief L3GD20 advanced configurations switch.
275 * @details If set to @p TRUE more configurations are available.
276 * @note The default is @p FALSE.
277 */
278#if !defined(L3GD20_USE_ADVANCED) || defined(__DOXYGEN__)
279#define L3GD20_USE_ADVANCED FALSE
280#endif
281
282/**
283 * @brief Number of acquisitions for bias removal
284 * @details This is the number of acquisitions performed to compute the
285 * bias. A repetition is required in order to remove noise.
286 */
287#if !defined(L3GD20_BIAS_ACQ_TIMES) || defined(__DOXYGEN__)
288#define L3GD20_BIAS_ACQ_TIMES 50
289#endif
290
291/**
292 * @brief Settling time for bias removal
293 * @details This is the time between each bias acquisition.
294 */
295#if !defined(L3GD20_BIAS_SETTLING_US) || defined(__DOXYGEN__)
296#define L3GD20_BIAS_SETTLING_US 5000
297#endif
298/** @} */
299
300/*===========================================================================*/
301/* Derived constants and error checks. */
302/*===========================================================================*/
303
304#if !(L3GD20_USE_SPI ^ L3GD20_USE_I2C)
305#error "L3GD20_USE_SPI and L3GD20_USE_I2C cannot be both true or both false"
306#endif
307
308#if L3GD20_USE_SPI && !HAL_USE_SPI
309#error "L3GD20_USE_SPI requires HAL_USE_SPI"
310#endif
311
312#if L3GD20_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION
313#error "L3GD20_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"
314#endif
315
316#if L3GD20_USE_I2C && !HAL_USE_I2C
317#error "L3GD20_USE_I2C requires HAL_USE_I2C"
318#endif
319
320#if L3GD20_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION
321#error "L3GD20_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION"
322#endif
323
324/*
325 * CHTODO: Add support for L3GD20 over I2C.
326 */
327#if L3GD20_USE_I2C
328#error "L3GD20 over I2C still not supported"
329#endif
330
331/*===========================================================================*/
332/* Driver data structures and types. */
333/*===========================================================================*/
334
335/**
336 * @name L3GD20 data structures and types.
337 * @{
338 */
339/**
340 * @brief Structure representing a L3GD20 driver.
341 */
342typedef struct L3GD20Driver L3GD20Driver;
343
344/**
345 * @brief L3GD20 full scale.
346 */
347typedef enum {
348 L3GD20_FS_250DPS = 0x00, /**< Full scale 250 degree per second. */
349 L3GD20_FS_500DPS = 0x10, /**< Full scale 500 degree per second. */
350 L3GD20_FS_2000DPS = 0x20 /**< Full scale 2000 degree per second. */
351} l3gd20_fs_t;
352
353/**
354 * @brief L3GD20 output data rate and bandwidth.
355 */
356typedef enum {
357 L3GD20_ODR_95HZ = 0x00, /**< Output data rate 95 Hz. */
358 L3GD20_ODR_190HZ = 0x40, /**< Output data rate 190 Hz. */
359 L3GD20_ODR_380HZ = 0x80, /**< Output data rate 380 Hz. */
360 L3GD20_ODR_760HZ = 0xC0 /**< Output data rate 760 Hz. */
361} l3gd20_odr_t;
362
363/**
364 * @brief L3GD20 low pass filter 1 bandwidth.
365 */
366typedef enum {
367 L3GD20_BW0 = 0x00, /**< LPF1 bandwidth. Depends on ODR. */
368 L3GD20_BW1 = 0x40, /**< LPF1 bandwidth. Depends on ODR. */
369 L3GD20_BW2 = 0x80, /**< LPF1 bandwidth. Depends on ODR. */
370 L3GD20_BW3 = 0xC0 /**< LPF1 bandwidth. Depends on ODR. */
371} l3gd20_bw_t;
372
373/**
374 * @brief L3GD20 block data update.
375 */
376typedef enum {
377 L3GD20_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */
378 L3GD20_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */
379} l3gd20_bdu_t;
380
381/**
382 * @brief L3GD20 HP filter mode.
383 */
384typedef enum {
385 L3GD20_HPM_NORMAL = 0x00, /**< Normal mode. */
386 L3GD20_HPM_REFERENCE = 0x10, /**< Reference signal for filtering. */
387 L3GD20_HPM_AUTORESET = 0x30, /**< Autoreset on interrupt event. */
388 L3GD20_HPM_BYPASSED = 0xFF /**< HP filter bypassed */
389} l3gd20_hpm_t;
390
391/**
392 * @brief L3GD20 HP configuration.
393 */
394typedef enum {
395 L3GD20_HPCF_0 = 0x00, /**< Depends on ODR (Table 26 for more).*/
396 L3GD20_HPCF_1 = 0x01, /**< Depends on ODR (Table 26 for more).*/
397 L3GD20_HPCF_2 = 0x02, /**< Depends on ODR (Table 26 for more).*/
398 L3GD20_HPCF_3 = 0x03, /**< Depends on ODR (Table 26 for more).*/
399 L3GD20_HPCF_4 = 0x04, /**< Depends on ODR (Table 26 for more).*/
400 L3GD20_HPCF_5 = 0x05, /**< Depends on ODR (Table 26 for more).*/
401 L3GD20_HPCF_6 = 0x06, /**< Depends on ODR (Table 26 for more).*/
402 L3GD20_HPCF_7 = 0x07, /**< Depends on ODR (Table 26 for more).*/
403 L3GD20_HPCF_8 = 0x08, /**< Depends on ODR (Table 26 for more).*/
404 L3GD20_HPCF_9 = 0x09 /**< Depends on ODR (Table 26 for more).*/
405} l3gd20_hpcf_t;
406
407/**
408 * @brief L3GD20 LP2 filter mode.
409 * @details To activate LP2 HP should be active
410 */
411typedef enum {
412 L3GD20_LP2M_ON = 0x00, /**< LP2 filter activated. */
413 L3GD20_LP2M_BYPASSED = 0xFF, /**< LP2 filter bypassed. */
414} l3gd20_lp2m_t;
415
416/**
417 * @brief L3GD20 endianness.
418 */
419typedef enum {
420 L3GD20_END_LITTLE = 0x00, /**< Little endian. */
421 L3GD20_END_BIG = 0x40 /**< Big endian. */
422} l3gd20_end_t;
423
424/**
425 * @brief Driver state machine possible states.
426 */
427typedef enum {
428 L3GD20_UNINIT = 0, /**< Not initialized. */
429 L3GD20_STOP = 1, /**< Stopped. */
430 L3GD20_READY = 2 /**< Ready. */
431} l3gd20_state_t;
432
433/**
434 * @brief L3GD20 configuration structure.
435 */
436typedef struct {
437
438#if L3GD20_USE_SPI || defined(__DOXYGEN__)
439 /**
440 * @brief SPI driver associated to this L3GD20.
441 */
442 SPIDriver *spip;
443 /**
444 * @brief SPI configuration associated to this L3GD20.
445 */
446 const SPIConfig *spicfg;
447#endif /* L3GD20_USE_SPI */
448#if L3GD20_USE_I2C || defined(__DOXYGEN__)
449 /**
450 * @brief I2C driver associated to this L3GD20.
451 */
452 I2CDriver *i2cp;
453 /**
454 * @brief I2C configuration associated to this L3GD20.
455 */
456 const I2CConfig *i2ccfg;
457#endif /* L3GD20_USE_I2C */
458 /**
459 * @brief L3GD20 gyroscope system initial sensitivity.
460 */
461 float *gyrosensitivity;
462 /**
463 * @brief L3GD20 gyroscope system initial bias.
464 */
465 float *gyrobias;
466 /**
467 * @brief L3GD20 gyroscope system initial full scale value.
468 */
469 l3gd20_fs_t gyrofullscale;
470 /**
471 * @brief L3GD20 gyroscope system output data rate selection.
472 */
473 l3gd20_odr_t gyrooutputdatarate;
474#if L3GD20_USE_ADVANCED || defined(__DOXYGEN__)
475 /**
476 * @brief L3GD20 gyroscope system block data update.
477 */
478 l3gd20_bdu_t gyroblockdataupdate;
479 /**
480 * @brief L3GD20 gyroscope system endianness.
481 */
482 l3gd20_end_t gyroendianness;
483 /**
484 * @brief L3GD20 gyroscope system LP1 filter bandwidth.
485 */
486 l3gd20_bw_t gyrobandwidth;
487 /**
488 * @brief L3GD20 gyroscope system HP filter mode.
489 */
490 l3gd20_hpm_t gyrohpmode;
491 /**
492 * @brief L3GD20 gyroscope system HP configuration.
493 */
494 l3gd20_hpcf_t gyrohpconfiguration;
495 /**
496 * @brief L3GD20 gyroscope system LP2 filter mode.
497 * @details To activate LP2 HP should be active
498 */
499 l3gd20_lp2m_t gyrolp2mode;
500#endif
501} L3GD20Config;
502
503/**
504 * @brief @p L3GD20 specific methods.
505 */
506#define _l3gd20_methods_alone \
507 /* Change full scale value of L3GD20.*/ \
508 msg_t (*gyro_set_full_scale)(L3GD20Driver *devp, l3gd20_fs_t fs);
509
510/**
511 * @brief @p L3GD20 specific methods with inherited ones.
512 */
513#define _l3gd20_methods \
514 _base_object_methods \
515 _l3gd20_methods_alone
516
517/**
518 * @extends BaseObjectVMT
519 *
520 * @brief @p L3GD20 virtual methods table.
521 */
522struct L3GD20VMT {
523 _l3gd20_methods
524};
525
526/**
527 * @brief @p L3GD20Driver specific data.
528 */
529#define _l3gd20_data \
530 _base_sensor_data \
531 /* Driver state.*/ \
532 l3gd20_state_t state; \
533 /* Current configuration data.*/ \
534 const L3GD20Config *config; \
535 /* Gyroscope subsystem axes number.*/ \
536 size_t gyroaxes; \
537 /* Gyroscope subsystem current sensitivity.*/ \
538 float gyrosensitivity[L3GD20_GYRO_NUMBER_OF_AXES]; \
539 /* Gyroscope subsystem current Bias.*/ \
540 float gyrobias[L3GD20_GYRO_NUMBER_OF_AXES]; \
541 /* Gyroscope subsystem current full scale value.*/ \
542 float gyrofullscale;
543
544/**
545 * @brief L3GD20 3-axis gyroscope class.
546 */
547struct L3GD20Driver {
548 /** @brief Virtual Methods Table. */
549 const struct L3GD20VMT *vmt;
550 /** @brief Base gyroscope interface.*/
551 BaseGyroscope gyro_if;
552 _l3gd20_data
553};
554/** @} */
555
556/*===========================================================================*/
557/* Driver macros. */
558/*===========================================================================*/
559
560/**
561 * @brief Return the number of axes of the BaseGyroscope.
562 *
563 * @param[in] devp pointer to @p L3GD20Driver.
564 *
565 * @return the number of axes.
566 *
567 * @api
568 */
569#define l3gd20GyroscopeGetAxesNumber(devp) \
570 gyroscopeGetAxesNumber(&((devp)->gyro_if))
571
572/**
573 * @brief Retrieves raw data from the BaseGyroscope.
574 * @note This data is retrieved from MEMS register without any algebraical
575 * manipulation.
576 * @note The axes array must be at least the same size of the
577 * BaseGyroscope axes number.
578 *
579 * @param[in] devp pointer to @p L3GD20Driver.
580 * @param[out] axes a buffer which would be filled with raw data.
581 *
582 * @return The operation status.
583 * @retval MSG_OK if the function succeeded.
584 *
585 * @api
586 */
587#define l3gd20GyroscopeReadRaw(devp, axes) \
588 gyroscopeReadRaw(&((devp)->gyro_if), axes)
589
590/**
591 * @brief Retrieves cooked data from the BaseGyroscope.
592 * @note This data is manipulated according to the formula
593 * cooked = (raw * sensitivity) - bias.
594 * @note Final data is expressed as DPS.
595 * @note The axes array must be at least the same size of the
596 * BaseGyroscope axes number.
597 *
598 * @param[in] devp pointer to @p L3GD20Driver.
599 * @param[out] axes a buffer which would be filled with cooked data.
600 *
601 * @return The operation status.
602 * @retval MSG_OK if the function succeeded.
603 *
604 * @api
605 */
606#define l3gd20GyroscopeReadCooked(devp, axes) \
607 gyroscopeReadCooked(&((devp)->gyro_if), axes)
608
609/**
610 * @brief Samples bias values for the BaseGyroscope.
611 * @note The L3GD20 shall not be moved during the whole procedure.
612 * @note After this function internal bias is automatically updated.
613 * @note The behavior of this function depends on @p L3GD20_BIAS_ACQ_TIMES
614 * and @p L3GD20_BIAS_SETTLING_US.
615 *
616 * @param[in] devp pointer to @p L3GD20Driver.
617 *
618 * @return The operation status.
619 * @retval MSG_OK if the function succeeded.
620 *
621 * @api
622 */
623#define l3gd20GyroscopeSampleBias(devp) \
624 gyroscopeSampleBias(&((devp)->gyro_if))
625
626/**
627 * @brief Set bias values for the BaseGyroscope.
628 * @note Bias must be expressed as DPS.
629 * @note The bias buffer must be at least the same size of the BaseGyroscope
630 * axes number.
631 *
632 * @param[in] devp pointer to @p L3GD20Driver.
633 * @param[in] bp a buffer which contains biases.
634 *
635 * @return The operation status.
636 * @retval MSG_OK if the function succeeded.
637 *
638 * @api
639 */
640#define l3gd20GyroscopeSetBias(devp, bp) \
641 gyroscopeSetBias(&((devp)->gyro_if), bp)
642
643/**
644 * @brief Reset bias values for the BaseGyroscope.
645 * @note Default biases value are obtained from device datasheet when
646 * available otherwise they are considered zero.
647 *
648 * @param[in] devp pointer to @p L3GD20Driver.
649 *
650 * @return The operation status.
651 * @retval MSG_OK if the function succeeded.
652 *
653 * @api
654 */
655#define l3gd20GyroscopeResetBias(devp) \
656 gyroscopeResetBias(&((devp)->gyro_if))
657
658/**
659 * @brief Set sensitivity values for the BaseGyroscope.
660 * @note Sensitivity must be expressed as DPS/LSB.
661 * @note The sensitivity buffer must be at least the same size of the
662 * BaseGyroscope axes number.
663 *
664 * @param[in] devp pointer to @p L3GD20Driver.
665 * @param[in] sp a buffer which contains sensitivities.
666 *
667 * @return The operation status.
668 * @retval MSG_OK if the function succeeded.
669 *
670 * @api
671 */
672#define l3gd20GyroscopeSetSensitivity(devp, sp) \
673 gyroscopeSetSensitivity(&((devp)->gyro_if), sp)
674
675/**
676 * @brief Reset sensitivity values for the BaseGyroscope.
677 * @note Default sensitivities value are obtained from device datasheet.
678 *
679 * @param[in] devp pointer to @p L3GD20Driver.
680 *
681 * @return The operation status.
682 * @retval MSG_OK if the function succeeded.
683 * @retval MSG_RESET otherwise.
684 *
685 * @api
686 */
687#define l3gd20GyroscopeResetSensitivity(devp) \
688 gyroscopeResetSensitivity(&((devp)->gyro_if))
689
690/**
691 * @brief Changes the L3GD20Driver gyroscope fullscale value.
692 * @note This function also rescale sensitivities and biases based on
693 * previous and next fullscale value.
694 * @note A recalibration is highly suggested after calling this function.
695 *
696 * @param[in] devp pointer to @p L3GD20Driver.
697 * @param[in] fs new fullscale value.
698 *
699 * @return The operation status.
700 * @retval MSG_OK if the function succeeded.
701 * @retval MSG_RESET otherwise.
702 *
703 * @api
704 */
705#define l3gd20GyroscopeSetFullScale(devp, fs) \
706 (devp)->vmt->acc_set_full_scale(devp, fs)
707
708/*===========================================================================*/
709/* External declarations. */
710/*===========================================================================*/
711
712#ifdef __cplusplus
713extern "C" {
714#endif
715 void l3gd20ObjectInit(L3GD20Driver *devp);
716 void l3gd20Start(L3GD20Driver *devp, const L3GD20Config *config);
717 void l3gd20Stop(L3GD20Driver *devp);
718#ifdef __cplusplus
719}
720#endif
721
722#endif /* _L3GD20_H_ */
723
724/** @} */
725
diff --git a/lib/chibios/os/ex/devices/ST/l3gd20.mk b/lib/chibios/os/ex/devices/ST/l3gd20.mk
new file mode 100644
index 000000000..b8fae998e
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/l3gd20.mk
@@ -0,0 +1,10 @@
1# List of all the L3GD20 device files.
2L3GD20SRC := $(CHIBIOS)/os/ex/devices/ST/l3gd20.c
3
4# Required include directories
5L3GD20INC := $(CHIBIOS)/os/ex/include \
6 $(CHIBIOS)/os/ex/devices/ST
7
8# Shared variables
9ALLCSRC += $(L3GD20SRC)
10ALLINC += $(L3GD20INC) \ No newline at end of file
diff --git a/lib/chibios/os/ex/devices/ST/lis302dl.c b/lib/chibios/os/ex/devices/ST/lis302dl.c
new file mode 100644
index 000000000..f1e03cacc
--- /dev/null
+++ b/lib/chibios/os/ex/devices/ST/lis302dl.c
@@ -0,0 +1,554 @@
1/*
2 ChibiOS - Copyright (C) 2016..2019 Rocco Marco Guglielmi
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 lis302dl.c
23 * @brief LIS302DL MEMS interface module code.
24 *
25 * @addtogroup LIS302DL
26 * @ingroup EX_ST
27 * @{
28 */
29
30#include "hal.h"
31#include "lis302dl.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 (LIS302DL_USE_SPI) || defined(__DOXYGEN__)
50/**
51 * @brief Reads a generic register value using SPI.
52 * @pre The SPI interface must be initialized and the driver started.
53 *
54 * @param[in] spip pointer to the SPI interface
55 * @param[in] reg starting register address
56 * @param[in] n number of adjacent registers to write
57 * @param[in] b pointer to a buffer.
58 */
59static void lis302dlSPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n,
60 uint8_t* b) {
61 uint8_t cmd;
62 (n == 1) ? (cmd = reg | LIS302DL_RW) : (cmd = reg | LIS302DL_RW | LIS302DL_MS);
63 spiSelect(spip);
64 spiSend(spip, 1, &cmd);
65 spiReceive(spip, n, b);
66 spiUnselect(spip);
67}
68
69/**
70 * @brief Writes a value into a generic register using SPI.
71 * @pre The SPI interface must be initialized and the driver started.
72 *
73 * @param[in] spip pointer to the SPI interface
74 * @param[in] reg starting register address
75 * @param[in] n number of adjacent registers to write
76 * @param[in] b pointer to a buffer of values.
77 */
78static void lis302dlSPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n,
79 uint8_t* b) {
80 uint8_t cmd;
81 (n == 1) ? (cmd = reg) : (cmd = reg | LIS302DL_MS);
82 spiSelect(spip);
83 spiSend(spip, 1, &cmd);
84 spiSend(spip, n, b);
85 spiUnselect(spip);
86}
87#endif /* LIS302DL_USE_SPI */
88
89/**
90 * @brief Return the number of axes of the BaseAccelerometer.
91 *
92 * @param[in] ip pointer to @p BaseAccelerometer interface.
93 *
94 * @return the number of axes.
95 */
96static size_t acc_get_axes_number(void *ip) {
97 (void)ip;
98
99 return LIS302DL_ACC_NUMBER_OF_AXES;
100}
101
102/**
103 * @brief Retrieves raw data from the BaseAccelerometer.
104 * @note This data is retrieved from MEMS register without any algebraical
105 * manipulation.
106 * @note The axes array must be at least the same size of the
107 * BaseAccelerometer axes number.
108 *
109 * @param[in] ip pointer to @p BaseAccelerometer interface.
110 * @param[out] axes a buffer which would be filled with raw data.
111 *
112 * @return The operation status.
113 * @retval MSG_OK if the function succeeded.
114 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
115 * be retrieved using @p i2cGetErrors().
116 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
117 */
118static msg_t acc_read_raw(void *ip, int32_t axes[]) {
119 LIS302DLDriver* devp;
120 uint8_t i, tmp;
121 msg_t msg = MSG_OK;
122
123 osalDbgCheck((ip != NULL) && (axes != NULL));
124
125 /* Getting parent instance pointer.*/
126 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
127
128 osalDbgAssert((devp->state == LIS302DL_READY),
129 "acc_read_raw(), invalid state");
130
131#if LIS302DL_USE_SPI
132#if LIS302DL_SHARED_SPI
133 osalDbgAssert((devp->config->spip->state == SPI_READY),
134 "acc_read_raw(), channel not ready");
135
136 spiAcquireBus(devp->config->spip);
137 spiStart(devp->config->spip,
138 devp->config->spicfg);
139#endif /* LIS302DL_SHARED_SPI */
140
141 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) {
142 lis302dlSPIReadRegister(devp->config->spip,
143 LIS302DL_AD_OUT_X + (i * 2), 1, &tmp);
144 axes[i] = (int32_t)((int8_t)tmp);
145 }
146
147#if LIS302DL_SHARED_SPI
148 spiReleaseBus(devp->config->spip);
149#endif /* LIS302DL_SHARED_SPI */
150#endif /* LIS302DL_USE_SPI */
151 return msg;
152}
153
154/**
155 * @brief Retrieves cooked data from the BaseAccelerometer.
156 * @note This data is manipulated according to the formula
157 * cooked = (raw * sensitivity) - bias.
158 * @note Final data is expressed as milli-G.
159 * @note The axes array must be at least the same size of the
160 * BaseAccelerometer axes number.
161 *
162 * @param[in] ip pointer to @p BaseAccelerometer interface.
163 * @param[out] axes a buffer which would be filled with cooked data.
164 *
165 * @return The operation status.
166 * @retval MSG_OK if the function succeeded.
167 * @retval MSG_RESET if one or more I2C errors occurred, the errors can
168 * be retrieved using @p i2cGetErrors().
169 * @retval MSG_TIMEOUT if a timeout occurred before operation end.
170 */
171static msg_t acc_read_cooked(void *ip, float axes[]) {
172 LIS302DLDriver* devp;
173 uint32_t i;
174 int32_t raw[LIS302DL_ACC_NUMBER_OF_AXES];
175 msg_t msg;
176
177 osalDbgCheck((ip != NULL) && (axes != NULL));
178
179 /* Getting parent instance pointer.*/
180 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
181
182 osalDbgAssert((devp->state == LIS302DL_READY),
183 "acc_read_cooked(), invalid state");
184
185 msg = acc_read_raw(ip, raw);
186 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) {
187 axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i];
188 }
189 return msg;
190}
191
192/**
193 * @brief Set bias values for the BaseAccelerometer.
194 * @note Bias must be expressed as milli-G.
195 * @note The bias buffer must be at least the same size of the
196 * BaseAccelerometer axes number.
197 *
198 * @param[in] ip pointer to @p BaseAccelerometer interface.
199 * @param[in] bp a buffer which contains biases.
200 *
201 * @return The operation status.
202 * @retval MSG_OK if the function succeeded.
203 */
204static msg_t acc_set_bias(void *ip, float *bp) {
205 LIS302DLDriver* devp;
206 uint32_t i;
207 msg_t msg = MSG_OK;
208
209 osalDbgCheck((ip != NULL) && (bp != NULL));
210
211 /* Getting parent instance pointer.*/
212 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
213
214 osalDbgAssert((devp->state == LIS302DL_READY),
215 "acc_set_bias(), invalid state");
216
217 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) {
218 devp->accbias[i] = bp[i];
219 }
220 return msg;
221}
222
223/**
224 * @brief Reset bias values for the BaseAccelerometer.
225 * @note Default biases value are obtained from device datasheet when
226 * available otherwise they are considered zero.
227 *
228 * @param[in] ip pointer to @p BaseAccelerometer interface.
229 *
230 * @return The operation status.
231 * @retval MSG_OK if the function succeeded.
232 */
233static msg_t acc_reset_bias(void *ip) {
234 LIS302DLDriver* devp;
235 uint32_t i;
236 msg_t msg = MSG_OK;
237
238 osalDbgCheck(ip != NULL);
239
240 /* Getting parent instance pointer.*/
241 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
242
243 osalDbgAssert((devp->state == LIS302DL_READY),
244 "acc_reset_bias(), invalid state");
245
246 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++)
247 devp->accbias[i] = LIS302DL_ACC_BIAS;
248 return msg;
249}
250
251/**
252 * @brief Set sensitivity values for the BaseAccelerometer.
253 * @note Sensitivity must be expressed as milli-G/LSB.
254 * @note The sensitivity buffer must be at least the same size of the
255 * BaseAccelerometer axes number.
256 *
257 * @param[in] ip pointer to @p BaseAccelerometer interface.
258 * @param[in] sp a buffer which contains sensitivities.
259 *
260 * @return The operation status.
261 * @retval MSG_OK if the function succeeded.
262 */
263static msg_t acc_set_sensivity(void *ip, float *sp) {
264 LIS302DLDriver* devp;
265 uint32_t i;
266 msg_t msg = MSG_OK;
267
268 /* Getting parent instance pointer.*/
269 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
270
271 osalDbgCheck((ip != NULL) && (sp != NULL));
272
273 osalDbgAssert((devp->state == LIS302DL_READY),
274 "acc_set_sensivity(), invalid state");
275
276 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) {
277 devp->accsensitivity[i] = sp[i];
278 }
279 return msg;
280}
281
282/**
283 * @brief Reset sensitivity values for the BaseAccelerometer.
284 * @note Default sensitivities value are obtained from device datasheet.
285 *
286 * @param[in] ip pointer to @p BaseAccelerometer interface.
287 *
288 * @return The operation status.
289 * @retval MSG_OK if the function succeeded.
290 * @retval MSG_RESET otherwise.
291 */
292static msg_t acc_reset_sensivity(void *ip) {
293 LIS302DLDriver* devp;
294 uint32_t i;
295 msg_t msg = MSG_OK;
296
297 osalDbgCheck(ip != NULL);
298
299 /* Getting parent instance pointer.*/
300 devp = objGetInstance(LIS302DLDriver*, (BaseAccelerometer*)ip);
301
302 osalDbgAssert((devp->state == LIS302DL_READY),
303 "acc_reset_sensivity(), invalid state");
304
305 if(devp->config->accfullscale == LIS302DL_ACC_FS_2G)
306 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++)
307 devp->accsensitivity[i] = LIS302DL_ACC_SENS_2G;
308 else if(devp->config->accfullscale == LIS302DL_ACC_FS_8G)
309 for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++)
310 devp->accsensitivity[i] = LIS302DL_ACC_SENS_8G;
311 else {
312 osalDbgAssert(FALSE,
313 "acc_reset_sensivity(), accelerometer full scale issue");
314 return MSG_RESET;
315 }
316 return msg;
317}
318
319/**
320 * @brief Changes the LIS302DLDriver accelerometer fullscale value.
321 * @note This function also rescale sensitivities and biases based on
322 * previous and next fullscale value.
323 * @note A recalibration is highly suggested after calling this function.
324 *
325 * @param[in] devp pointer to @p LIS302DLDriver interface.
326 * @param[in] fs new fullscale value.
327 *
328 * @return The operation status.
329 * @retval MSG_OK if the function succeeded.
330 * @retval MSG_RESET otherwise.
331 */
332static msg_t acc_set_full_scale(LIS302DLDriver *devp, lis302dl_acc_fs_t fs) {
333 float newfs, scale;
334 uint8_t i, cr;
335 msg_t msg;
336
337 osalDbgCheck(devp != NULL);
338
339 osalDbgAssert((devp->state == LIS302DL_READY),
340 "acc_set_full_scale(), invalid state");
341 osalDbgAssert((devp->config->spip->state == SPI_READY),
342 "acc_set_full_scale(), channel not ready");
343
344 /* Computing new fullscale value.*/
345 if(fs == LIS302DL_ACC_FS_2G) {
346 newfs = LIS302DL_ACC_2G;
347 }
348 else if(fs == LIS302DL_ACC_FS_8G) {
349 newfs = LIS302DL_ACC_8G;
350 }
351 else {
352 msg = MSG_RESET;
353 return msg;
354 }
355
356 if(newfs != devp->accfullscale) {
357 /* Computing scale value.*/
358 scale = newfs / devp->accfullscale;
359 devp->accfullscale = newfs;
360
361#if LIS302DL_USE_SPI
362#if LIS302DL_SHARED_SPI
363 spiAcquireBus(devp->config->spip);
364 spiStart(devp->config->spip,
365 devp->config->spicfg);
366#endif /* LIS302DL_SHARED_SPI */
367
368 /* Getting data from register.*/
369 lis302dlSPIReadRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr);
370
371#if LIS302DL_SHARED_SPI
372 spiReleaseBus(devp->config->spip);
373#endif /* LIS302DL_SHARED_SPI */
374#endif /* LIS302DL_USE_SPI */
375
376 cr &= ~(LIS302DL_CTRL_REG1_FS_MASK);