diff options
author | Akshay <[email protected]> | 2022-04-10 12:13:40 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2022-04-10 12:13:40 +0100 |
commit | dc90387ce7d8ba7b607d9c48540bf6d8b560f14d (patch) | |
tree | 4ccb8fa5886b66fa9d480edef74236c27f035e16 /lib/chibios/os/ex/devices |
Diffstat (limited to 'lib/chibios/os/ex/devices')
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 | */ | ||
71 | msg_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 | */ | ||
92 | msg_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 | */ | ||
108 | static 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 | */ | ||
146 | static 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 | */ | ||
165 | static 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 | */ | ||
202 | static 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 | */ | ||
223 | static 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 | */ | ||
274 | static 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 | */ | ||
311 | static 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 | */ | ||
356 | static 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 | */ | ||
370 | static 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 | */ | ||
384 | static 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 | */ | ||
399 | static 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 | */ | ||
433 | static 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 | */ | ||
467 | static 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 | */ | ||
492 | static 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 | */ | ||
520 | static 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 | */ | ||
545 | static 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 | */ | ||
569 | static 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 | */ | ||
586 | static 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 | */ | ||
602 | static 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 | */ | ||
619 | static 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 | */ | ||
637 | static 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 | */ | ||
654 | static 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 | */ | ||
670 | static 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 | */ | ||
686 | static 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 | |||
695 | static const struct BaseSensorVMT vmt_basesensor = { | ||
696 | sens_get_axes_number, sens_read_raw, sens_read_cooked | ||
697 | }; | ||
698 | |||
699 | static 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 | |||
705 | static 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 | */ | ||
722 | void 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 | */ | ||
739 | void 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 | */ | ||
768 | void 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 | */ | ||
180 | typedef 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 | */ | ||
190 | typedef 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 | */ | ||
200 | typedef 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 | */ | ||
210 | typedef 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 | */ | ||
235 | typedef 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 | */ | ||
252 | typedef 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 | */ | ||
261 | typedef 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 | */ | ||
315 | typedef 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 | */ | ||
334 | struct BMP085BAROVMT { | ||
335 | _bmp085_baro_methods | ||
336 | }; | ||
337 | |||
338 | /** | ||
339 | * @extends BaseThermometerVMT | ||
340 | * | ||
341 | * @brief @p BMP085 thermometer virtual methods table. | ||
342 | */ | ||
343 | struct 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 | */ | ||
371 | struct 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 | ||
392 | extern "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. | ||
2 | BMP085SRC := $(CHIBIOS)/os/ex/devices/Bosch/bmp085.c | ||
3 | |||
4 | # Required include directories | ||
5 | BMP085INC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/Bosch | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(BMP085SRC) | ||
10 | ALLINC += $(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 | */ | ||
69 | static 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 | */ | ||
92 | static 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 | */ | ||
112 | static 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 | */ | ||
173 | static 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 | */ | ||
195 | static 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 | */ | ||
249 | static 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 | */ | ||
284 | static 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 | */ | ||
310 | static 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 | */ | ||
338 | static 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 | */ | ||
363 | static 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 | */ | ||
386 | static 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 | */ | ||
408 | static 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 | */ | ||
462 | static 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 | */ | ||
494 | static 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 | */ | ||
521 | static 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 | */ | ||
550 | static 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 | */ | ||
576 | static 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 | |||
593 | static const struct HTS221VMT vmt_device = { | ||
594 | (size_t)0 | ||
595 | }; | ||
596 | |||
597 | static 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 | |||
604 | static 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 | */ | ||
622 | void 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 | */ | ||
647 | void 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 | */ | ||
755 | void 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 | */ | ||
268 | typedef struct HTS221Driver HTS221Driver; | ||
269 | |||
270 | /** | ||
271 | * @brief HTS221 output data rate and bandwidth. | ||
272 | */ | ||
273 | typedef 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 | */ | ||
283 | typedef 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 | */ | ||
297 | typedef 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 | */ | ||
311 | typedef 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 | */ | ||
319 | typedef 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 | */ | ||
328 | typedef 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 | */ | ||
404 | struct 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 | */ | ||
440 | struct 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 | ||
696 | extern "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. | ||
2 | HTS221SRC := $(CHIBIOS)/os/ex/devices/ST/hts221.c | ||
3 | |||
4 | # Required include directories | ||
5 | HTS221INC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(HTS221SRC) | ||
10 | ALLINC += $(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 | */ | ||
59 | static 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 | */ | ||
78 | static 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 | */ | ||
96 | static 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 | */ | ||
115 | static 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 | */ | ||
167 | static 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 | */ | ||
200 | static 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 | */ | ||
248 | static 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 | */ | ||
277 | static 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 | */ | ||
307 | static 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 | */ | ||
336 | static 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 | */ | ||
378 | static 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 | |||
450 | static const struct L3GD20VMT vmt_device = { | ||
451 | (size_t)0, | ||
452 | gyro_set_full_scale | ||
453 | }; | ||
454 | |||
455 | static 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 | */ | ||
473 | void 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 | */ | ||
490 | void 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 | */ | ||
613 | void 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 | */ | ||
342 | typedef struct L3GD20Driver L3GD20Driver; | ||
343 | |||
344 | /** | ||
345 | * @brief L3GD20 full scale. | ||
346 | */ | ||
347 | typedef 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 | */ | ||
356 | typedef 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 | */ | ||
366 | typedef 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 | */ | ||
376 | typedef 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 | */ | ||
384 | typedef 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 | */ | ||
394 | typedef 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 | */ | ||
411 | typedef 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 | */ | ||
419 | typedef 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 | */ | ||
427 | typedef 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 | */ | ||
436 | typedef 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 | */ | ||
522 | struct 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 | */ | ||
547 | struct 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 | ||
713 | extern "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. | ||
2 | L3GD20SRC := $(CHIBIOS)/os/ex/devices/ST/l3gd20.c | ||
3 | |||
4 | # Required include directories | ||
5 | L3GD20INC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(L3GD20SRC) | ||
10 | ALLINC += $(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 | */ | ||
59 | static 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 | */ | ||
78 | static 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 | */ | ||
96 | static 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 | */ | ||
118 | static 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 | */ | ||
171 | static 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 | */ | ||
204 | static 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 | */ | ||
233 | static 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 | */ | ||
263 | static 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 | */ | ||
292 | static 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 | */ | ||
332 | static 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); | ||