diff options
Diffstat (limited to 'lib/chibios/os/ex/devices/ST')
35 files changed, 18307 insertions, 0 deletions
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); | ||
377 | cr |= fs; | ||
378 | |||
379 | #if LIS302DL_USE_SPI | ||
380 | #if LIS302DL_SHARED_SPI | ||
381 | spiAcquireBus(devp->config->spip); | ||
382 | spiStart(devp->config->spip, | ||
383 | devp->config->spicfg); | ||
384 | #endif /* LIS302DL_SHARED_SPI */ | ||
385 | |||
386 | /* Getting data from register.*/ | ||
387 | lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr); | ||
388 | |||
389 | #if LIS302DL_SHARED_SPI | ||
390 | spiReleaseBus(devp->config->spip); | ||
391 | #endif /* LIS302DL_SHARED_SPI */ | ||
392 | #endif /* LIS302DL_USE_SPI */ | ||
393 | |||
394 | /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ | ||
395 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) { | ||
396 | devp->accsensitivity[i] *= scale; | ||
397 | devp->accbias[i] *= scale; | ||
398 | } | ||
399 | } | ||
400 | return msg; | ||
401 | } | ||
402 | |||
403 | static const struct LIS302DLVMT vmt_device = { | ||
404 | (size_t)0, | ||
405 | acc_set_full_scale | ||
406 | }; | ||
407 | |||
408 | static const struct BaseAccelerometerVMT vmt_accelerometer = { | ||
409 | sizeof(struct LIS302DLVMT*), | ||
410 | acc_get_axes_number, acc_read_raw, acc_read_cooked, | ||
411 | acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity | ||
412 | }; | ||
413 | |||
414 | /*===========================================================================*/ | ||
415 | /* Driver exported functions. */ | ||
416 | /*===========================================================================*/ | ||
417 | |||
418 | /** | ||
419 | * @brief Initializes an instance. | ||
420 | * | ||
421 | * @param[out] devp pointer to the @p LIS302DLDriver object | ||
422 | * | ||
423 | * @init | ||
424 | */ | ||
425 | void lis302dlObjectInit(LIS302DLDriver *devp) { | ||
426 | devp->vmt = &vmt_device; | ||
427 | devp->acc_if.vmt = &vmt_accelerometer; | ||
428 | |||
429 | devp->config = NULL; | ||
430 | |||
431 | devp->accaxes = LIS302DL_ACC_NUMBER_OF_AXES; | ||
432 | |||
433 | devp->state = LIS302DL_STOP; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * @brief Configures and activates LIS302DL Complex Driver peripheral. | ||
438 | * | ||
439 | * @param[in] devp pointer to the @p LIS302DLDriver object | ||
440 | * @param[in] config pointer to the @p LIS302DLConfig object | ||
441 | * | ||
442 | * @api | ||
443 | */ | ||
444 | void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config) { | ||
445 | uint32_t i; | ||
446 | uint8_t cr[2] = {0, 0}; | ||
447 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
448 | |||
449 | osalDbgAssert((devp->state == LIS302DL_STOP) || (devp->state == LIS302DL_READY), | ||
450 | "lis302dlStart(), invalid state"); | ||
451 | |||
452 | devp->config = config; | ||
453 | |||
454 | /* Control register 1 configuration block.*/ | ||
455 | { | ||
456 | cr[0] = LIS302DL_CTRL_REG1_XEN | LIS302DL_CTRL_REG1_YEN | | ||
457 | LIS302DL_CTRL_REG1_ZEN | LIS302DL_CTRL_REG1_PD | | ||
458 | devp->config->accoutputdatarate | | ||
459 | devp->config->accfullscale; | ||
460 | } | ||
461 | |||
462 | /* Control register 2 configuration block.*/ | ||
463 | { | ||
464 | #if LIS302DL_USE_ADVANCED || defined(__DOXYGEN__) | ||
465 | if(devp->config->hpmode != LIS302DL_HPM_BYPASSED) | ||
466 | cr[1] = devp->config->acchighpass; | ||
467 | #endif | ||
468 | } | ||
469 | |||
470 | #if LIS302DL_USE_SPI | ||
471 | #if LIS302DL_SHARED_SPI | ||
472 | spiAcquireBus((devp)->config->spip); | ||
473 | #endif /* LIS302DL_SHARED_SPI */ | ||
474 | spiStart((devp)->config->spip, (devp)->config->spicfg); | ||
475 | |||
476 | lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, | ||
477 | 2, cr); | ||
478 | |||
479 | #if LIS302DL_SHARED_SPI | ||
480 | spiReleaseBus((devp)->config->spip); | ||
481 | #endif /* LIS302DL_SHARED_SPI */ | ||
482 | #endif /* LIS302DL_USE_SPI */ | ||
483 | |||
484 | /* Storing sensitivity information according to full scale value */ | ||
485 | if(devp->config->accfullscale == LIS302DL_ACC_FS_2G) { | ||
486 | devp->accfullscale = LIS302DL_ACC_2G; | ||
487 | if(devp->config->accsensitivity == NULL) | ||
488 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
489 | devp->accsensitivity[i] = LIS302DL_ACC_SENS_2G; | ||
490 | else | ||
491 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
492 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
493 | } | ||
494 | else if(devp->config->accfullscale == LIS302DL_ACC_FS_8G) { | ||
495 | devp->accfullscale = LIS302DL_ACC_8G; | ||
496 | if(devp->config->accsensitivity == NULL) | ||
497 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
498 | devp->accsensitivity[i] = LIS302DL_ACC_SENS_8G; | ||
499 | else | ||
500 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
501 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
502 | } | ||
503 | else { | ||
504 | osalDbgAssert(FALSE, "lis302dlStart(), accelerometer full scale issue"); | ||
505 | } | ||
506 | |||
507 | /* Storing bias information according to user setting */ | ||
508 | if(devp->config->accbias != NULL) | ||
509 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
510 | devp->accbias[i] = devp->config->accbias[i]; | ||
511 | else | ||
512 | for(i = 0; i < LIS302DL_ACC_NUMBER_OF_AXES; i++) | ||
513 | devp->accbias[i] = LIS302DL_ACC_BIAS; | ||
514 | |||
515 | /* This is the Accelerometer transient recovery time */ | ||
516 | osalThreadSleepMilliseconds(10); | ||
517 | |||
518 | devp->state = LIS302DL_READY; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * @brief Deactivates the LIS302DL Complex Driver peripheral. | ||
523 | * | ||
524 | * @param[in] devp pointer to the @p LIS302DLDriver object | ||
525 | * | ||
526 | * @api | ||
527 | */ | ||
528 | void lis302dlStop(LIS302DLDriver *devp) { | ||
529 | uint8_t cr1; | ||
530 | osalDbgCheck(devp != NULL); | ||
531 | |||
532 | osalDbgAssert((devp->state == LIS302DL_STOP) || | ||
533 | (devp->state == LIS302DL_READY), | ||
534 | "lis302dlStop(), invalid state"); | ||
535 | |||
536 | if (devp->state == LIS302DL_READY) { | ||
537 | #if LIS302DL_USE_SPI | ||
538 | #if LIS302DL_SHARED_SPI | ||
539 | spiAcquireBus((devp)->config->spip); | ||
540 | spiStart((devp)->config->spip, | ||
541 | (devp)->config->spicfg); | ||
542 | #endif /* LIS302DL_SHARED_SPI */ | ||
543 | /* Disabling all axes and enabling power down mode.*/ | ||
544 | cr1 = 0; | ||
545 | lis302dlSPIWriteRegister(devp->config->spip, LIS302DL_AD_CTRL_REG1, 1, &cr1); | ||
546 | spiStop((devp)->config->spip); | ||
547 | #if LIS302DL_SHARED_SPI | ||
548 | spiReleaseBus((devp)->config->spip); | ||
549 | #endif /* LIS302DL_SHARED_SPI */ | ||
550 | #endif /* LIS302DL_USE_SPI */ | ||
551 | } | ||
552 | devp->state = LIS302DL_STOP; | ||
553 | } | ||
554 | /** @} */ | ||
diff --git a/lib/chibios/os/ex/devices/ST/lis302dl.h b/lib/chibios/os/ex/devices/ST/lis302dl.h new file mode 100644 index 000000000..7a316b64d --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis302dl.h | |||
@@ -0,0 +1,566 @@ | |||
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.h | ||
23 | * @brief LIS302DL MEMS interface module header. | ||
24 | * | ||
25 | * @addtogroup LIS302DL | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #ifndef _LIS302DL_H_ | ||
31 | #define _LIS302DL_H_ | ||
32 | |||
33 | #include "ex_accelerometer.h" | ||
34 | |||
35 | /*===========================================================================*/ | ||
36 | /* Driver constants. */ | ||
37 | /*===========================================================================*/ | ||
38 | |||
39 | /** | ||
40 | * @name Version identification | ||
41 | * @{ | ||
42 | */ | ||
43 | /** | ||
44 | * @brief LIS302DL driver version string. | ||
45 | */ | ||
46 | #define EX_LIS302DL_VERSION "1.1.1" | ||
47 | |||
48 | /** | ||
49 | * @brief LIS302DL driver version major number. | ||
50 | */ | ||
51 | #define EX_LIS302DL_MAJOR 1 | ||
52 | |||
53 | /** | ||
54 | * @brief LIS302DL driver version minor number. | ||
55 | */ | ||
56 | #define EX_LIS302DL_MINOR 1 | ||
57 | |||
58 | /** | ||
59 | * @brief LIS302DL driver version patch number. | ||
60 | */ | ||
61 | #define EX_LIS302DL_PATCH 1 | ||
62 | /** @} */ | ||
63 | |||
64 | /** | ||
65 | * @brief LIS302DL accelerometer subsystem characteristics. | ||
66 | * @note Sensitivity is expressed as milli-G/LSB whereas | ||
67 | * 1 milli-G = 0.00980665 m/s^2. | ||
68 | * @note Bias is expressed as milli-G. | ||
69 | * | ||
70 | * @{ | ||
71 | */ | ||
72 | #define LIS302DL_ACC_NUMBER_OF_AXES 3U | ||
73 | |||
74 | #define LIS302DL_ACC_2G 2.0f | ||
75 | #define LIS302DL_ACC_8G 8.0f | ||
76 | |||
77 | #define LIS302DL_ACC_SENS_2G 18.0f | ||
78 | #define LIS302DL_ACC_SENS_8G 72.0f | ||
79 | |||
80 | #define LIS302DL_ACC_BIAS 0.0f | ||
81 | /** @} */ | ||
82 | |||
83 | /** | ||
84 | * @name LIS302DL communication interfaces related bit masks | ||
85 | * @{ | ||
86 | */ | ||
87 | #define LIS302DL_DI_MASK 0xFF | ||
88 | #define LIS302DL_DI(n) (1 << n) | ||
89 | #define LIS302DL_AD_MASK 0x3F | ||
90 | #define LIS302DL_AD(n) (1 << n) | ||
91 | #define LIS302DL_MS (1 << 6) | ||
92 | #define LIS302DL_RW (1 << 7) | ||
93 | /** @} */ | ||
94 | |||
95 | /** | ||
96 | * @name LIS302DL register addresses | ||
97 | * @{ | ||
98 | */ | ||
99 | #define LIS302DL_AD_WHO_AM_I 0x0F | ||
100 | #define LIS302DL_AD_CTRL_REG1 0x20 | ||
101 | #define LIS302DL_AD_CTRL_REG2 0x21 | ||
102 | #define LIS302DL_AD_CTRL_REG3 0x22 | ||
103 | #define LIS302DL_AD_HP_FILER_RESET 0x23 | ||
104 | #define LIS302DL_AD_STATUS_REG 0x27 | ||
105 | #define LIS302DL_AD_OUT_X 0x29 | ||
106 | #define LIS302DL_AD_OUT_Y 0x2B | ||
107 | #define LIS302DL_AD_OUT_Z 0x2D | ||
108 | #define LIS302DL_AD_FF_WU_CFG_1 0x30 | ||
109 | #define LIS302DL_AD_FF_WU_SRC_1 0x31 | ||
110 | #define LIS302DL_AD_FF_WU_THS_1 0x32 | ||
111 | #define LIS302DL_AD_FF_WU_DURATION_1 0x33 | ||
112 | #define LIS302DL_AD_FF_WU_CFG_2 0x34 | ||
113 | #define LIS302DL_AD_FF_WU_SRC_2 0x35 | ||
114 | #define LIS302DL_AD_FF_WU_THS_2 0x36 | ||
115 | #define LIS302DL_AD_FF_WU_DURATION_2 0x37 | ||
116 | #define LIS302DL_AD_CLICK_CFG 0x38 | ||
117 | #define LIS302DL_AD_CLICK_SRC 0x39 | ||
118 | #define LIS302DL_AD_CLICK_THSY_X 0x3B | ||
119 | #define LIS302DL_AD_CLICK_THSZ 0x3C | ||
120 | #define LIS302DL_AD_CLICK_TIME_LIMIT 0x3D | ||
121 | #define LIS302DL_AD_CLICK_LATENCY 0x3E | ||
122 | #define LIS302DL_AD_CLICK_WINDOW 0x3F | ||
123 | /** @} */ | ||
124 | |||
125 | /** | ||
126 | * @name LIS302DL_CTRL_REG1 register bits definitions | ||
127 | * @{ | ||
128 | */ | ||
129 | #define LIS302DL_CTRL_REG1_MASK 0xFF | ||
130 | #define LIS302DL_CTRL_REG1_XEN (1 << 0) | ||
131 | #define LIS302DL_CTRL_REG1_YEN (1 << 1) | ||
132 | #define LIS302DL_CTRL_REG1_ZEN (1 << 2) | ||
133 | #define LIS302DL_CTRL_REG1_STM (1 << 3) | ||
134 | #define LIS302DL_CTRL_REG1_STP (1 << 4) | ||
135 | #define LIS302DL_CTRL_REG1_FS_MASK 0x20 | ||
136 | #define LIS302DL_CTRL_REG1_FS (1 << 5) | ||
137 | #define LIS302DL_CTRL_REG1_PD (1 << 6) | ||
138 | #define LIS302DL_CTRL_REG1_DR (1 << 7) | ||
139 | /** @} */ | ||
140 | |||
141 | /** | ||
142 | * @name LIS302DL_CTRL_REG2 register bits definitions | ||
143 | * @{ | ||
144 | */ | ||
145 | #define LIS302DL_CTRL_REG2_MASK 0xDF | ||
146 | #define LIS302DL_CTRL_REG2_HPCF1 (1 << 0) | ||
147 | #define LIS302DL_CTRL_REG2_HPCF2 (1 << 1) | ||
148 | #define LIS302DL_CTRL_REG2_HPFFWU1 (1 << 2) | ||
149 | #define LIS302DL_CTRL_REG2_HPFFWU2 (1 << 3) | ||
150 | #define LIS302DL_CTRL_REG2_FDS (1 << 4) | ||
151 | #define LIS302DL_CTRL_REG2_BOOT (1 << 6) | ||
152 | #define LIS302DL_CTRL_REG2_SIM (1 << 7) | ||
153 | /** @} */ | ||
154 | |||
155 | /** | ||
156 | * @name LIS302DL_CTRL_REG3 register bits definitions | ||
157 | * @{ | ||
158 | */ | ||
159 | #define LIS302DL_CTRL_REG3_MASK 0xFF | ||
160 | #define LIS302DL_CTRL_REG3_I1CFG0 (1 << 0) | ||
161 | #define LIS302DL_CTRL_REG3_I1CFG1 (1 << 1) | ||
162 | #define LIS302DL_CTRL_REG3_I1CFG2 (1 << 2) | ||
163 | #define LIS302DL_CTRL_REG3_I2CFG0 (1 << 3) | ||
164 | #define LIS302DL_CTRL_REG3_I2CFG1 (1 << 4) | ||
165 | #define LIS302DL_CTRL_REG3_I2CFG2 (1 << 5) | ||
166 | #define LIS302DL_CTRL_REG3_PP_OD (1 << 6) | ||
167 | #define LIS302DL_CTRL_REG3_IHL (1 << 7) | ||
168 | /** @} */ | ||
169 | |||
170 | /*===========================================================================*/ | ||
171 | /* Driver pre-compile time settings. */ | ||
172 | /*===========================================================================*/ | ||
173 | |||
174 | /** | ||
175 | * @name Configuration options | ||
176 | * @{ | ||
177 | */ | ||
178 | /** | ||
179 | * @brief LIS302DL SPI interface switch. | ||
180 | * @details If set to @p TRUE the support for SPI is included. | ||
181 | * @note The default is @p TRUE. | ||
182 | */ | ||
183 | #if !defined(LIS302DL_USE_SPI) || defined(__DOXYGEN__) | ||
184 | #define LIS302DL_USE_SPI TRUE | ||
185 | #endif | ||
186 | |||
187 | /** | ||
188 | * @brief LIS302DL 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(LIS302DL_SHARED_SPI) || defined(__DOXYGEN__) | ||
194 | #define LIS302DL_SHARED_SPI FALSE | ||
195 | #endif | ||
196 | |||
197 | /** | ||
198 | * @brief LIS302DL I2C interface switch. | ||
199 | * @details If set to @p TRUE the support for I2C is included. | ||
200 | * @note The default is @p FALSE. | ||
201 | */ | ||
202 | #if !defined(LIS302DL_USE_I2C) || defined(__DOXYGEN__) | ||
203 | #define LIS302DL_USE_I2C FALSE | ||
204 | #endif | ||
205 | |||
206 | /** | ||
207 | * @brief LIS302DL 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(LIS302DL_SHARED_I2C) || defined(__DOXYGEN__) | ||
213 | #define LIS302DL_SHARED_I2C FALSE | ||
214 | #endif | ||
215 | |||
216 | /** | ||
217 | * @brief LIS302DL 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(LIS302DL_USE_ADVANCED) || defined(__DOXYGEN__) | ||
222 | #define LIS302DL_USE_ADVANCED FALSE | ||
223 | #endif | ||
224 | /** @} */ | ||
225 | |||
226 | /*===========================================================================*/ | ||
227 | /* Derived constants and error checks. */ | ||
228 | /*===========================================================================*/ | ||
229 | |||
230 | #if !(LIS302DL_USE_SPI ^ LIS302DL_USE_I2C) | ||
231 | #error "LIS302DL_USE_SPI and LIS302DL_USE_I2C cannot be both true or both false" | ||
232 | #endif | ||
233 | |||
234 | #if LIS302DL_USE_SPI && !HAL_USE_SPI | ||
235 | #error "LIS302DL_USE_SPI requires HAL_USE_SPI" | ||
236 | #endif | ||
237 | |||
238 | #if LIS302DL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION | ||
239 | #error "LIS302DL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" | ||
240 | #endif | ||
241 | |||
242 | #if LIS302DL_USE_I2C && !HAL_USE_I2C | ||
243 | #error "LIS302DL_USE_I2C requires HAL_USE_I2C" | ||
244 | #endif | ||
245 | |||
246 | #if LIS302DL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION | ||
247 | #error "LIS302DL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" | ||
248 | #endif | ||
249 | |||
250 | /* | ||
251 | * CHTODO: Add support for LIS302DL over I2C. | ||
252 | */ | ||
253 | #if LIS302DL_USE_I2C | ||
254 | #error "LIS302DL over I2C still not supported" | ||
255 | #endif | ||
256 | |||
257 | /*===========================================================================*/ | ||
258 | /* Driver data structures and types. */ | ||
259 | /*===========================================================================*/ | ||
260 | |||
261 | /** | ||
262 | * @name LIS302DL data structures and types | ||
263 | * @{ | ||
264 | */ | ||
265 | /** | ||
266 | * @brief Structure representing a LIS302DL driver. | ||
267 | */ | ||
268 | typedef struct LIS302DLDriver LIS302DLDriver; | ||
269 | |||
270 | /** | ||
271 | * @brief LIS302DL full scale. | ||
272 | */ | ||
273 | typedef enum { | ||
274 | LIS302DL_ACC_FS_2G = 0x00, /**< Full scale �2g. */ | ||
275 | LIS302DL_ACC_FS_8G = 0x20 /**< Full scale �8g. */ | ||
276 | }lis302dl_acc_fs_t; | ||
277 | |||
278 | /** | ||
279 | * @brief LIS302DL output data rate and bandwidth. | ||
280 | */ | ||
281 | typedef enum { | ||
282 | LIS302DL_ACC_ODR_100HZ = 0x00, /**< ODR 100 Hz. */ | ||
283 | LIS302DL_ACC_ODR_400HZ = 0x80 /**< ODR 400 Hz. */ | ||
284 | }lis302dl_acc_odr_t; | ||
285 | |||
286 | /** | ||
287 | * @brief LIS302DL high pass filtering. | ||
288 | */ | ||
289 | typedef enum { | ||
290 | LIS302DL_ACC_HP_DISABLED = 0x00, /**< HP bypassed. */ | ||
291 | LIS302DL_ACC_HP_0 = 0x10, /**< HP cutoff 2Hz (ODR 100Hz) or 8Hz */ | ||
292 | LIS302DL_ACC_HP_1 = 0x11, /**< HP cutoff 1Hz or 4Hz */ | ||
293 | LIS302DL_ACC_HP_2 = 0x12, /**< HP cutoff 0.5Hz or 2Hz */ | ||
294 | LIS302DL_ACC_HP_3 = 0x13 /**< HP cutoff 0.25Hz or 1Hz */ | ||
295 | }lis302dl_acc_hp_t; | ||
296 | |||
297 | /** | ||
298 | * @brief Driver state machine possible states. | ||
299 | */ | ||
300 | typedef enum { | ||
301 | LIS302DL_UNINIT = 0, /**< Not initialized. */ | ||
302 | LIS302DL_STOP = 1, /**< Stopped. */ | ||
303 | LIS302DL_READY = 2, /**< Ready. */ | ||
304 | } lis302dl_state_t; | ||
305 | |||
306 | /** | ||
307 | * @brief LIS302DL configuration structure. | ||
308 | */ | ||
309 | typedef struct { | ||
310 | |||
311 | #if (LIS302DL_USE_SPI) || defined(__DOXYGEN__) | ||
312 | /** | ||
313 | * @brief SPI driver associated to this LIS302DL. | ||
314 | */ | ||
315 | SPIDriver *spip; | ||
316 | /** | ||
317 | * @brief SPI configuration associated to this LIS302DL. | ||
318 | */ | ||
319 | const SPIConfig *spicfg; | ||
320 | #endif /* LIS302DL_USE_SPI */ | ||
321 | #if (LIS302DL_USE_I2C) || defined(__DOXYGEN__) | ||
322 | /** | ||
323 | * @brief I2C driver associated to this LIS302DL. | ||
324 | */ | ||
325 | I2CDriver *i2cp; | ||
326 | /** | ||
327 | * @brief I2C configuration associated to this LIS302DL. | ||
328 | */ | ||
329 | const I2CConfig *i2ccfg; | ||
330 | #endif /* LIS302DL_USE_I2C */ | ||
331 | /** | ||
332 | * @brief LIS302DL accelerometer subsystem initial sensitivity. | ||
333 | */ | ||
334 | float *accsensitivity; | ||
335 | /** | ||
336 | * @brief LIS302DL accelerometer subsystem initial bias. | ||
337 | */ | ||
338 | float *accbias; | ||
339 | /** | ||
340 | * @brief LIS302DL accelerometer subsystem initial full scale. | ||
341 | */ | ||
342 | lis302dl_acc_fs_t accfullscale; | ||
343 | /** | ||
344 | * @brief LIS302DL output data rate selection. | ||
345 | */ | ||
346 | lis302dl_acc_odr_t accoutputdatarate; | ||
347 | #if LIS302DL_USE_ADVANCED || defined(__DOXYGEN__) | ||
348 | /** | ||
349 | * @brief LIS302DL high pass filtering. | ||
350 | */ | ||
351 | lis302dl_acc_hp_t acchighpass; | ||
352 | #endif | ||
353 | } LIS302DLConfig; | ||
354 | |||
355 | /** | ||
356 | * @brief @p LIS302DL specific methods. | ||
357 | */ | ||
358 | #define _lis302dl_methods_alone \ | ||
359 | /* Change full scale value of LIS302DL .*/ \ | ||
360 | msg_t (*set_full_scale)(LIS302DLDriver *devp, lis302dl_acc_fs_t fs); | ||
361 | |||
362 | |||
363 | /** | ||
364 | * @brief @p LIS302DL specific methods with inherited ones. | ||
365 | */ | ||
366 | #define _lis302dl_methods \ | ||
367 | _base_object_methods \ | ||
368 | _lis302dl_methods_alone | ||
369 | |||
370 | /** | ||
371 | * @extends BaseObjectVMT | ||
372 | * | ||
373 | * @brief @p LIS302DL accelerometer virtual methods table. | ||
374 | */ | ||
375 | struct LIS302DLVMT { | ||
376 | _lis302dl_methods | ||
377 | }; | ||
378 | |||
379 | /** | ||
380 | * @brief @p LIS302DLDriver specific data. | ||
381 | */ | ||
382 | #define _lis302dl_data \ | ||
383 | /* Driver state.*/ \ | ||
384 | lis302dl_state_t state; \ | ||
385 | /* Current configuration data.*/ \ | ||
386 | const LIS302DLConfig *config; \ | ||
387 | /* Accelerometer subsystem axes number.*/ \ | ||
388 | size_t accaxes; \ | ||
389 | /* Current sensitivity.*/ \ | ||
390 | float accsensitivity[LIS302DL_ACC_NUMBER_OF_AXES]; \ | ||
391 | /* Bias data.*/ \ | ||
392 | int32_t accbias[LIS302DL_ACC_NUMBER_OF_AXES]; \ | ||
393 | /* Current full scale value.*/ \ | ||
394 | float accfullscale; | ||
395 | |||
396 | /** | ||
397 | * @brief LIS302DL 3-axis accelerometer class. | ||
398 | */ | ||
399 | struct LIS302DLDriver { | ||
400 | /** @brief Virtual Methods Table.*/ | ||
401 | const struct LIS302DLVMT *vmt; | ||
402 | /** @brief Base accelerometer interface.*/ | ||
403 | BaseAccelerometer acc_if; | ||
404 | _lis302dl_data | ||
405 | }; | ||
406 | /** @} */ | ||
407 | |||
408 | /*===========================================================================*/ | ||
409 | /* Driver macros. */ | ||
410 | /*===========================================================================*/ | ||
411 | |||
412 | /** | ||
413 | * @brief Return the number of axes of the BaseAccelerometer. | ||
414 | * | ||
415 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
416 | * | ||
417 | * @return the number of axes. | ||
418 | * | ||
419 | * @api | ||
420 | */ | ||
421 | #define lis302dlAccelerometerGetAxesNumber(devp) \ | ||
422 | accelerometerGetAxesNumber(&((devp)->acc_if)) | ||
423 | |||
424 | /** | ||
425 | * @brief Retrieves raw data from the BaseAccelerometer. | ||
426 | * @note This data is retrieved from MEMS register without any algebraical | ||
427 | * manipulation. | ||
428 | * @note The axes array must be at least the same size of the | ||
429 | * BaseAccelerometer axes number. | ||
430 | * | ||
431 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
432 | * @param[out] axes a buffer which would be filled with raw data. | ||
433 | * | ||
434 | * @return The operation status. | ||
435 | * @retval MSG_OK if the function succeeded. | ||
436 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
437 | * be retrieved using @p i2cGetErrors(). | ||
438 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
439 | * | ||
440 | * @api | ||
441 | */ | ||
442 | #define lis302dlAccelerometerReadRaw(devp, axes) \ | ||
443 | accelerometerReadRaw(&((devp)->acc_if), axes) | ||
444 | |||
445 | /** | ||
446 | * @brief Retrieves cooked data from the BaseAccelerometer. | ||
447 | * @note This data is manipulated according to the formula | ||
448 | * cooked = (raw * sensitivity) - bias. | ||
449 | * @note Final data is expressed as milli-G. | ||
450 | * @note The axes array must be at least the same size of the | ||
451 | * BaseAccelerometer axes number. | ||
452 | * | ||
453 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
454 | * @param[out] axes 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 | * @api | ||
463 | */ | ||
464 | #define lis302dlAccelerometerReadCooked(devp, axes) \ | ||
465 | accelerometerReadCooked(&((devp)->acc_if), axes) | ||
466 | |||
467 | /** | ||
468 | * @brief Set bias values for the BaseAccelerometer. | ||
469 | * @note Bias must be expressed as milli-G. | ||
470 | * @note The bias buffer must be at least the same size of the | ||
471 | * BaseAccelerometer axes number. | ||
472 | * | ||
473 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
474 | * @param[in] bp a buffer which contains biases. | ||
475 | * | ||
476 | * @return The operation status. | ||
477 | * @retval MSG_OK if the function succeeded. | ||
478 | * | ||
479 | * @api | ||
480 | */ | ||
481 | #define lis302dlAccelerometerSetBias(devp, bp) \ | ||
482 | accelerometerSetBias(&((devp)->acc_if), bp) | ||
483 | |||
484 | /** | ||
485 | * @brief Reset bias values for the BaseAccelerometer. | ||
486 | * @note Default biases value are obtained from device datasheet when | ||
487 | * available otherwise they are considered zero. | ||
488 | * | ||
489 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
490 | * | ||
491 | * @return The operation status. | ||
492 | * @retval MSG_OK if the function succeeded. | ||
493 | * | ||
494 | * @api | ||
495 | */ | ||
496 | #define lis302dlAccelerometerResetBias(devp) \ | ||
497 | accelerometerResetBias(&((devp)->acc_if)) | ||
498 | |||
499 | /** | ||
500 | * @brief Set sensitivity values for the BaseAccelerometer. | ||
501 | * @note Sensitivity must be expressed as milli-G/LSB. | ||
502 | * @note The sensitivity buffer must be at least the same size of the | ||
503 | * BaseAccelerometer axes number. | ||
504 | * | ||
505 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
506 | * @param[in] sp a buffer which contains sensitivities. | ||
507 | * | ||
508 | * @return The operation status. | ||
509 | * @retval MSG_OK if the function succeeded. | ||
510 | * | ||
511 | * @api | ||
512 | */ | ||
513 | #define lis302dlAccelerometerSetSensitivity(devp, sp) \ | ||
514 | accelerometerSetSensitivity(&((devp)->acc_if), sp) | ||
515 | |||
516 | /** | ||
517 | * @brief Reset sensitivity values for the BaseAccelerometer. | ||
518 | * @note Default sensitivities value are obtained from device datasheet. | ||
519 | * | ||
520 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
521 | * | ||
522 | * @return The operation status. | ||
523 | * @retval MSG_OK if the function succeeded. | ||
524 | * @retval MSG_RESET otherwise. | ||
525 | * | ||
526 | * @api | ||
527 | */ | ||
528 | #define lis302dlAccelerometerResetSensitivity(devp) \ | ||
529 | accelerometerResetSensitivity(&((devp)->acc_if)) | ||
530 | |||
531 | /** | ||
532 | * @brief Changes the LIS302DLDriver accelerometer fullscale value. | ||
533 | * @note This function also rescale sensitivities and biases based on | ||
534 | * previous and next fullscale value. | ||
535 | * @note A recalibration is highly suggested after calling this function. | ||
536 | * | ||
537 | * @param[in] devp pointer to @p LIS302DLDriver. | ||
538 | * @param[in] fs new fullscale value. | ||
539 | * | ||
540 | * @return The operation status. | ||
541 | * @retval MSG_OK if the function succeeded. | ||
542 | * @retval MSG_RESET otherwise. | ||
543 | * | ||
544 | * @api | ||
545 | */ | ||
546 | #define lis302dlAccelerometerSetFullScale(devp, fs) \ | ||
547 | (devp)->vmt->acc_set_full_scale(devp, fs) | ||
548 | |||
549 | /*===========================================================================*/ | ||
550 | /* External declarations. */ | ||
551 | /*===========================================================================*/ | ||
552 | |||
553 | #ifdef __cplusplus | ||
554 | extern "C" { | ||
555 | #endif | ||
556 | void lis302dlObjectInit(LIS302DLDriver *devp); | ||
557 | void lis302dlStart(LIS302DLDriver *devp, const LIS302DLConfig *config); | ||
558 | void lis302dlStop(LIS302DLDriver *devp); | ||
559 | #ifdef __cplusplus | ||
560 | } | ||
561 | #endif | ||
562 | |||
563 | #endif /* _LIS302DL_H_ */ | ||
564 | |||
565 | /** @} */ | ||
566 | |||
diff --git a/lib/chibios/os/ex/devices/ST/lis302dl.mk b/lib/chibios/os/ex/devices/ST/lis302dl.mk new file mode 100644 index 000000000..5f5ccf4f6 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis302dl.mk | |||
@@ -0,0 +1,10 @@ | |||
1 | # List of all the LIS302DL device files. | ||
2 | LIS302DLSRC := $(CHIBIOS)/os/ex/devices/ST/lis302dl.c | ||
3 | |||
4 | # Required include directories | ||
5 | LIS302DLINC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(LIS302DLSRC) | ||
10 | ALLINC += $(LIS302DLINC) \ No newline at end of file | ||
diff --git a/lib/chibios/os/ex/devices/ST/lis3dsh.c b/lib/chibios/os/ex/devices/ST/lis3dsh.c new file mode 100644 index 000000000..f8f34788e --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3dsh.c | |||
@@ -0,0 +1,641 @@ | |||
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 lis3dsh.c | ||
23 | * @brief LIS3DSH MEMS interface module code. | ||
24 | * | ||
25 | * @addtogroup LIS3DSH | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #include "hal.h" | ||
31 | #include "lis3dsh.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 (LIS3DSH_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 | * @note Multiple write/read requires proper settings in CTRL_REG6. | ||
54 | * | ||
55 | * @param[in] spip pointer to the SPI interface | ||
56 | * @param[in] reg starting register address | ||
57 | * @param[in] n number of adjacent registers to write | ||
58 | * @param[in] b pointer to a buffer. | ||
59 | */ | ||
60 | static void lis3dshSPIReadRegister(SPIDriver *spip, uint8_t reg, size_t n, | ||
61 | uint8_t* b) { | ||
62 | uint8_t cmd; | ||
63 | cmd = reg | LIS3DSH_RW; | ||
64 | spiSelect(spip); | ||
65 | spiSend(spip, 1, &cmd); | ||
66 | spiReceive(spip, n, b); | ||
67 | spiUnselect(spip); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * @brief Writes a value into a generic register using SPI. | ||
72 | * @pre The SPI interface must be initialized and the driver started. | ||
73 | * @note Multiple write/read requires proper settings in CTRL_REG6. | ||
74 | * | ||
75 | * @param[in] spip pointer to the SPI interface | ||
76 | * @param[in] reg starting register address | ||
77 | * @param[in] n number of adjacent registers to write | ||
78 | * @param[in] b pointer to a buffer of values. | ||
79 | */ | ||
80 | static void lis3dshSPIWriteRegister(SPIDriver *spip, uint8_t reg, size_t n, | ||
81 | uint8_t* b) { | ||
82 | uint8_t cmd; | ||
83 | cmd = reg; | ||
84 | spiSelect(spip); | ||
85 | spiSend(spip, 1, &cmd); | ||
86 | spiSend(spip, n, b); | ||
87 | spiUnselect(spip); | ||
88 | } | ||
89 | #endif /* LIS3DSH_USE_SPI */ | ||
90 | |||
91 | /** | ||
92 | * @brief Return the number of axes of the BaseAccelerometer. | ||
93 | * | ||
94 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
95 | * | ||
96 | * @return the number of axes. | ||
97 | */ | ||
98 | static size_t acc_get_axes_number(void *ip) { | ||
99 | (void)ip; | ||
100 | |||
101 | return LIS3DSH_ACC_NUMBER_OF_AXES; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * @brief Retrieves raw data from the BaseAccelerometer. | ||
106 | * @note This data is retrieved from MEMS register without any algebraical | ||
107 | * manipulation. | ||
108 | * @note The axes array must be at least the same size of the | ||
109 | * BaseAccelerometer axes number. | ||
110 | * | ||
111 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
112 | * @param[out] axes a buffer which would be filled with raw data. | ||
113 | * | ||
114 | * @return The operation status. | ||
115 | * @retval MSG_OK if the function succeeded. | ||
116 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
117 | * be retrieved using @p i2cGetErrors(). | ||
118 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
119 | */ | ||
120 | static msg_t acc_read_raw(void *ip, int32_t axes[]) { | ||
121 | LIS3DSHDriver* devp; | ||
122 | uint8_t buff [LIS3DSH_ACC_NUMBER_OF_AXES * 2], i; | ||
123 | int16_t tmp; | ||
124 | msg_t msg = MSG_OK; | ||
125 | |||
126 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
127 | |||
128 | /* Getting parent instance pointer.*/ | ||
129 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
130 | |||
131 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
132 | "acc_read_raw(), invalid state"); | ||
133 | |||
134 | #if LIS3DSH_USE_SPI | ||
135 | #if LIS3DSH_SHARED_SPI | ||
136 | osalDbgAssert((devp->config->spip->state == SPI_READY), | ||
137 | "acc_read_raw(), channel not ready"); | ||
138 | |||
139 | spiAcquireBus(devp->config->spip); | ||
140 | spiStart(devp->config->spip, | ||
141 | devp->config->spicfg); | ||
142 | #endif /* LIS3DSH_SHARED_SPI */ | ||
143 | |||
144 | lis3dshSPIReadRegister(devp->config->spip, LIS3DSH_AD_OUT_X_L, | ||
145 | LIS3DSH_ACC_NUMBER_OF_AXES * 2, buff); | ||
146 | |||
147 | #if LIS3DSH_SHARED_SPI | ||
148 | spiReleaseBus(devp->config->spip); | ||
149 | #endif /* LIS3DSH_SHARED_SPI */ | ||
150 | #endif /* LIS3DSH_USE_SPI */ | ||
151 | |||
152 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { | ||
153 | tmp = buff[2 * i] + (buff[2 * i + 1] << 8); | ||
154 | axes[i] = (int32_t)tmp; | ||
155 | } | ||
156 | return msg; | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * @brief Retrieves cooked data from the BaseAccelerometer. | ||
161 | * @note This data is manipulated according to the formula | ||
162 | * cooked = (raw * sensitivity) - bias. | ||
163 | * @note Final data is expressed as milli-G. | ||
164 | * @note The axes array must be at least the same size of the | ||
165 | * BaseAccelerometer axes number. | ||
166 | * | ||
167 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
168 | * @param[out] axes a buffer which would be filled with cooked data. | ||
169 | * | ||
170 | * @return The operation status. | ||
171 | * @retval MSG_OK if the function succeeded. | ||
172 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
173 | * be retrieved using @p i2cGetErrors(). | ||
174 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
175 | */ | ||
176 | static msg_t acc_read_cooked(void *ip, float axes[]) { | ||
177 | LIS3DSHDriver* devp; | ||
178 | uint32_t i; | ||
179 | int32_t raw[LIS3DSH_ACC_NUMBER_OF_AXES]; | ||
180 | msg_t msg; | ||
181 | |||
182 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
183 | |||
184 | /* Getting parent instance pointer.*/ | ||
185 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
186 | |||
187 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
188 | "acc_read_cooked(), invalid state"); | ||
189 | |||
190 | msg = acc_read_raw(ip, raw); | ||
191 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { | ||
192 | axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; | ||
193 | } | ||
194 | return msg; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * @brief Set bias values for the BaseAccelerometer. | ||
199 | * @note Bias must be expressed as milli-G. | ||
200 | * @note The bias buffer must be at least the same size of the | ||
201 | * BaseAccelerometer axes number. | ||
202 | * | ||
203 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
204 | * @param[in] bp a buffer which contains biases. | ||
205 | * | ||
206 | * @return The operation status. | ||
207 | * @retval MSG_OK if the function succeeded. | ||
208 | */ | ||
209 | static msg_t acc_set_bias(void *ip, float *bp) { | ||
210 | LIS3DSHDriver* devp; | ||
211 | uint32_t i; | ||
212 | msg_t msg = MSG_OK; | ||
213 | |||
214 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
215 | |||
216 | /* Getting parent instance pointer.*/ | ||
217 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
218 | |||
219 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
220 | "acc_set_bias(), invalid state"); | ||
221 | |||
222 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { | ||
223 | devp->accbias[i] = bp[i]; | ||
224 | } | ||
225 | return msg; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * @brief Reset bias values for the BaseAccelerometer. | ||
230 | * @note Default biases value are obtained from device datasheet when | ||
231 | * available otherwise they are considered zero. | ||
232 | * | ||
233 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
234 | * | ||
235 | * @return The operation status. | ||
236 | * @retval MSG_OK if the function succeeded. | ||
237 | */ | ||
238 | static msg_t acc_reset_bias(void *ip) { | ||
239 | LIS3DSHDriver* devp; | ||
240 | uint32_t i; | ||
241 | msg_t msg = MSG_OK; | ||
242 | |||
243 | osalDbgCheck(ip != NULL); | ||
244 | |||
245 | /* Getting parent instance pointer.*/ | ||
246 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
247 | |||
248 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
249 | "acc_reset_bias(), invalid state"); | ||
250 | |||
251 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
252 | devp->accbias[i] = LIS3DSH_ACC_BIAS; | ||
253 | return msg; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * @brief Set sensitivity values for the BaseAccelerometer. | ||
258 | * @note Sensitivity must be expressed as milli-G/LSB. | ||
259 | * @note The sensitivity buffer must be at least the same size of the | ||
260 | * BaseAccelerometer axes number. | ||
261 | * | ||
262 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
263 | * @param[in] sp a buffer which contains sensitivities. | ||
264 | * | ||
265 | * @return The operation status. | ||
266 | * @retval MSG_OK if the function succeeded. | ||
267 | */ | ||
268 | static msg_t acc_set_sensivity(void *ip, float *sp) { | ||
269 | LIS3DSHDriver* devp; | ||
270 | uint32_t i; | ||
271 | msg_t msg = MSG_OK; | ||
272 | |||
273 | /* Getting parent instance pointer.*/ | ||
274 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
275 | |||
276 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
277 | |||
278 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
279 | "acc_set_sensivity(), invalid state"); | ||
280 | |||
281 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { | ||
282 | devp->accsensitivity[i] = sp[i]; | ||
283 | } | ||
284 | return msg; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * @brief Reset sensitivity values for the BaseAccelerometer. | ||
289 | * @note Default sensitivities value are obtained from device datasheet. | ||
290 | * | ||
291 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
292 | * | ||
293 | * @return The operation status. | ||
294 | * @retval MSG_OK if the function succeeded. | ||
295 | * @retval MSG_RESET otherwise. | ||
296 | */ | ||
297 | static msg_t acc_reset_sensivity(void *ip) { | ||
298 | LIS3DSHDriver* devp; | ||
299 | uint32_t i; | ||
300 | msg_t msg = MSG_OK; | ||
301 | |||
302 | osalDbgCheck(ip != NULL); | ||
303 | |||
304 | /* Getting parent instance pointer.*/ | ||
305 | devp = objGetInstance(LIS3DSHDriver*, (BaseAccelerometer*)ip); | ||
306 | |||
307 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
308 | "acc_reset_sensivity(), invalid state"); | ||
309 | |||
310 | if(devp->config->accfullscale == LIS3DSH_ACC_FS_2G) | ||
311 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
312 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_2G; | ||
313 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_4G) | ||
314 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
315 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_4G; | ||
316 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_6G) | ||
317 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
318 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_6G; | ||
319 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_8G) | ||
320 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
321 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_8G; | ||
322 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_16G) | ||
323 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
324 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_16G; | ||
325 | else { | ||
326 | osalDbgAssert(FALSE, | ||
327 | "acc_reset_sensivity(), accelerometer full scale issue"); | ||
328 | return MSG_RESET; | ||
329 | } | ||
330 | return msg; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * @brief Changes the LIS3DSHDriver accelerometer fullscale value. | ||
335 | * @note This function also rescale sensitivities and biases based on | ||
336 | * previous and next fullscale value. | ||
337 | * @note A recalibration is highly suggested after calling this function. | ||
338 | * | ||
339 | * @param[in] devp pointer to @p LIS3DSHDriver interface. | ||
340 | * @param[in] fs new fullscale value. | ||
341 | * | ||
342 | * @return The operation status. | ||
343 | * @retval MSG_OK if the function succeeded. | ||
344 | * @retval MSG_RESET otherwise. | ||
345 | */ | ||
346 | static msg_t acc_set_full_scale(LIS3DSHDriver *devp, lis3dsh_acc_fs_t fs) { | ||
347 | float newfs, scale; | ||
348 | uint8_t i, cr; | ||
349 | msg_t msg; | ||
350 | |||
351 | osalDbgCheck(devp != NULL); | ||
352 | |||
353 | osalDbgAssert((devp->state == LIS3DSH_READY), | ||
354 | "acc_set_full_scale(), invalid state"); | ||
355 | osalDbgAssert((devp->config->spip->state == SPI_READY), | ||
356 | "acc_set_full_scale(), channel not ready"); | ||
357 | |||
358 | /* Computing new fullscale value.*/ | ||
359 | if(fs == LIS3DSH_ACC_FS_2G) { | ||
360 | newfs = LIS3DSH_ACC_2G; | ||
361 | } | ||
362 | else if(fs == LIS3DSH_ACC_FS_4G) { | ||
363 | newfs = LIS3DSH_ACC_4G; | ||
364 | } | ||
365 | else if(fs == LIS3DSH_ACC_FS_6G) { | ||
366 | newfs = LIS3DSH_ACC_6G; | ||
367 | } | ||
368 | else if(fs == LIS3DSH_ACC_FS_8G) { | ||
369 | newfs = LIS3DSH_ACC_8G; | ||
370 | } | ||
371 | else if(fs == LIS3DSH_ACC_FS_16G) { | ||
372 | newfs = LIS3DSH_ACC_16G; | ||
373 | } | ||
374 | else { | ||
375 | msg = MSG_RESET; | ||
376 | return msg; | ||
377 | } | ||
378 | |||
379 | if(newfs != devp->accfullscale) { | ||
380 | /* Computing scale value.*/ | ||
381 | scale = newfs / devp->accfullscale; | ||
382 | devp->accfullscale = newfs; | ||
383 | |||
384 | #if LIS3DSH_USE_SPI | ||
385 | #if LIS3DSH_SHARED_SPI | ||
386 | spiAcquireBus(devp->config->spip); | ||
387 | spiStart(devp->config->spip, | ||
388 | devp->config->spicfg); | ||
389 | #endif /* LIS3DSH_SHARED_SPI */ | ||
390 | |||
391 | /* Getting data from register.*/ | ||
392 | lis3dshSPIReadRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); | ||
393 | |||
394 | #if LIS3DSH_SHARED_SPI | ||
395 | spiReleaseBus(devp->config->spip); | ||
396 | #endif /* LIS3DSH_SHARED_SPI */ | ||
397 | #endif /* LIS3DSH_USE_SPI */ | ||
398 | |||
399 | cr &= ~(LIS3DSH_CTRL_REG5_FS_MASK); | ||
400 | cr |= fs; | ||
401 | |||
402 | #if LIS3DSH_USE_SPI | ||
403 | #if LIS3DSH_SHARED_SPI | ||
404 | spiAcquireBus(devp->config->spip); | ||
405 | spiStart(devp->config->spip, | ||
406 | devp->config->spicfg); | ||
407 | #endif /* LIS3DSH_SHARED_SPI */ | ||
408 | |||
409 | /* Getting data from register.*/ | ||
410 | lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); | ||
411 | |||
412 | #if LIS3DSH_SHARED_SPI | ||
413 | spiReleaseBus(devp->config->spip); | ||
414 | #endif /* LIS3DSH_SHARED_SPI */ | ||
415 | #endif /* LIS3DSH_USE_SPI */ | ||
416 | |||
417 | /* Scaling sensitivity and bias. Re-calibration is suggested anyway. */ | ||
418 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) { | ||
419 | devp->accsensitivity[i] *= scale; | ||
420 | devp->accbias[i] *= scale; | ||
421 | } | ||
422 | } | ||
423 | return msg; | ||
424 | } | ||
425 | |||
426 | static const struct LIS3DSHVMT vmt_device = { | ||
427 | (size_t)0, | ||
428 | acc_set_full_scale | ||
429 | }; | ||
430 | |||
431 | static const struct BaseAccelerometerVMT vmt_accelerometer = { | ||
432 | sizeof(struct LIS3DSHVMT*), | ||
433 | acc_get_axes_number, acc_read_raw, acc_read_cooked, | ||
434 | acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity | ||
435 | }; | ||
436 | |||
437 | /*===========================================================================*/ | ||
438 | /* Driver exported functions. */ | ||
439 | /*===========================================================================*/ | ||
440 | |||
441 | /** | ||
442 | * @brief Initializes an instance. | ||
443 | * | ||
444 | * @param[out] devp pointer to the @p LIS3DSHDriver object | ||
445 | * | ||
446 | * @init | ||
447 | */ | ||
448 | void lis3dshObjectInit(LIS3DSHDriver *devp) { | ||
449 | devp->vmt = &vmt_device; | ||
450 | devp->acc_if.vmt = &vmt_accelerometer; | ||
451 | |||
452 | devp->config = NULL; | ||
453 | |||
454 | devp->accaxes = LIS3DSH_ACC_NUMBER_OF_AXES; | ||
455 | |||
456 | devp->state = LIS3DSH_STOP; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * @brief Configures and activates LIS3DSH Complex Driver peripheral. | ||
461 | * | ||
462 | * @param[in] devp pointer to the @p LIS3DSHDriver object | ||
463 | * @param[in] config pointer to the @p LIS3DSHConfig object | ||
464 | * | ||
465 | * @api | ||
466 | */ | ||
467 | void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config) { | ||
468 | uint32_t i; | ||
469 | uint8_t cr; | ||
470 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
471 | |||
472 | osalDbgAssert((devp->state == LIS3DSH_STOP) || | ||
473 | (devp->state == LIS3DSH_READY), | ||
474 | "lis3dshStart(), invalid state"); | ||
475 | |||
476 | devp->config = config; | ||
477 | |||
478 | /* Control register 4 configuration block.*/ | ||
479 | { | ||
480 | cr = LIS3DSH_CTRL_REG4_XEN | LIS3DSH_CTRL_REG4_YEN | LIS3DSH_CTRL_REG4_ZEN | | ||
481 | devp->config->accoutputdatarate; | ||
482 | #if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) | ||
483 | cr |= devp->config->accblockdataupdate; | ||
484 | #endif | ||
485 | } | ||
486 | |||
487 | #if LIS3DSH_USE_SPI | ||
488 | #if LIS3DSH_SHARED_SPI | ||
489 | spiAcquireBus(devp->config->spip); | ||
490 | #endif /* LIS3DSH_SHARED_SPI */ | ||
491 | spiStart(devp->config->spip, devp->config->spicfg); | ||
492 | |||
493 | lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4, 1, &cr); | ||
494 | |||
495 | #if LIS3DSH_SHARED_SPI | ||
496 | spiReleaseBus(devp->config->spip); | ||
497 | #endif /* LIS3DSH_SHARED_SPI */ | ||
498 | #endif /* LIS3DSH_USE_SPI */ | ||
499 | |||
500 | /* Control register 5 configuration block.*/ | ||
501 | { | ||
502 | cr = devp->config->accfullscale; | ||
503 | #if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) | ||
504 | cr |= devp->config->accantialiasing; | ||
505 | #endif | ||
506 | } | ||
507 | |||
508 | #if LIS3DSH_USE_SPI | ||
509 | #if LIS3DSH_SHARED_SPI | ||
510 | spiAcquireBus(devp->config->spip); | ||
511 | spiStart(devp->config->spip, devp->config->spicfg); | ||
512 | #endif /* LIS3DSH_SHARED_SPI */ | ||
513 | |||
514 | lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG5, 1, &cr); | ||
515 | |||
516 | #if LIS3DSH_SHARED_SPI | ||
517 | spiReleaseBus(devp->config->spip); | ||
518 | #endif /* LIS3DSH_SHARED_SPI */ | ||
519 | #endif /* LIS3DSH_USE_SPI */ | ||
520 | |||
521 | /* Control register 6 configuration block.*/ | ||
522 | { | ||
523 | cr = LIS3DSH_CTRL_REG6_ADD_INC; | ||
524 | #if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) | ||
525 | cr |= devp->config->accblockdataupdate; | ||
526 | #endif | ||
527 | } | ||
528 | |||
529 | #if LIS3DSH_USE_SPI | ||
530 | #if LIS3DSH_SHARED_SPI | ||
531 | spiAcquireBus(devp->config->spip); | ||
532 | spiStart(devp->config->spip, devp->config->spicfg); | ||
533 | #endif /* LIS3DSH_SHARED_SPI */ | ||
534 | |||
535 | lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG6, 1, &cr); | ||
536 | |||
537 | #if LIS3DSH_SHARED_SPI | ||
538 | spiReleaseBus(devp->config->spip); | ||
539 | #endif /* LIS3DSH_SHARED_SPI */ | ||
540 | #endif /* LIS3DSH_USE_SPI */ | ||
541 | |||
542 | /* Storing sensitivity information according to user setting */ | ||
543 | if(devp->config->accfullscale == LIS3DSH_ACC_FS_2G) { | ||
544 | devp->accfullscale = LIS3DSH_ACC_2G; | ||
545 | if(devp->config->accsensitivity == NULL) | ||
546 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
547 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_2G; | ||
548 | else | ||
549 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
550 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
551 | } | ||
552 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_4G) { | ||
553 | devp->accfullscale = LIS3DSH_ACC_4G; | ||
554 | if(devp->config->accsensitivity == NULL) | ||
555 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
556 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_4G; | ||
557 | else | ||
558 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
559 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
560 | } | ||
561 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_6G) { | ||
562 | devp->accfullscale = LIS3DSH_ACC_6G; | ||
563 | if(devp->config->accsensitivity == NULL) | ||
564 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
565 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_6G; | ||
566 | else | ||
567 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
568 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
569 | } | ||
570 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_8G) { | ||
571 | devp->accfullscale = LIS3DSH_ACC_8G; | ||
572 | if(devp->config->accsensitivity == NULL) | ||
573 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
574 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_8G; | ||
575 | else | ||
576 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
577 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
578 | } | ||
579 | else if(devp->config->accfullscale == LIS3DSH_ACC_FS_16G) { | ||
580 | devp->accfullscale = LIS3DSH_ACC_16G; | ||
581 | if(devp->config->accsensitivity == NULL) | ||
582 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
583 | devp->accsensitivity[i] = LIS3DSH_ACC_SENS_16G; | ||
584 | else | ||
585 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
586 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
587 | } | ||
588 | else { | ||
589 | osalDbgAssert(FALSE, "lis3dshStart(), accelerometer full scale issue"); | ||
590 | } | ||
591 | |||
592 | /* Storing bias information according to user setting */ | ||
593 | if(devp->config->accbias != NULL) | ||
594 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
595 | devp->accbias[i] = devp->config->accbias[i]; | ||
596 | else | ||
597 | for(i = 0; i < LIS3DSH_ACC_NUMBER_OF_AXES; i++) | ||
598 | devp->accbias[i] = LIS3DSH_ACC_BIAS; | ||
599 | |||
600 | /* This is the Accelerometer transient recovery time */ | ||
601 | osalThreadSleepMilliseconds(10); | ||
602 | |||
603 | devp->state = LIS3DSH_READY; | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * @brief Deactivates the LIS3DSH Complex Driver peripheral. | ||
608 | * | ||
609 | * @param[in] devp pointer to the @p LIS3DSHDriver object | ||
610 | * | ||
611 | * @api | ||
612 | */ | ||
613 | void lis3dshStop(LIS3DSHDriver *devp) { | ||
614 | uint8_t cr4; | ||
615 | osalDbgCheck(devp != NULL); | ||
616 | |||
617 | osalDbgAssert((devp->state == LIS3DSH_STOP) || | ||
618 | (devp->state == LIS3DSH_READY), | ||
619 | "lis3dshStop(), invalid state"); | ||
620 | |||
621 | if (devp->state == LIS3DSH_READY) { | ||
622 | #if (LIS3DSH_USE_SPI) | ||
623 | #if LIS3DSH_SHARED_SPI | ||
624 | spiAcquireBus(devp->config->spip); | ||
625 | spiStart(devp->config->spip, | ||
626 | devp->config->spicfg); | ||
627 | #endif /* LIS3DSH_SHARED_SPI */ | ||
628 | /* Disabling all axes and enabling power down mode.*/ | ||
629 | cr4 = 0; | ||
630 | lis3dshSPIWriteRegister(devp->config->spip, LIS3DSH_AD_CTRL_REG4, | ||
631 | 1, &cr4); | ||
632 | |||
633 | spiStop(devp->config->spip); | ||
634 | #if LIS3DSH_SHARED_SPI | ||
635 | spiReleaseBus(devp->config->spip); | ||
636 | #endif /* LIS3DSH_SHARED_SPI */ | ||
637 | #endif /* LIS3DSH_USE_SPI */ | ||
638 | } | ||
639 | devp->state = LIS3DSH_STOP; | ||
640 | } | ||
641 | /** @} */ | ||
diff --git a/lib/chibios/os/ex/devices/ST/lis3dsh.h b/lib/chibios/os/ex/devices/ST/lis3dsh.h new file mode 100644 index 000000000..6f569091d --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3dsh.h | |||
@@ -0,0 +1,708 @@ | |||
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 lis3dsh.h | ||
23 | * @brief LIS3DSH MEMS interface module header. | ||
24 | * | ||
25 | * @addtogroup LIS3DSH | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #ifndef _LIS3DSH_H_ | ||
31 | #define _LIS3DSH_H_ | ||
32 | |||
33 | #include "ex_accelerometer.h" | ||
34 | |||
35 | /*===========================================================================*/ | ||
36 | /* Driver constants. */ | ||
37 | /*===========================================================================*/ | ||
38 | |||
39 | /** | ||
40 | * @name Version identification | ||
41 | * @{ | ||
42 | */ | ||
43 | /** | ||
44 | * @brief LIS3DSH driver version string. | ||
45 | */ | ||
46 | #define EX_LIS3DSH_VERSION "1.1.2" | ||
47 | |||
48 | /** | ||
49 | * @brief LIS3DSH driver version major number. | ||
50 | */ | ||
51 | #define EX_LIS3DSH_MAJOR 1 | ||
52 | |||
53 | /** | ||
54 | * @brief LIS3DSH driver version minor number. | ||
55 | */ | ||
56 | #define EX_LIS3DSH_MINOR 1 | ||
57 | |||
58 | /** | ||
59 | * @brief LIS3DSH driver version patch number. | ||
60 | */ | ||
61 | #define EX_LIS3DSH_PATCH 2 | ||
62 | /** @} */ | ||
63 | |||
64 | /** | ||
65 | * @brief LIS3DSH accelerometer subsystem characteristics. | ||
66 | * @note Sensitivity is expressed as milli-G/LSB whereas | ||
67 | * 1 milli-G = 0.00980665 m/s^2. | ||
68 | * @note Bias is expressed as milli-G. | ||
69 | * | ||
70 | * @{ | ||
71 | */ | ||
72 | #define LIS3DSH_ACC_NUMBER_OF_AXES 3U | ||
73 | |||
74 | #define LIS3DSH_ACC_2G 2.0f | ||
75 | #define LIS3DSH_ACC_4G 4.0f | ||
76 | #define LIS3DSH_ACC_6G 6.0f | ||
77 | #define LIS3DSH_ACC_8G 8.0f | ||
78 | #define LIS3DSH_ACC_16G 16.0f | ||
79 | |||
80 | #define LIS3DSH_ACC_SENS_2G 0.06f | ||
81 | #define LIS3DSH_ACC_SENS_4G 0.12f | ||
82 | #define LIS3DSH_ACC_SENS_6G 0.18f | ||
83 | #define LIS3DSH_ACC_SENS_8G 0.24f | ||
84 | #define LIS3DSH_ACC_SENS_16G 0.73f | ||
85 | |||
86 | #define LIS3DSH_ACC_BIAS 0.0f | ||
87 | /** @} */ | ||
88 | |||
89 | /** | ||
90 | * @name LIS3DSH communication interfaces related bit masks | ||
91 | * @{ | ||
92 | */ | ||
93 | #define LIS3DSH_DI_MASK 0xFF | ||
94 | #define LIS3DSH_DI(n) (1 << n) | ||
95 | #define LIS3DSH_AD_MASK 0x3F | ||
96 | #define LIS3DSH_AD(n) (1 << n) | ||
97 | #define LIS3DSH_MS (1 << 6) | ||
98 | #define LIS3DSH_RW (1 << 7) | ||
99 | /** @} */ | ||
100 | |||
101 | /** | ||
102 | * @name LIS3DSH register addresses | ||
103 | * @{ | ||
104 | */ | ||
105 | #define LIS3DSH_AD_OUT_T 0x0C | ||
106 | #define LIS3DSH_AD_INFO1 0x0D | ||
107 | #define LIS3DSH_AD_INFO2 0x0E | ||
108 | #define LIS3DSH_AD_WHO_AM_I 0x0F | ||
109 | #define LIS3DSH_AD_OFF_X 0x10 | ||
110 | #define LIS3DSH_AD_OFF_Y 0x11 | ||
111 | #define LIS3DSH_AD_OFF_Z 0x12 | ||
112 | #define LIS3DSH_AD_CS_X 0x13 | ||
113 | #define LIS3DSH_AD_CS_Y 0x14 | ||
114 | #define LIS3DSH_AD_CS_Z 0x15 | ||
115 | #define LIS3DSH_AD_LC_L 0x16 | ||
116 | #define LIS3DSH_AD_LC_H 0x17 | ||
117 | #define LIS3DSH_AD_STAT 0x18 | ||
118 | #define LIS3DSH_AD_PEAK1 0x19 | ||
119 | #define LIS3DSH_AD_PEAK2 0x1A | ||
120 | #define LIS3DSH_AD_VFC_1 0x1B | ||
121 | #define LIS3DSH_AD_VFC_2 0x1C | ||
122 | #define LIS3DSH_AD_VFC_3 0x1D | ||
123 | #define LIS3DSH_AD_VFC_4 0x1E | ||
124 | #define LIS3DSH_AD_THRS3 0x1F | ||
125 | #define LIS3DSH_AD_CTRL_REG4 0x20 | ||
126 | #define LIS3DSH_AD_CTRL_REG1 0x21 | ||
127 | #define LIS3DSH_AD_CTRL_REG2 0x22 | ||
128 | #define LIS3DSH_AD_CTRL_REG3 0x23 | ||
129 | #define LIS3DSH_AD_CTRL_REG5 0x24 | ||
130 | #define LIS3DSH_AD_CTRL_REG6 0x25 | ||
131 | #define LIS3DSH_AD_STATUS 0x27 | ||
132 | #define LIS3DSH_AD_OUT_X_L 0x28 | ||
133 | #define LIS3DSH_AD_OUT_X_H 0x29 | ||
134 | #define LIS3DSH_AD_OUT_Y_L 0x2A | ||
135 | #define LIS3DSH_AD_OUT_Y_H 0x2B | ||
136 | #define LIS3DSH_AD_OUT_Z_L 0x2C | ||
137 | #define LIS3DSH_AD_OUT_Z_H 0x2D | ||
138 | #define LIS3DSH_AD_FIFO_CTRL 0x2E | ||
139 | #define LIS3DSH_AD_FIFO_SRC 0x2F | ||
140 | #define LIS3DSH_AD_ST1_0 0x40 | ||
141 | #define LIS3DSH_AD_ST1_1 0x41 | ||
142 | #define LIS3DSH_AD_ST1_2 0x42 | ||
143 | #define LIS3DSH_AD_ST1_3 0x43 | ||
144 | #define LIS3DSH_AD_ST1_4 0x44 | ||
145 | #define LIS3DSH_AD_ST1_5 0x45 | ||
146 | #define LIS3DSH_AD_ST1_6 0x46 | ||
147 | #define LIS3DSH_AD_ST1_7 0x47 | ||
148 | #define LIS3DSH_AD_ST1_8 0x48 | ||
149 | #define LIS3DSH_AD_ST1_9 0x49 | ||
150 | #define LIS3DSH_AD_ST1_A 0x4A | ||
151 | #define LIS3DSH_AD_ST1_B 0x4B | ||
152 | #define LIS3DSH_AD_ST1_C 0x4C | ||
153 | #define LIS3DSH_AD_ST1_D 0x4D | ||
154 | #define LIS3DSH_AD_ST1_E 0x4E | ||
155 | #define LIS3DSH_AD_ST1_F 0x4F | ||
156 | #define LIS3DSH_AD_TIM4_1 0x50 | ||
157 | #define LIS3DSH_AD_TIM3_1 0x51 | ||
158 | #define LIS3DSH_AD_TIM2_1_L 0x52 | ||
159 | #define LIS3DSH_AD_TIM2_1_H 0x53 | ||
160 | #define LIS3DSH_AD_TIM1_1_L 0x54 | ||
161 | #define LIS3DSH_AD_TIM1_1_H 0x55 | ||
162 | #define LIS3DSH_AD_THRS2_1 0x56 | ||
163 | #define LIS3DSH_AD_THRS1_1 0x57 | ||
164 | #define LIS3DSH_AD_MASK1_B 0x59 | ||
165 | #define LIS3DSH_AD_MASK1_A 0x5A | ||
166 | #define LIS3DSH_AD_SETT1 0x5B | ||
167 | #define LIS3DSH_AD_PR1 0x5C | ||
168 | #define LIS3DSH_AD_TC1_L 0x5D | ||
169 | #define LIS3DSH_AD_TC1_H 0x5E | ||
170 | #define LIS3DSH_AD_OUTS1 0x5F | ||
171 | #define LIS3DSH_AD_ST2_0 0x60 | ||
172 | #define LIS3DSH_AD_ST2_1 0x61 | ||
173 | #define LIS3DSH_AD_ST2_2 0x62 | ||
174 | #define LIS3DSH_AD_ST2_3 0x63 | ||
175 | #define LIS3DSH_AD_ST2_4 0x64 | ||
176 | #define LIS3DSH_AD_ST2_5 0x65 | ||
177 | #define LIS3DSH_AD_ST2_6 0x66 | ||
178 | #define LIS3DSH_AD_ST2_7 0x67 | ||
179 | #define LIS3DSH_AD_ST2_8 0x68 | ||
180 | #define LIS3DSH_AD_ST2_9 0x69 | ||
181 | #define LIS3DSH_AD_ST2_A 0x6A | ||
182 | #define LIS3DSH_AD_ST2_B 0x6B | ||
183 | #define LIS3DSH_AD_ST2_C 0x6C | ||
184 | #define LIS3DSH_AD_ST2_D 0x6D | ||
185 | #define LIS3DSH_AD_ST2_E 0x6E | ||
186 | #define LIS3DSH_AD_ST2_F 0x6F | ||
187 | #define LIS3DSH_AD_TIM4_2 0x70 | ||
188 | #define LIS3DSH_AD_TIM3_2 0x71 | ||
189 | #define LIS3DSH_AD_TIM2_2_L 0x72 | ||
190 | #define LIS3DSH_AD_TIM2_2_H 0x73 | ||
191 | #define LIS3DSH_AD_TIM1_2_L 0x74 | ||
192 | #define LIS3DSH_AD_TIM1_2_H 0x75 | ||
193 | #define LIS3DSH_AD_THRS2_2 0x76 | ||
194 | #define LIS3DSH_AD_THRS1_2 0x77 | ||
195 | #define LIS3DSH_AD_DES2 0x78 | ||
196 | #define LIS3DSH_AD_MASK2_B 0x79 | ||
197 | #define LIS3DSH_AD_MASK2_A 0x7A | ||
198 | #define LIS3DSH_AD_SETT2 0x7B | ||
199 | #define LIS3DSH_AD_PR2 0x7C | ||
200 | #define LIS3DSH_AD_TC2_L 0x7D | ||
201 | #define LIS3DSH_AD_TC2_H 0x7E | ||
202 | #define LIS3DSH_AD_OUTS2 0x7F | ||
203 | /** @} */ | ||
204 | |||
205 | /** | ||
206 | * @name LIS3DSH_CTRL_REG1 register bits definitions | ||
207 | * @{ | ||
208 | */ | ||
209 | #define LIS3DSH_CTRL_REG1_MASK 0xE9 | ||
210 | #define LIS3DSH_CTRL_REG1_SM1_EN (1 << 0) | ||
211 | #define LIS3DSH_CTRL_REG1_SM1_PIN (1 << 3) | ||
212 | #define LIS3DSH_CTRL_REG1_HYST0_1 (1 << 5) | ||
213 | #define LIS3DSH_CTRL_REG1_HYST1_1 (1 << 6) | ||
214 | #define LIS3DSH_CTRL_REG1_HYST2_1 (1 << 7) | ||
215 | /** @} */ | ||
216 | |||
217 | /** | ||
218 | * @name LIS3DSH_CTRL_REG2 register bits definitions | ||
219 | * @{ | ||
220 | */ | ||
221 | #define LIS3DSH_CTRL_REG2_MASK 0xE9 | ||
222 | #define LIS3DSH_CTRL_REG2_SM2_EN (1 << 0) | ||
223 | #define LIS3DSH_CTRL_REG2_SM2_PIN (1 << 3) | ||
224 | #define LIS3DSH_CTRL_REG2_HYST0_2 (1 << 5) | ||
225 | #define LIS3DSH_CTRL_REG2_HYST1_2 (1 << 6) | ||
226 | #define LIS3DSH_CTRL_REG2_HYST2_2 (1 << 7) | ||
227 | /** @} */ | ||
228 | |||
229 | /** | ||
230 | * @name LIS3DSH_CTRL_REG3 register bits definitions | ||
231 | * @{ | ||
232 | */ | ||
233 | #define LIS3DSH_CTRL_REG3_MASK 0xFF | ||
234 | #define LIS3DSH_CTRL_REG3_STRT (1 << 0) | ||
235 | #define LIS3DSH_CTRL_REG3_VFILT (1 << 2) | ||
236 | #define LIS3DSH_CTRL_REG3_INT1_EN (1 << 3) | ||
237 | #define LIS3DSH_CTRL_REG3_INT2_EN (1 << 4) | ||
238 | #define LIS3DSH_CTRL_REG3_IEL (1 << 5) | ||
239 | #define LIS3DSH_CTRL_REG3_IEA (1 << 6) | ||
240 | #define LIS3DSH_CTRL_REG3_DR_EN (1 << 7) | ||
241 | /** @} */ | ||
242 | |||
243 | /** | ||
244 | * @name LIS3DSH_CTRL_REG4 register bits definitions | ||
245 | * @{ | ||
246 | */ | ||
247 | #define LIS3DSH_CTRL_REG4_MASK 0xFF | ||
248 | #define LIS3DSH_CTRL_REG4_XEN (1 << 0) | ||
249 | #define LIS3DSH_CTRL_REG4_YEN (1 << 1) | ||
250 | #define LIS3DSH_CTRL_REG4_ZEN (1 << 2) | ||
251 | #define LIS3DSH_CTRL_REG4_BDU (1 << 3) | ||
252 | #define LIS3DSH_CTRL_REG4_ODR_0 (1 << 4) | ||
253 | #define LIS3DSH_CTRL_REG4_ODR_1 (1 << 5) | ||
254 | #define LIS3DSH_CTRL_REG4_ODR_2 (1 << 6) | ||
255 | #define LIS3DSH_CTRL_REG4_ODR_3 (1 << 7) | ||
256 | /** @} */ | ||
257 | |||
258 | /** | ||
259 | * @name LIS3DSH_CTRL_REG5 register bits definitions | ||
260 | * @{ | ||
261 | */ | ||
262 | #define LIS3DSH_CTRL_REG5_MASK 0xFF | ||
263 | #define LIS3DSH_CTRL_REG5_SIM (1 << 0) | ||
264 | #define LIS3DSH_CTRL_REG5_ST1 (1 << 1) | ||
265 | #define LIS3DSH_CTRL_REG5_ST2 (1 << 2) | ||
266 | #define LIS3DSH_CTRL_REG5_FS_MASK 0x38 | ||
267 | #define LIS3DSH_CTRL_REG5_FS0 (1 << 3) | ||
268 | #define LIS3DSH_CTRL_REG5_FS1 (1 << 4) | ||
269 | #define LIS3DSH_CTRL_REG5_FS2 (1 << 5) | ||
270 | #define LIS3DSH_CTRL_REG5_BW1 (1 << 6) | ||
271 | #define LIS3DSH_CTRL_REG5_BW2 (1 << 7) | ||
272 | /** @} */ | ||
273 | |||
274 | /** | ||
275 | * @name LIS3DSH_CTRL_REG6 register bits definitions | ||
276 | * @{ | ||
277 | */ | ||
278 | #define LIS3DSH_CTRL_REG6_MASK 0xFF | ||
279 | #define LIS3DSH_CTRL_REG6_P2_BOOT (1 << 0) | ||
280 | #define LIS3DSH_CTRL_REG6_P1_OVRUN (1 << 1) | ||
281 | #define LIS3DSH_CTRL_REG6_P1_WTM (1 << 2) | ||
282 | #define LIS3DSH_CTRL_REG6_P1_EMPTY (1 << 3) | ||
283 | #define LIS3DSH_CTRL_REG6_ADD_INC (1 << 4) | ||
284 | #define LIS3DSH_CTRL_REG6_WTM_EN (1 << 5) | ||
285 | #define LIS3DSH_CTRL_REG6_FIFO_EN (1 << 6) | ||
286 | #define LIS3DSH_CTRL_REG6_BOOT (1 << 7) | ||
287 | /** @} */ | ||
288 | |||
289 | /*===========================================================================*/ | ||
290 | /* Driver pre-compile time settings. */ | ||
291 | /*===========================================================================*/ | ||
292 | |||
293 | /** | ||
294 | * @name Configuration options | ||
295 | * @{ | ||
296 | */ | ||
297 | /** | ||
298 | * @brief LIS3DSH SPI interface switch. | ||
299 | * @details If set to @p TRUE the support for SPI is included. | ||
300 | * @note The default is @p TRUE. | ||
301 | */ | ||
302 | #if !defined(LIS3DSH_USE_SPI) || defined(__DOXYGEN__) | ||
303 | #define LIS3DSH_USE_SPI TRUE | ||
304 | #endif | ||
305 | |||
306 | /** | ||
307 | * @brief LIS3DSH shared SPI switch. | ||
308 | * @details If set to @p TRUE the device acquires SPI bus ownership | ||
309 | * on each transaction. | ||
310 | * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. | ||
311 | */ | ||
312 | #if !defined(LIS3DSH_SHARED_SPI) || defined(__DOXYGEN__) | ||
313 | #define LIS3DSH_SHARED_SPI FALSE | ||
314 | #endif | ||
315 | |||
316 | /** | ||
317 | * @brief LIS3DSH I2C interface switch. | ||
318 | * @details If set to @p TRUE the support for I2C is included. | ||
319 | * @note The default is @p FALSE. | ||
320 | */ | ||
321 | #if !defined(LIS3DSH_USE_I2C) || defined(__DOXYGEN__) | ||
322 | #define LIS3DSH_USE_I2C FALSE | ||
323 | #endif | ||
324 | |||
325 | /** | ||
326 | * @brief LIS3DSH shared I2C switch. | ||
327 | * @details If set to @p TRUE the device acquires I2C bus ownership | ||
328 | * on each transaction. | ||
329 | * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. | ||
330 | */ | ||
331 | #if !defined(LIS3DSH_SHARED_I2C) || defined(__DOXYGEN__) | ||
332 | #define LIS3DSH_SHARED_I2C FALSE | ||
333 | #endif | ||
334 | |||
335 | /** | ||
336 | * @brief LIS3DSH advanced configurations switch. | ||
337 | * @details If set to @p TRUE more configurations are available. | ||
338 | * @note The default is @p FALSE. | ||
339 | */ | ||
340 | #if !defined(LIS3DSH_USE_ADVANCED) || defined(__DOXYGEN__) | ||
341 | #define LIS3DSH_USE_ADVANCED FALSE | ||
342 | #endif | ||
343 | /** @} */ | ||
344 | |||
345 | /*===========================================================================*/ | ||
346 | /* Derived constants and error checks. */ | ||
347 | /*===========================================================================*/ | ||
348 | |||
349 | #if !(LIS3DSH_USE_SPI ^ LIS3DSH_USE_I2C) | ||
350 | #error "LIS3DSH_USE_SPI and LIS3DSH_USE_I2C cannot be both true or both false" | ||
351 | #endif | ||
352 | |||
353 | #if LIS3DSH_USE_SPI && !HAL_USE_SPI | ||
354 | #error "LIS3DSH_USE_SPI requires HAL_USE_SPI" | ||
355 | #endif | ||
356 | |||
357 | #if LIS3DSH_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION | ||
358 | #error "LIS3DSH_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" | ||
359 | #endif | ||
360 | |||
361 | #if LIS3DSH_USE_I2C && !HAL_USE_I2C | ||
362 | #error "LIS3DSH_USE_I2C requires HAL_USE_I2C" | ||
363 | #endif | ||
364 | |||
365 | #if LIS3DSH_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION | ||
366 | #error "LIS3DSH_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" | ||
367 | #endif | ||
368 | |||
369 | /* | ||
370 | * CHTODO: Add support for LIS3DSH over I2C. | ||
371 | */ | ||
372 | #if LIS3DSH_USE_I2C | ||
373 | #error "LIS3DSH over I2C still not supported" | ||
374 | #endif | ||
375 | |||
376 | /*===========================================================================*/ | ||
377 | /* Driver data structures and types. */ | ||
378 | /*===========================================================================*/ | ||
379 | |||
380 | /** | ||
381 | * @name LIS3DSH data structures and types | ||
382 | * @{ | ||
383 | */ | ||
384 | /** | ||
385 | * @brief Structure representing a LIS3DSH driver. | ||
386 | */ | ||
387 | typedef struct LIS3DSHDriver LIS3DSHDriver; | ||
388 | |||
389 | /** | ||
390 | * @brief LIS3DSH full scale. | ||
391 | */ | ||
392 | typedef enum { | ||
393 | LIS3DSH_ACC_FS_2G = 0x00, /**< Full scale �2g. */ | ||
394 | LIS3DSH_ACC_FS_4G = 0x08, /**< Full scale �4g. */ | ||
395 | LIS3DSH_ACC_FS_6G = 0x10, /**< Full scale �6g. */ | ||
396 | LIS3DSH_ACC_FS_8G = 0x18, /**< Full scale �8g. */ | ||
397 | LIS3DSH_ACC_FS_16G = 0x20 /**< Full scale �16g. */ | ||
398 | }lis3dsh_acc_fs_t; | ||
399 | |||
400 | /** | ||
401 | * @brief LIS3DSH output data rate. | ||
402 | */ | ||
403 | typedef enum { | ||
404 | LIS3DSH_ACC_ODR_PD = 0x00, /**< ODR 100 Hz. */ | ||
405 | LIS3DSH_ACC_ODR_3_125HZ = 0x10, /**< ODR 3.125 Hz. */ | ||
406 | LIS3DSH_ACC_ODR_6_25HZ = 0x20, /**< ODR 6.25 Hz. */ | ||
407 | LIS3DSH_ACC_ODR_12_5HZ = 0x30, /**< ODR 12.5 Hz. */ | ||
408 | LIS3DSH_ACC_ODR_25HZ = 0x40, /**< ODR 25 Hz. */ | ||
409 | LIS3DSH_ACC_ODR_50HZ = 0x50, /**< ODR 50 Hz. */ | ||
410 | LIS3DSH_ACC_ODR_100HZ = 0x60, /**< ODR 100 Hz. */ | ||
411 | LIS3DSH_ACC_ODR_400HZ = 0x70, /**< ODR 400 Hz. */ | ||
412 | LIS3DSH_ACC_ODR_800HZ = 0x80, /**< ODR 800 Hz. */ | ||
413 | LIS3DSH_ACC_ODR_1600HZ = 0x90 /**< ODR 1600 Hz. */ | ||
414 | }lis3dsh_acc_odr_t; | ||
415 | |||
416 | /** | ||
417 | * @brief LIS3DSH anti-aliasing bandwidth. | ||
418 | */ | ||
419 | typedef enum { | ||
420 | LIS3DSH_ACC_BW_800HZ = 0x00, /**< AA filter BW 800Hz. */ | ||
421 | LIS3DSH_ACC_BW_200HZ = 0x40, /**< AA filter BW 200Hz. */ | ||
422 | LIS3DSH_ACC_BW_400HZ = 0x80, /**< AA filter BW 400Hz. */ | ||
423 | LIS3DSH_ACC_BW_50HZ = 0xC0 /**< AA filter BW 50Hz. */ | ||
424 | }lis3dsh_acc_bw_t; | ||
425 | |||
426 | /** | ||
427 | * @brief LIS3DSH block data update. | ||
428 | */ | ||
429 | typedef enum { | ||
430 | LIS3DSH_ACC_BDU_CONTINUOUS = 0x00,/**< Block data continuously updated. */ | ||
431 | LIS3DSH_ACC_BDU_BLOCKED = 0x80 /**< Block data updated after reading. */ | ||
432 | } lis3dsh_acc_bdu_t; | ||
433 | |||
434 | /** | ||
435 | * @brief Driver state machine possible states. | ||
436 | */ | ||
437 | typedef enum { | ||
438 | LIS3DSH_UNINIT = 0, /**< Not initialized. */ | ||
439 | LIS3DSH_STOP = 1, /**< Stopped. */ | ||
440 | LIS3DSH_READY = 2, /**< Ready. */ | ||
441 | } lis3dsh_state_t; | ||
442 | |||
443 | /** | ||
444 | * @brief LIS3DSH configuration structure. | ||
445 | */ | ||
446 | typedef struct { | ||
447 | |||
448 | #if (LIS3DSH_USE_SPI) || defined(__DOXYGEN__) | ||
449 | /** | ||
450 | * @brief SPI driver associated to this LIS3DSH. | ||
451 | */ | ||
452 | SPIDriver *spip; | ||
453 | /** | ||
454 | * @brief SPI configuration associated to this LIS3DSH. | ||
455 | */ | ||
456 | const SPIConfig *spicfg; | ||
457 | #endif /* LIS3DSH_USE_SPI */ | ||
458 | #if (LIS3DSH_USE_I2C) || defined(__DOXYGEN__) | ||
459 | /** | ||
460 | * @brief I2C driver associated to this LIS3DSH. | ||
461 | */ | ||
462 | I2CDriver *i2cp; | ||
463 | /** | ||
464 | * @brief I2C configuration associated to this LIS3DSH. | ||
465 | */ | ||
466 | const I2CConfig *i2ccfg; | ||
467 | #endif /* LIS3DSH_USE_I2C */ | ||
468 | /** | ||
469 | * @brief LIS3DSH accelerometer subsystem initial sensitivity. | ||
470 | */ | ||
471 | float *accsensitivity; | ||
472 | /** | ||
473 | * @brief LIS3DSH accelerometer subsystem initial bias. | ||
474 | */ | ||
475 | float *accbias; | ||
476 | /** | ||
477 | * @brief LIS3DSH accelerometer subsystem initial full scale. | ||
478 | */ | ||
479 | lis3dsh_acc_fs_t accfullscale; | ||
480 | /** | ||
481 | * @brief LIS3DSH output data rate selection. | ||
482 | */ | ||
483 | lis3dsh_acc_odr_t accoutputdatarate; | ||
484 | #if LIS3DSH_USE_ADVANCED || defined(__DOXYGEN__) | ||
485 | /** | ||
486 | * @brief LIS3DSH anti-aliasing bandwidth. | ||
487 | */ | ||
488 | lis3dsh_acc_bw_t accantialiasing; | ||
489 | /** | ||
490 | * @brief LIS3DSH block data update. | ||
491 | */ | ||
492 | lis3dsh_acc_bdu_t accblockdataupdate; | ||
493 | #endif | ||
494 | } LIS3DSHConfig; | ||
495 | |||
496 | /** | ||
497 | * @brief @p LIS3DSH specific methods. | ||
498 | */ | ||
499 | #define _lis3dsh_methods_alone \ | ||
500 | /* Change full scale value of LIS3DSH accelerometer subsystem.*/ \ | ||
501 | msg_t (*acc_set_full_scale)(LIS3DSHDriver *devp, lis3dsh_acc_fs_t fs); | ||
502 | |||
503 | |||
504 | /** | ||
505 | * @brief @p LIS3DSH specific methods with inherited ones. | ||
506 | */ | ||
507 | #define _lis3dsh_methods \ | ||
508 | _base_object_methods \ | ||
509 | _lis3dsh_methods_alone | ||
510 | |||
511 | /** | ||
512 | * @extends BaseObjectVMT | ||
513 | * | ||
514 | * @brief @p LIS3DSH virtual methods table. | ||
515 | */ | ||
516 | struct LIS3DSHVMT { | ||
517 | _lis3dsh_methods | ||
518 | }; | ||
519 | |||
520 | /** | ||
521 | * @brief @p LIS3DSHDriver specific data. | ||
522 | */ | ||
523 | #define _lis3dsh_data \ | ||
524 | _base_sensor_data \ | ||
525 | /* Driver state.*/ \ | ||
526 | lis3dsh_state_t state; \ | ||
527 | /* Current configuration data.*/ \ | ||
528 | const LIS3DSHConfig *config; \ | ||
529 | /* Accelerometer subsystem axes number.*/ \ | ||
530 | size_t accaxes; \ | ||
531 | /* Accelerometer subsystem current sensitivity.*/ \ | ||
532 | float accsensitivity[LIS3DSH_ACC_NUMBER_OF_AXES]; \ | ||
533 | /* Accelerometer subsystem current bias .*/ \ | ||
534 | float accbias[LIS3DSH_ACC_NUMBER_OF_AXES]; \ | ||
535 | /* Accelerometer subsystem current full scale value.*/ \ | ||
536 | float accfullscale; | ||
537 | |||
538 | /** | ||
539 | * @brief LIS3DSH 3-axis accelerometer class. | ||
540 | */ | ||
541 | struct LIS3DSHDriver { | ||
542 | /** @brief Virtual Methods Table.*/ | ||
543 | const struct LIS3DSHVMT *vmt; | ||
544 | /** @brief Base accelerometer interface.*/ | ||
545 | BaseAccelerometer acc_if; | ||
546 | _lis3dsh_data | ||
547 | }; | ||
548 | /** @} */ | ||
549 | |||
550 | /*===========================================================================*/ | ||
551 | /* Driver macros. */ | ||
552 | /*===========================================================================*/ | ||
553 | |||
554 | /** | ||
555 | * @brief Return the number of axes of the BaseAccelerometer. | ||
556 | * | ||
557 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
558 | * | ||
559 | * @return the number of axes. | ||
560 | * | ||
561 | * @api | ||
562 | */ | ||
563 | #define lis3dshAccelerometerGetAxesNumber(devp) \ | ||
564 | accelerometerGetAxesNumber(&((devp)->acc_if)) | ||
565 | |||
566 | /** | ||
567 | * @brief Retrieves raw data from the BaseAccelerometer. | ||
568 | * @note This data is retrieved from MEMS register without any algebraical | ||
569 | * manipulation. | ||
570 | * @note The axes array must be at least the same size of the | ||
571 | * BaseAccelerometer axes number. | ||
572 | * | ||
573 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
574 | * @param[out] axes a buffer which would be filled with raw data. | ||
575 | * | ||
576 | * @return The operation status. | ||
577 | * @retval MSG_OK if the function succeeded. | ||
578 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
579 | * be retrieved using @p i2cGetErrors(). | ||
580 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
581 | * | ||
582 | * @api | ||
583 | */ | ||
584 | #define lis3dshAccelerometerReadRaw(devp, axes) \ | ||
585 | accelerometerReadRaw(&((devp)->acc_if), axes) | ||
586 | |||
587 | /** | ||
588 | * @brief Retrieves cooked data from the BaseAccelerometer. | ||
589 | * @note This data is manipulated according to the formula | ||
590 | * cooked = (raw * sensitivity) - bias. | ||
591 | * @note Final data is expressed as milli-G. | ||
592 | * @note The axes array must be at least the same size of the | ||
593 | * BaseAccelerometer axes number. | ||
594 | * | ||
595 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
596 | * @param[out] axes a buffer which would be filled with cooked data. | ||
597 | * | ||
598 | * @return The operation status. | ||
599 | * @retval MSG_OK if the function succeeded. | ||
600 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
601 | * be retrieved using @p i2cGetErrors(). | ||
602 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
603 | * | ||
604 | * @api | ||
605 | */ | ||
606 | #define lis3dshAccelerometerReadCooked(devp, axes) \ | ||
607 | accelerometerReadCooked(&((devp)->acc_if), axes) | ||
608 | |||
609 | /** | ||
610 | * @brief Set bias values for the BaseAccelerometer. | ||
611 | * @note Bias must be expressed as milli-G. | ||
612 | * @note The bias buffer must be at least the same size of the | ||
613 | * BaseAccelerometer axes number. | ||
614 | * | ||
615 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
616 | * @param[in] bp a buffer which contains biases. | ||
617 | * | ||
618 | * @return The operation status. | ||
619 | * @retval MSG_OK if the function succeeded. | ||
620 | * | ||
621 | * @api | ||
622 | */ | ||
623 | #define lis3dshAccelerometerSetBias(devp, bp) \ | ||
624 | accelerometerSetBias(&((devp)->acc_if), bp) | ||
625 | |||
626 | /** | ||
627 | * @brief Reset bias values for the BaseAccelerometer. | ||
628 | * @note Default biases value are obtained from device datasheet when | ||
629 | * available otherwise they are considered zero. | ||
630 | * | ||
631 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
632 | * | ||
633 | * @return The operation status. | ||
634 | * @retval MSG_OK if the function succeeded. | ||
635 | * | ||
636 | * @api | ||
637 | */ | ||
638 | #define lis3dshAccelerometerResetBias(devp) \ | ||
639 | accelerometerResetBias(&((devp)->acc_if)) | ||
640 | |||
641 | /** | ||
642 | * @brief Set sensitivity values for the BaseAccelerometer. | ||
643 | * @note Sensitivity must be expressed as milli-G/LSB. | ||
644 | * @note The sensitivity buffer must be at least the same size of the | ||
645 | * BaseAccelerometer axes number. | ||
646 | * | ||
647 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
648 | * @param[in] sp a buffer which contains sensitivities. | ||
649 | * | ||
650 | * @return The operation status. | ||
651 | * @retval MSG_OK if the function succeeded. | ||
652 | * | ||
653 | * @api | ||
654 | */ | ||
655 | #define lis3dshAccelerometerSetSensitivity(devp, sp) \ | ||
656 | accelerometerSetSensitivity(&((devp)->acc_if), sp) | ||
657 | |||
658 | /** | ||
659 | * @brief Reset sensitivity values for the BaseAccelerometer. | ||
660 | * @note Default sensitivities value are obtained from device datasheet. | ||
661 | * | ||
662 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
663 | * | ||
664 | * @return The operation status. | ||
665 | * @retval MSG_OK if the function succeeded. | ||
666 | * @retval MSG_RESET otherwise. | ||
667 | * | ||
668 | * @api | ||
669 | */ | ||
670 | #define lis3dshAccelerometerResetSensitivity(devp) \ | ||
671 | accelerometerResetSensitivity(&((devp)->acc_if)) | ||
672 | |||
673 | /** | ||
674 | * @brief Changes the LIS3DSHDriver accelerometer fullscale value. | ||
675 | * @note This function also rescale sensitivities and biases based on | ||
676 | * previous and next fullscale value. | ||
677 | * @note A recalibration is highly suggested after calling this function. | ||
678 | * | ||
679 | * @param[in] devp pointer to @p LIS3DSHDriver. | ||
680 | * @param[in] fs new fullscale value. | ||
681 | * | ||
682 | * @return The operation status. | ||
683 | * @retval MSG_OK if the function succeeded. | ||
684 | * @retval MSG_RESET otherwise. | ||
685 | * | ||
686 | * @api | ||
687 | */ | ||
688 | #define lis3dshAccelerometerSetFullScale(devp, fs) \ | ||
689 | (devp)->vmt->acc_set_full_scale(devp, fs) | ||
690 | |||
691 | /*===========================================================================*/ | ||
692 | /* External declarations. */ | ||
693 | /*===========================================================================*/ | ||
694 | |||
695 | #ifdef __cplusplus | ||
696 | extern "C" { | ||
697 | #endif | ||
698 | void lis3dshObjectInit(LIS3DSHDriver *devp); | ||
699 | void lis3dshStart(LIS3DSHDriver *devp, const LIS3DSHConfig *config); | ||
700 | void lis3dshStop(LIS3DSHDriver *devp); | ||
701 | #ifdef __cplusplus | ||
702 | } | ||
703 | #endif | ||
704 | |||
705 | #endif /* _LIS3DSH_H_ */ | ||
706 | |||
707 | /** @} */ | ||
708 | |||
diff --git a/lib/chibios/os/ex/devices/ST/lis3dsh.mk b/lib/chibios/os/ex/devices/ST/lis3dsh.mk new file mode 100644 index 000000000..270c78d9e --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3dsh.mk | |||
@@ -0,0 +1,10 @@ | |||
1 | # List of all the LIS3DSH device files. | ||
2 | LIS3DSHSRC := $(CHIBIOS)/os/ex/devices/ST/lis3dsh.c | ||
3 | |||
4 | # Required include directories | ||
5 | LIS3DSHINC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(LIS3DSHSRC) | ||
10 | ALLINC += $(LIS3DSHINC) \ No newline at end of file | ||
diff --git a/lib/chibios/os/ex/devices/ST/lis3mdl.c b/lib/chibios/os/ex/devices/ST/lis3mdl.c new file mode 100644 index 000000000..6f167e929 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3mdl.c | |||
@@ -0,0 +1,627 @@ | |||
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 lis3mdl.c | ||
23 | * @brief LIS3MDL MEMS interface module code. | ||
24 | * | ||
25 | * @addtogroup LIS3MDL | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #include "hal.h" | ||
31 | #include "lis3mdl.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 (LIS3MDL_USE_I2C) || defined(__DOXYGEN__) | ||
50 | /** | ||
51 | * @brief Reads registers value using I2C. | ||
52 | * @pre The I2C interface must be initialized and the driver started. | ||
53 | * | ||
54 | * @param[in] i2cp pointer to the I2C interface | ||
55 | * @param[in] sad slave address without R bit | ||
56 | * @param[in] reg first sub-register address | ||
57 | * @param[out] rxbuf pointer to an output buffer | ||
58 | * @param[in] n number of consecutive register to read | ||
59 | * @return the operation status. | ||
60 | * @notapi | ||
61 | */ | ||
62 | msg_t lis3mdlI2CReadRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t reg, | ||
63 | uint8_t* rxbuf, size_t n) { | ||
64 | uint8_t txbuf = reg; | ||
65 | if(n > 1) | ||
66 | txbuf |= LIS3MDL_SUB_MS; | ||
67 | |||
68 | return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, | ||
69 | TIME_INFINITE); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * @brief Writes a value into a register using I2C. | ||
74 | * @pre The I2C interface must be initialized and the driver started. | ||
75 | * | ||
76 | * @param[in] i2cp pointer to the I2C interface | ||
77 | * @param[in] sad slave address without R bit | ||
78 | * @param[in] txbuf buffer containing sub-address value in first position | ||
79 | * and values to write | ||
80 | * @param[in] n size of txbuf less one (not considering the first | ||
81 | * element) | ||
82 | * @return the operation status. | ||
83 | * @notapi | ||
84 | */ | ||
85 | msg_t lis3mdlI2CWriteRegister(I2CDriver *i2cp, lis3mdl_sad_t sad, uint8_t* txbuf, | ||
86 | uint8_t n) { | ||
87 | if (n > 1) | ||
88 | (*txbuf) |= LIS3MDL_SUB_MS; | ||
89 | |||
90 | return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, | ||
91 | TIME_INFINITE); | ||
92 | } | ||
93 | #endif /* LIS3MDL_USE_I2C */ | ||
94 | |||
95 | /** | ||
96 | * @brief Return the number of axes of the BaseCompass. | ||
97 | * | ||
98 | * @param[in] ip pointer to @p BaseCompass interface | ||
99 | * | ||
100 | * @return the number of axes. | ||
101 | */ | ||
102 | static size_t comp_get_axes_number(void *ip) { | ||
103 | |||
104 | osalDbgCheck(ip != NULL); | ||
105 | return LIS3MDL_COMP_NUMBER_OF_AXES; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * @brief Retrieves raw data from the BaseCompass. | ||
110 | * @note This data is retrieved from MEMS register without any algebraical | ||
111 | * manipulation. | ||
112 | * @note The axes array must be at least the same size of the | ||
113 | * BaseCompass axes number. | ||
114 | * | ||
115 | * @param[in] ip pointer to @p BaseCompass interface. | ||
116 | * @param[out] axes a buffer which would be filled with raw data. | ||
117 | * | ||
118 | * @return The operation status. | ||
119 | * @retval MSG_OK if the function succeeded. | ||
120 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
121 | * be retrieved using @p i2cGetErrors(). | ||
122 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
123 | */ | ||
124 | static msg_t comp_read_raw(void *ip, int32_t axes[]) { | ||
125 | LIS3MDLDriver* devp; | ||
126 | uint8_t buff [LIS3MDL_COMP_NUMBER_OF_AXES * 2], i; | ||
127 | int16_t tmp; | ||
128 | msg_t msg; | ||
129 | |||
130 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
131 | |||
132 | /* Getting parent instance pointer.*/ | ||
133 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
134 | |||
135 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
136 | "comp_read_raw(), invalid state"); | ||
137 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
138 | "comp_read_raw(), channel not ready"); | ||
139 | |||
140 | #if LIS3MDL_SHARED_I2C | ||
141 | i2cAcquireBus(devp->config->i2cp); | ||
142 | i2cStart(devp->config->i2cp, | ||
143 | devp->config->i2ccfg); | ||
144 | #endif /* LIS3MDL_SHARED_I2C */ | ||
145 | msg = lis3mdlI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
146 | LIS3MDL_AD_OUT_X_L, buff, | ||
147 | LIS3MDL_COMP_NUMBER_OF_AXES * 2); | ||
148 | |||
149 | #if LIS3MDL_SHARED_I2C | ||
150 | i2cReleaseBus(devp->config->i2cp); | ||
151 | #endif /* LIS3MDL_SHARED_I2C */ | ||
152 | |||
153 | if(msg == MSG_OK) | ||
154 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
155 | tmp = buff[2 * i] + (buff[2 * i + 1] << 8); | ||
156 | axes[i] = (int32_t)tmp; | ||
157 | } | ||
158 | return msg; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * @brief Retrieves cooked data from the BaseCompass. | ||
163 | * @note This data is manipulated according to the formula | ||
164 | * cooked = (raw * sensitivity) - bias. | ||
165 | * @note Final data is expressed as G. | ||
166 | * @note The axes array must be at least the same size of the | ||
167 | * BaseCompass axes number. | ||
168 | * | ||
169 | * @param[in] ip pointer to @p BaseCompass interface. | ||
170 | * @param[out] axes a buffer which would be filled with cooked data. | ||
171 | * | ||
172 | * @return The operation status. | ||
173 | * @retval MSG_OK if the function succeeded. | ||
174 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
175 | * be retrieved using @p i2cGetErrors(). | ||
176 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
177 | */ | ||
178 | static msg_t comp_read_cooked(void *ip, float axes[]) { | ||
179 | LIS3MDLDriver* devp; | ||
180 | uint32_t i; | ||
181 | int32_t raw[LIS3MDL_COMP_NUMBER_OF_AXES]; | ||
182 | msg_t msg; | ||
183 | |||
184 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
185 | |||
186 | |||
187 | /* Getting parent instance pointer.*/ | ||
188 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
189 | |||
190 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
191 | "comp_read_cooked(), invalid state"); | ||
192 | |||
193 | msg = comp_read_raw(ip, raw); | ||
194 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES ; i++) { | ||
195 | axes[i] = (raw[i] * devp->compsensitivity[i]) - devp->compbias[i]; | ||
196 | } | ||
197 | return msg; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * @brief Set bias values for the BaseCompass. | ||
202 | * @note Bias must be expressed as G. | ||
203 | * @note The bias buffer must be at least the same size of the | ||
204 | * BaseCompass axes number. | ||
205 | * | ||
206 | * @param[in] ip pointer to @p BaseCompass interface. | ||
207 | * @param[in] bp a buffer which contains biases. | ||
208 | * | ||
209 | * @return The operation status. | ||
210 | * @retval MSG_OK if the function succeeded. | ||
211 | */ | ||
212 | static msg_t comp_set_bias(void *ip, float *bp) { | ||
213 | LIS3MDLDriver* devp; | ||
214 | uint32_t i; | ||
215 | msg_t msg = MSG_OK; | ||
216 | |||
217 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
218 | |||
219 | /* Getting parent instance pointer.*/ | ||
220 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
221 | |||
222 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
223 | "comp_set_bias(), invalid state"); | ||
224 | |||
225 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
226 | devp->compbias[i] = bp[i]; | ||
227 | } | ||
228 | return msg; | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * @brief Reset bias values for the BaseCompass. | ||
233 | * @note Default biases value are obtained from device datasheet when | ||
234 | * available otherwise they are considered zero. | ||
235 | * | ||
236 | * @param[in] ip pointer to @p BaseCompass interface. | ||
237 | * | ||
238 | * @return The operation status. | ||
239 | * @retval MSG_OK if the function succeeded. | ||
240 | */ | ||
241 | static msg_t comp_reset_bias(void *ip) { | ||
242 | LIS3MDLDriver* devp; | ||
243 | uint32_t i; | ||
244 | msg_t msg = MSG_OK; | ||
245 | |||
246 | osalDbgCheck(ip != NULL); | ||
247 | |||
248 | /* Getting parent instance pointer.*/ | ||
249 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
250 | |||
251 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
252 | "comp_reset_bias(), invalid state"); | ||
253 | |||
254 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
255 | devp->compbias[i] = LIS3MDL_COMP_BIAS; | ||
256 | return msg; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * @brief Set sensitivity values for the BaseCompass. | ||
261 | * @note Sensitivity must be expressed as G/LSB. | ||
262 | * @note The sensitivity buffer must be at least the same size of the | ||
263 | * BaseCompass axes number. | ||
264 | * | ||
265 | * @param[in] ip pointer to @p BaseCompass interface. | ||
266 | * @param[in] sp a buffer which contains sensitivities. | ||
267 | * | ||
268 | * @return The operation status. | ||
269 | * @retval MSG_OK if the function succeeded. | ||
270 | */ | ||
271 | static msg_t comp_set_sensivity(void *ip, float *sp) { | ||
272 | LIS3MDLDriver* devp; | ||
273 | uint32_t i; | ||
274 | msg_t msg = MSG_OK; | ||
275 | |||
276 | /* Getting parent instance pointer.*/ | ||
277 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
278 | |||
279 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
280 | |||
281 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
282 | "comp_set_sensivity(), invalid state"); | ||
283 | |||
284 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
285 | devp->compsensitivity[i] = sp[i]; | ||
286 | } | ||
287 | return msg; | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * @brief Reset sensitivity values for the BaseCompass. | ||
292 | * @note Default sensitivities value are obtained from device datasheet. | ||
293 | * | ||
294 | * @param[in] ip pointer to @p BaseCompass interface. | ||
295 | * | ||
296 | * @return The operation status. | ||
297 | * @retval MSG_OK if the function succeeded. | ||
298 | * @retval MSG_RESET otherwise. | ||
299 | */ | ||
300 | static msg_t comp_reset_sensivity(void *ip) { | ||
301 | LIS3MDLDriver* devp; | ||
302 | uint32_t i; | ||
303 | msg_t msg = MSG_OK; | ||
304 | |||
305 | osalDbgCheck(ip != NULL); | ||
306 | |||
307 | /* Getting parent instance pointer.*/ | ||
308 | devp = objGetInstance(LIS3MDLDriver*, (BaseCompass*)ip); | ||
309 | |||
310 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
311 | "comp_reset_sensivity(), invalid state"); | ||
312 | |||
313 | if(devp->config->compfullscale == LIS3MDL_COMP_FS_4GA) | ||
314 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
315 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_4GA; | ||
316 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_8GA) | ||
317 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
318 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_8GA; | ||
319 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_12GA) | ||
320 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
321 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_12GA; | ||
322 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_16GA) | ||
323 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
324 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_16GA; | ||
325 | else { | ||
326 | osalDbgAssert(FALSE, "comp_reset_sensivity(), compass full scale issue"); | ||
327 | msg = MSG_RESET; | ||
328 | } | ||
329 | return msg; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * @brief Changes the LIS3MDLDriver compass fullscale value. | ||
334 | * @note This function also rescale sensitivities and biases based on | ||
335 | * previous and next fullscale value. | ||
336 | * @note A recalibration is highly suggested after calling this function. | ||
337 | * | ||
338 | * @param[in] devp pointer to @p LIS3MDLDriver interface. | ||
339 | * @param[in] fs new fullscale value. | ||
340 | * | ||
341 | * @return The operation status. | ||
342 | * @retval MSG_OK if the function succeeded. | ||
343 | * @retval MSG_RESET otherwise. | ||
344 | */ | ||
345 | static msg_t comp_set_full_scale(LIS3MDLDriver *devp, lis3mdl_comp_fs_t fs) { | ||
346 | float newfs, scale; | ||
347 | uint8_t i, buff[2]; | ||
348 | msg_t msg; | ||
349 | |||
350 | osalDbgCheck(devp != NULL); | ||
351 | |||
352 | osalDbgAssert((devp->state == LIS3MDL_READY), | ||
353 | "comp_set_full_scale(), invalid state"); | ||
354 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
355 | "comp_set_full_scale(), channel not ready"); | ||
356 | |||
357 | /* Computing new fullscale value.*/ | ||
358 | if(fs == LIS3MDL_COMP_FS_4GA) { | ||
359 | newfs = LIS3MDL_COMP_4GA; | ||
360 | } | ||
361 | else if(fs == LIS3MDL_COMP_FS_8GA) { | ||
362 | newfs = LIS3MDL_COMP_8GA; | ||
363 | } | ||
364 | else if(fs == LIS3MDL_COMP_FS_12GA) { | ||
365 | newfs = LIS3MDL_COMP_12GA; | ||
366 | } | ||
367 | else if(fs == LIS3MDL_COMP_FS_16GA) { | ||
368 | newfs = LIS3MDL_COMP_16GA; | ||
369 | } | ||
370 | else { | ||
371 | msg = MSG_RESET; | ||
372 | return msg; | ||
373 | } | ||
374 | |||
375 | if(newfs != devp->compfullscale) { | ||
376 | /* Computing scale value.*/ | ||
377 | scale = newfs / devp->compfullscale; | ||
378 | devp->compfullscale = newfs; | ||
379 | |||
380 | #if LIS3MDL_SHARED_I2C | ||
381 | i2cAcquireBus(devp->config->i2cp); | ||
382 | i2cStart(devp->config->i2cp, devp->config->i2ccfg); | ||
383 | #endif /* LIS3MDL_SHARED_I2C */ | ||
384 | |||
385 | /* Updating register.*/ | ||
386 | msg = lis3mdlI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
387 | LIS3MDL_AD_CTRL_REG2, &buff[1], 1); | ||
388 | |||
389 | #if LIS3MDL_SHARED_I2C | ||
390 | i2cReleaseBus(devp->config->i2cp); | ||
391 | #endif /* LIS3MDL_SHARED_I2C */ | ||
392 | |||
393 | if(msg != MSG_OK) | ||
394 | return msg; | ||
395 | buff[1] &= ~(LIS3MDL_CTRL_REG2_FS_MASK); | ||
396 | buff[1] |= fs; | ||
397 | buff[0] = LIS3MDL_AD_CTRL_REG2; | ||
398 | |||
399 | #if LIS3MDL_SHARED_I2C | ||
400 | i2cAcquireBus(devp->config->i2cp); | ||
401 | i2cStart(devp->config->i2cp, devp->config->i2ccfg); | ||
402 | #endif /* LIS3MDL_SHARED_I2C */ | ||
403 | |||
404 | msg = lis3mdlI2CWriteRegister(devp->config->i2cp, | ||
405 | devp->config->slaveaddress, | ||
406 | buff, 1); | ||
407 | |||
408 | #if LIS3MDL_SHARED_I2C | ||
409 | i2cReleaseBus(devp->config->i2cp); | ||
410 | #endif /* LIS3MDL_SHARED_I2C */ | ||
411 | |||
412 | if(msg != MSG_OK) | ||
413 | return msg; | ||
414 | |||
415 | /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ | ||
416 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
417 | devp->compsensitivity[i] *= scale; | ||
418 | devp->compbias[i] *= scale; | ||
419 | } | ||
420 | } | ||
421 | return msg; | ||
422 | } | ||
423 | |||
424 | static const struct LIS3MDLVMT vmt_device = { | ||
425 | (size_t)0, | ||
426 | comp_set_full_scale | ||
427 | }; | ||
428 | |||
429 | static const struct BaseCompassVMT vmt_compass = { | ||
430 | sizeof(struct LIS3MDLVMT*), | ||
431 | comp_get_axes_number, comp_read_raw, comp_read_cooked, | ||
432 | comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity | ||
433 | }; | ||
434 | |||
435 | /*===========================================================================*/ | ||
436 | /* Driver exported functions. */ | ||
437 | /*===========================================================================*/ | ||
438 | |||
439 | /** | ||
440 | * @brief Initializes an instance. | ||
441 | * | ||
442 | * @param[out] devp pointer to the @p LIS3MDLDriver object | ||
443 | * | ||
444 | * @init | ||
445 | */ | ||
446 | void lis3mdlObjectInit(LIS3MDLDriver *devp) { | ||
447 | devp->vmt = &vmt_device; | ||
448 | devp->comp_if.vmt = &vmt_compass; | ||
449 | |||
450 | devp->config = NULL; | ||
451 | |||
452 | devp->compaxes = LIS3MDL_COMP_NUMBER_OF_AXES; | ||
453 | |||
454 | devp->state = LIS3MDL_STOP; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * @brief Configures and activates LIS3MDL Complex Driver peripheral. | ||
459 | * | ||
460 | * @param[in] devp pointer to the @p LIS3MDLDriver object | ||
461 | * @param[in] config pointer to the @p LIS3MDLConfig object | ||
462 | * | ||
463 | * @api | ||
464 | */ | ||
465 | void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config) { | ||
466 | uint32_t i; | ||
467 | uint8_t cr[6]; | ||
468 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
469 | |||
470 | osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY), | ||
471 | "lis3mdlStart(), invalid state"); | ||
472 | |||
473 | devp->config = config; | ||
474 | |||
475 | /* Control register 1 configuration block.*/ | ||
476 | { | ||
477 | cr[0] = LIS3MDL_AD_CTRL_REG1; | ||
478 | cr[1] = devp->config->compoutputdatarate; | ||
479 | #if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) | ||
480 | cr[1] |= devp->config->compoperationmodexy; | ||
481 | #else | ||
482 | cr[1] |= LIS3MDL_CTRL_REG1_OM0 | LIS3MDL_CTRL_REG1_OM1; | ||
483 | #endif | ||
484 | } | ||
485 | |||
486 | /* Control register 2 configuration block.*/ | ||
487 | { | ||
488 | cr[2] = devp->config->compfullscale; | ||
489 | } | ||
490 | |||
491 | /* Control register 3 configuration block.*/ | ||
492 | { | ||
493 | cr[3] = 0; | ||
494 | #if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) | ||
495 | cr[3] = devp->config->compconversionmode; | ||
496 | #endif | ||
497 | } | ||
498 | |||
499 | /* Control register 4 configuration block.*/ | ||
500 | { | ||
501 | cr[4] = 0; | ||
502 | #if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) | ||
503 | cr[4] = devp->config->compoperationmodez | devp->config->endianness; | ||
504 | #endif | ||
505 | } | ||
506 | |||
507 | /* Control register 5 configuration block.*/ | ||
508 | { | ||
509 | cr[5] = 0; | ||
510 | #if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) | ||
511 | cr[5] = devp->config->blockdataupdate; | ||
512 | #endif | ||
513 | } | ||
514 | |||
515 | #if LIS3MDL_USE_I2C | ||
516 | #if LIS3MDL_SHARED_I2C | ||
517 | i2cAcquireBus((devp)->config->i2cp); | ||
518 | #endif /* LIS3MDL_SHARED_I2C */ | ||
519 | i2cStart((devp)->config->i2cp, | ||
520 | (devp)->config->i2ccfg); | ||
521 | |||
522 | lis3mdlI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
523 | cr, 5); | ||
524 | |||
525 | #if LIS3MDL_SHARED_I2C | ||
526 | i2cReleaseBus((devp)->config->i2cp); | ||
527 | #endif /* LIS3MDL_SHARED_I2C */ | ||
528 | #endif /* LIS3MDL_USE_I2C */ | ||
529 | |||
530 | if(devp->config->compfullscale == LIS3MDL_COMP_FS_4GA) { | ||
531 | devp->compfullscale = LIS3MDL_COMP_4GA; | ||
532 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
533 | if(devp->config->compsensitivity == NULL) { | ||
534 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_4GA; | ||
535 | } | ||
536 | else { | ||
537 | devp->compsensitivity[i] = devp->config->compsensitivity[i]; | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_8GA) { | ||
542 | devp->compfullscale = LIS3MDL_COMP_8GA; | ||
543 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
544 | if(devp->config->compsensitivity == NULL) { | ||
545 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_8GA; | ||
546 | } | ||
547 | else { | ||
548 | devp->compsensitivity[i] = devp->config->compsensitivity[i]; | ||
549 | } | ||
550 | } | ||
551 | } | ||
552 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_12GA) { | ||
553 | devp->compfullscale = LIS3MDL_COMP_12GA; | ||
554 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
555 | if(devp->config->compsensitivity == NULL) { | ||
556 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_12GA; | ||
557 | } | ||
558 | else { | ||
559 | devp->compsensitivity[i] = devp->config->compsensitivity[i]; | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | else if(devp->config->compfullscale == LIS3MDL_COMP_FS_16GA) { | ||
564 | devp->compfullscale = LIS3MDL_COMP_16GA; | ||
565 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) { | ||
566 | if(devp->config->compsensitivity == NULL) { | ||
567 | devp->compsensitivity[i] = LIS3MDL_COMP_SENS_16GA; | ||
568 | } | ||
569 | else { | ||
570 | devp->compsensitivity[i] = devp->config->compsensitivity[i]; | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | else | ||
575 | osalDbgAssert(FALSE, "lis3mdlStart(), compass full scale issue"); | ||
576 | |||
577 | /* Storing bias information */ | ||
578 | if(devp->config->compbias != NULL) | ||
579 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
580 | devp->compbias[i] = devp->config->compbias[i]; | ||
581 | else | ||
582 | for(i = 0; i < LIS3MDL_COMP_NUMBER_OF_AXES; i++) | ||
583 | devp->compbias[i] = LIS3MDL_COMP_BIAS; | ||
584 | |||
585 | /* This is the MEMS transient recovery time */ | ||
586 | osalThreadSleepMilliseconds(5); | ||
587 | |||
588 | devp->state = LIS3MDL_READY; | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * @brief Deactivates the LIS3MDL Complex Driver peripheral. | ||
593 | * | ||
594 | * @param[in] devp pointer to the @p LIS3MDLDriver object | ||
595 | * | ||
596 | * @api | ||
597 | */ | ||
598 | void lis3mdlStop(LIS3MDLDriver *devp) { | ||
599 | uint8_t cr[2]; | ||
600 | osalDbgCheck(devp != NULL); | ||
601 | |||
602 | osalDbgAssert((devp->state == LIS3MDL_STOP) || (devp->state == LIS3MDL_READY), | ||
603 | "lis3mdlStop(), invalid state"); | ||
604 | |||
605 | if (devp->state == LIS3MDL_READY) { | ||
606 | #if (LIS3MDL_USE_I2C) | ||
607 | #if LIS3MDL_SHARED_I2C | ||
608 | i2cAcquireBus((devp)->config->i2cp); | ||
609 | i2cStart((devp)->config->i2cp, | ||
610 | (devp)->config->i2ccfg); | ||
611 | #endif /* LIS3MDL_SHARED_I2C */ | ||
612 | |||
613 | /* Disabling compass. */ | ||
614 | cr[0] = LIS3MDL_AD_CTRL_REG3; | ||
615 | cr[1] = LIS3MDL_CTRL_REG3_MD0 | LIS3MDL_CTRL_REG3_MD1; | ||
616 | lis3mdlI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
617 | cr, 1); | ||
618 | |||
619 | i2cStop((devp)->config->i2cp); | ||
620 | #if LIS3MDL_SHARED_I2C | ||
621 | i2cReleaseBus((devp)->config->i2cp); | ||
622 | #endif /* LIS3MDL_SHARED_I2C */ | ||
623 | #endif /* LIS3MDL_USE_I2C */ | ||
624 | } | ||
625 | devp->state = LIS3MDL_STOP; | ||
626 | } | ||
627 | /** @} */ | ||
diff --git a/lib/chibios/os/ex/devices/ST/lis3mdl.h b/lib/chibios/os/ex/devices/ST/lis3mdl.h new file mode 100644 index 000000000..4adf2954f --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3mdl.h | |||
@@ -0,0 +1,670 @@ | |||
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 lis3mdl.h | ||
23 | * @brief LIS3MDL MEMS interface module header. | ||
24 | * | ||
25 | * @addtogroup LIS3MDL | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | #ifndef _LIS3MDL_H_ | ||
30 | #define _LIS3MDL_H_ | ||
31 | |||
32 | #include "ex_compass.h" | ||
33 | |||
34 | /*===========================================================================*/ | ||
35 | /* Driver constants. */ | ||
36 | /*===========================================================================*/ | ||
37 | |||
38 | /** | ||
39 | * @name Version identification | ||
40 | * @{ | ||
41 | */ | ||
42 | /** | ||
43 | * @brief LIS3MDL driver version string. | ||
44 | */ | ||
45 | #define EX_LIS3MDL_VERSION "1.1.2" | ||
46 | |||
47 | /** | ||
48 | * @brief LIS3MDL driver version major number. | ||
49 | */ | ||
50 | #define EX_LIS3MDL_MAJOR 1 | ||
51 | |||
52 | /** | ||
53 | * @brief LIS3MDL driver version minor number. | ||
54 | */ | ||
55 | #define EX_LIS3MDL_MINOR 1 | ||
56 | |||
57 | /** | ||
58 | * @brief LIS3MDL driver version patch number. | ||
59 | */ | ||
60 | #define EX_LIS3MDL_PATCH 2 | ||
61 | /** @} */ | ||
62 | |||
63 | /** | ||
64 | * @brief LIS3MDL compass subsystem characteristics. | ||
65 | * @note Sensitivity is expressed as G/LSB whereas G stands for Gauss. | ||
66 | * @note Bias is expressed as G. | ||
67 | * | ||
68 | * @{ | ||
69 | */ | ||
70 | #define LIS3MDL_COMP_NUMBER_OF_AXES 3U | ||
71 | |||
72 | #define LIS3MDL_COMP_4GA 4.0f | ||
73 | #define LIS3MDL_COMP_8GA 8.0f | ||
74 | #define LIS3MDL_COMP_12GA 12.0f | ||
75 | #define LIS3MDL_COMP_16GA 16.0f | ||
76 | |||
77 | #define LIS3MDL_COMP_SENS_4GA 0.00014615f | ||
78 | #define LIS3MDL_COMP_SENS_8GA 0.00029231f | ||
79 | #define LIS3MDL_COMP_SENS_12GA 0.0004384f | ||
80 | #define LIS3MDL_COMP_SENS_16GA 0.00058445f | ||
81 | |||
82 | #define LIS3MDL_COMP_BIAS 0.0f | ||
83 | /** @} */ | ||
84 | |||
85 | /** | ||
86 | * @name LIS3MDL communication interfaces related bit masks | ||
87 | * @{ | ||
88 | */ | ||
89 | #define LIS3MDL_DI_MASK 0xFF | ||
90 | #define LIS3MDL_DI(n) (1 << n) | ||
91 | #define LIS3MDL_AD_MASK 0x3F | ||
92 | #define LIS3MDL_AD(n) (1 << n) | ||
93 | #define LIS3MDL_MS (1 << 6) | ||
94 | #define LIS3MDL_RW (1 << 7) | ||
95 | |||
96 | #define LIS3MDL_SUB_MS (1 << 7) | ||
97 | /** @} */ | ||
98 | |||
99 | /** | ||
100 | * @name LIS3MDL register addresses | ||
101 | * @{ | ||
102 | */ | ||
103 | #define LIS3MDL_AD_WHO_AM_I 0x0F | ||
104 | #define LIS3MDL_AD_CTRL_REG1 0x20 | ||
105 | #define LIS3MDL_AD_CTRL_REG2 0x21 | ||
106 | #define LIS3MDL_AD_CTRL_REG3 0x22 | ||
107 | #define LIS3MDL_AD_CTRL_REG4 0x23 | ||
108 | #define LIS3MDL_AD_CTRL_REG5 0x24 | ||
109 | #define LIS3MDL_AD_STATUS_REG 0x27 | ||
110 | #define LIS3MDL_AD_OUT_X_L 0x28 | ||
111 | #define LIS3MDL_AD_OUT_X_H 0x29 | ||
112 | #define LIS3MDL_AD_OUT_Y_L 0x2A | ||
113 | #define LIS3MDL_AD_OUT_Y_H 0x2B | ||
114 | #define LIS3MDL_AD_OUT_Z_L 0x2C | ||
115 | #define LIS3MDL_AD_OUT_Z_H 0x2D | ||
116 | #define LIS3MDL_AD_TEMP_OUT_L 0x2E | ||
117 | #define LIS3MDL_AD_TEMP_OUT_H 0x2F | ||
118 | #define LIS3MDL_AD_INT_CFG 0x30 | ||
119 | #define LIS3MDL_AD_INT_SOURCE 0x31 | ||
120 | #define LIS3MDL_AD_INT_THS_L 0x32 | ||
121 | #define LIS3MDL_AD_INT_THS_H 0x33 | ||
122 | /** @} */ | ||
123 | |||
124 | /** | ||
125 | * @name LIS3MDL_CTRL_REG1 register bits definitions | ||
126 | * @{ | ||
127 | */ | ||
128 | #define LIS3MDL_CTRL_REG1_MASK 0xFF | ||
129 | #define LIS3MDL_CTRL_REG1_ST (1 << 0) | ||
130 | #define LIS3MDL_CTRL_REG1_FAST_ODR (1 << 1) | ||
131 | #define LIS3MDL_CTRL_REG1_DO0 (1 << 2) | ||
132 | #define LIS3MDL_CTRL_REG1_DO1 (1 << 3) | ||
133 | #define LIS3MDL_CTRL_REG1_DO2 (1 << 4) | ||
134 | #define LIS3MDL_CTRL_REG1_OM0 (1 << 5) | ||
135 | #define LIS3MDL_CTRL_REG1_OM1 (1 << 6) | ||
136 | #define LIS3MDL_CTRL_REG1_TEMP_EN (1 << 7) | ||
137 | /** @} */ | ||
138 | |||
139 | /** | ||
140 | * @name LIS3MDL_CTRL_REG2 register bits definitions | ||
141 | * @{ | ||
142 | */ | ||
143 | #define LIS3MDL_CTRL_REG2_MASK 0x6C | ||
144 | #define LIS3MDL_CTRL_REG2_SOFT_RST (1 << 2) | ||
145 | #define LIS3MDL_CTRL_REG2_REBOOT (1 << 3) | ||
146 | #define LIS3MDL_CTRL_REG2_FS_MASK 0x60 | ||
147 | #define LIS3MDL_CTRL_REG2_FS0 (1 << 5) | ||
148 | #define LIS3MDL_CTRL_REG2_FS1 (1 << 6) | ||
149 | /** @} */ | ||
150 | |||
151 | /** | ||
152 | * @name LIS3MDL_CTRL_REG3 register bits definitions | ||
153 | * @{ | ||
154 | */ | ||
155 | #define LIS3MDL_CTRL_REG3_MASK 0x27 | ||
156 | #define LIS3MDL_CTRL_REG3_MD0 (1 << 0) | ||
157 | #define LIS3MDL_CTRL_REG3_MD1 (1 << 1) | ||
158 | #define LIS3MDL_CTRL_REG3_SIM (1 << 2) | ||
159 | #define LIS3MDL_CTRL_REG3_LP (1 << 5) | ||
160 | /** @} */ | ||
161 | |||
162 | /** | ||
163 | * @name LIS3MDL_CTRL_REG4 register bits definitions | ||
164 | * @{ | ||
165 | */ | ||
166 | #define LIS3MDL_CTRL_REG4_MASK 0x0E | ||
167 | #define LIS3MDL_CTRL_REG4_BLE (1 << 1) | ||
168 | #define LIS3MDL_CTRL_REG4_OMZ0 (1 << 2) | ||
169 | #define LIS3MDL_CTRL_REG4_OMZ1 (1 << 3) | ||
170 | /** @} */ | ||
171 | |||
172 | /** | ||
173 | * @name LIS3MDL_CTRL_REG5 register bits definitions | ||
174 | * @{ | ||
175 | */ | ||
176 | #define LIS3MDL_CTRL_REG5_MASK 0xC0 | ||
177 | #define LIS3MDL_CTRL_REG5_BDU (1 << 6) | ||
178 | #define LIS3MDL_CTRL_REG5_FAST_READ (1 << 7) | ||
179 | /** @} */ | ||
180 | |||
181 | /*===========================================================================*/ | ||
182 | /* Driver pre-compile time settings. */ | ||
183 | /*===========================================================================*/ | ||
184 | |||
185 | /** | ||
186 | * @name Configuration options | ||
187 | * @{ | ||
188 | */ | ||
189 | /** | ||
190 | * @brief LIS3MDL SPI interface switch. | ||
191 | * @details If set to @p TRUE the support for SPI is included. | ||
192 | * @note The default is @p FALSE. | ||
193 | */ | ||
194 | #if !defined(LIS3MDL_USE_SPI) || defined(__DOXYGEN__) | ||
195 | #define LIS3MDL_USE_SPI FALSE | ||
196 | #endif | ||
197 | |||
198 | /** | ||
199 | * @brief LIS3MDL shared SPI switch. | ||
200 | * @details If set to @p TRUE the device acquires SPI bus ownership | ||
201 | * on each transaction. | ||
202 | * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. | ||
203 | */ | ||
204 | #if !defined(LIS3MDL_SHARED_SPI) || defined(__DOXYGEN__) | ||
205 | #define LIS3MDL_SHARED_SPI FALSE | ||
206 | #endif | ||
207 | |||
208 | /** | ||
209 | * @brief LIS3MDL I2C interface switch. | ||
210 | * @details If set to @p TRUE the support for I2C is included. | ||
211 | * @note The default is @p TRUE. | ||
212 | */ | ||
213 | #if !defined(LIS3MDL_USE_I2C) || defined(__DOXYGEN__) | ||
214 | #define LIS3MDL_USE_I2C TRUE | ||
215 | #endif | ||
216 | |||
217 | /** | ||
218 | * @brief LIS3MDL shared I2C switch. | ||
219 | * @details If set to @p TRUE the device acquires I2C bus ownership | ||
220 | * on each transaction. | ||
221 | * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION | ||
222 | */ | ||
223 | #if !defined(LIS3MDL_SHARED_I2C) || defined(__DOXYGEN__) | ||
224 | #define LIS3MDL_SHARED_I2C FALSE | ||
225 | #endif | ||
226 | |||
227 | /** | ||
228 | * @brief LIS3MDL advanced configurations switch. | ||
229 | * @details If set to @p TRUE more configurations are available. | ||
230 | * @note The default is @p FALSE. | ||
231 | */ | ||
232 | #if !defined(LIS3MDL_USE_ADVANCED) || defined(__DOXYGEN__) | ||
233 | #define LIS3MDL_USE_ADVANCED FALSE | ||
234 | #endif | ||
235 | /** @} */ | ||
236 | |||
237 | /*===========================================================================*/ | ||
238 | /* Derived constants and error checks. */ | ||
239 | /*===========================================================================*/ | ||
240 | |||
241 | #if !(LIS3MDL_USE_SPI ^ LIS3MDL_USE_I2C) | ||
242 | #error "LIS3MDL_USE_SPI and LIS3MDL_USE_I2C cannot be both true or both false" | ||
243 | #endif | ||
244 | |||
245 | #if LIS3MDL_USE_SPI && !HAL_USE_SPI | ||
246 | #error "LIS3MDL_USE_SPI requires HAL_USE_SPI" | ||
247 | #endif | ||
248 | |||
249 | #if LIS3MDL_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION | ||
250 | #error "LIS3MDL_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" | ||
251 | #endif | ||
252 | |||
253 | #if LIS3MDL_USE_I2C && !HAL_USE_I2C | ||
254 | #error "LIS3MDL_USE_I2C requires HAL_USE_I2C" | ||
255 | #endif | ||
256 | |||
257 | #if LIS3MDL_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION | ||
258 | #error "LIS3MDL_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" | ||
259 | #endif | ||
260 | |||
261 | /* | ||
262 | * CHTODO: Add support for LIS3MDL over SPI. | ||
263 | */ | ||
264 | #if LIS3MDL_USE_SPI | ||
265 | #error "LIS3MDL over SPI still not supported" | ||
266 | #endif | ||
267 | |||
268 | /*===========================================================================*/ | ||
269 | /* Driver data structures and types. */ | ||
270 | /*===========================================================================*/ | ||
271 | |||
272 | /** | ||
273 | * @name LIS3MDL data structures and types | ||
274 | * @{ | ||
275 | */ | ||
276 | |||
277 | /** | ||
278 | * @brief LIS3MDL slave address | ||
279 | */ | ||
280 | /** | ||
281 | * @brief Structure representing a LIS3MDL driver. | ||
282 | */ | ||
283 | typedef struct LIS3MDLDriver LIS3MDLDriver; | ||
284 | |||
285 | /** | ||
286 | * @brief LIS3MDL slave address | ||
287 | */ | ||
288 | typedef enum { | ||
289 | LIS3MDL_SAD_GND = 0x1C, /**< Slave Address when SA1 is to GND */ | ||
290 | LIS3MDL_SAD_VCC = 0x1E /**< Slave Address when SA1 is to VCC */ | ||
291 | }lis3mdl_sad_t; | ||
292 | |||
293 | /** | ||
294 | * @brief LIS3MDL full scale | ||
295 | */ | ||
296 | typedef enum { | ||
297 | LIS3MDL_COMP_FS_4GA = 0x00, /**< �4 Gauss */ | ||
298 | LIS3MDL_COMP_FS_8GA = 0x20, /**< �8 Gauss */ | ||
299 | LIS3MDL_COMP_FS_12GA = 0x40, /**< �12 Gauss */ | ||
300 | LIS3MDL_COMP_FS_16GA = 0x60 /**< �16 Gauss */ | ||
301 | }lis3mdl_comp_fs_t; | ||
302 | |||
303 | /** | ||
304 | * @brief LIS3MDL output data rate | ||
305 | */ | ||
306 | typedef enum { | ||
307 | LIS3MDL_COMP_ODR_0_625HZ = 0x00, /**< Output Data Rate = 0.625 Hz */ | ||
308 | LIS3MDL_COMP_ODR_1_25HZ = 0x04, /**< Output Data Rate = 1.25 Hz */ | ||
309 | LIS3MDL_COMP_ODR_2_5HZ = 0x08, /**< Output Data Rate = 2.5 Hz */ | ||
310 | LIS3MDL_COMP_ODR_5HZ = 0x0C, /**< Output Data Rate = 5 Hz */ | ||
311 | LIS3MDL_COMP_ODR_10HZ = 0x10, /**< Output Data Rate = 10 Hz */ | ||
312 | LIS3MDL_COMP_ODR_20HZ = 0x14, /**< Output Data Rate = 20 Hz */ | ||
313 | LIS3MDL_COMP_ODR_40HZ = 0x18, /**< Output Data Rate = 40 Hz */ | ||
314 | LIS3MDL_COMP_ODR_80HZ = 0x1C /**< Output Data Rate = 80 Hz */ | ||
315 | }lis3mdl_comp_odr_t; | ||
316 | |||
317 | /** | ||
318 | * @brief LIS3MDL low power mode configuration | ||
319 | */ | ||
320 | typedef enum { | ||
321 | LIS3MDL_COMP_LP_DISABLED = 0x00, /**< Low Power mode disabled */ | ||
322 | LIS3MDL_COMP_LP_ENABLED = 0x20 /**< Low Power mode enabled */ | ||
323 | }lis3mdl_comp_lp_t; | ||
324 | |||
325 | /** | ||
326 | * @brief LIS3MDL conversion mode | ||
327 | */ | ||
328 | typedef enum { | ||
329 | LIS3MDL_COMP_MD_CONTINUOUS = 0x00,/**< Continuous conversion mode */ | ||
330 | LIS3MDL_COMP_MD_SINGLE = 0x01, /**< Single conversion mode */ | ||
331 | LIS3MDL_COMP_MD_POWER_DOWN = 0x02 /**< Power down mode */ | ||
332 | }lis3mdl_comp_md_t; | ||
333 | |||
334 | /** | ||
335 | * @brief LIS3MDL operation mode for X and Y axes | ||
336 | */ | ||
337 | typedef enum { | ||
338 | LIS3MDL_COMP_OMXY_LP = 0x00, /**< X-Y axes low power mode */ | ||
339 | LIS3MDL_COMP_OMXY_MEDIUM = 0x20, /**< X-Y axes medium performance mode */ | ||
340 | LIS3MDL_COMP_OMXY_HIGH = 0x40, /**< X-Y axes high performance mode */ | ||
341 | LIS3MDL_COMP_OMXY_ULTRA = 0x60 /**< X-Y axes ultra performance mode */ | ||
342 | }lis3mdl_comp_omxy_t; | ||
343 | |||
344 | /** | ||
345 | * @brief LIS3MDL operation mode for Z axis | ||
346 | */ | ||
347 | typedef enum { | ||
348 | LIS3MDL_COMP_OMZ_LP = 0x00, /**< Z axis low power mode */ | ||
349 | LIS3MDL_COMP_OMZ_MEDIUM = 0x04, /**< Z axis medium performance mode */ | ||
350 | LIS3MDL_COMP_OMZ_HIGH = 0x08, /**< Z axis high performance mode */ | ||
351 | LIS3MDL_COMP_OMZ_ULTRA = 0x0C /**< Z axis ultra performance mode */ | ||
352 | }lis3mdl_comp_omz_t; | ||
353 | |||
354 | /** | ||
355 | * @brief LIS3MDL temperature sensor enabling | ||
356 | */ | ||
357 | typedef enum { | ||
358 | LIS3MDL_TEMP_DISABLED = 0x00, /**< Temperature sensor disabled. */ | ||
359 | LIS3MDL_TEMP_ENABLED = 0x80 /**< Temperature sensor enabled. */ | ||
360 | }lis3mdl_temp_t; | ||
361 | |||
362 | /** | ||
363 | * @brief LIS3MDL block data update | ||
364 | */ | ||
365 | typedef enum { | ||
366 | LIS3MDL_BDU_CONTINUOUS = 0x00, /**< Continuous Update */ | ||
367 | LIS3MDL_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ | ||
368 | }lis3mdl_bdu_t; | ||
369 | |||
370 | /** | ||
371 | * @brief LIS3MDL endianness | ||
372 | */ | ||
373 | typedef enum { | ||
374 | LIS3MDL_END_LITTLE = 0x00, /**< Little endian. */ | ||
375 | LIS3MDL_END_BIG = 0x02 /**< Big endian. */ | ||
376 | }lis3mdl_end_t; | ||
377 | |||
378 | /** | ||
379 | * @brief Driver state machine possible states. | ||
380 | */ | ||
381 | typedef enum { | ||
382 | LIS3MDL_UNINIT = 0, /**< Not initialized. */ | ||
383 | LIS3MDL_STOP = 1, /**< Stopped. */ | ||
384 | LIS3MDL_READY = 2, /**< Ready. */ | ||
385 | } lis3mdl_state_t; | ||
386 | |||
387 | /** | ||
388 | * @brief LIS3MDL configuration structure. | ||
389 | */ | ||
390 | typedef struct { | ||
391 | #if (LIS3MDL_USE_SPI) || defined(__DOXYGEN__) | ||
392 | /** | ||
393 | * @brief SPI driver associated to this LIS3MDL. | ||
394 | */ | ||
395 | SPIDriver *spip; | ||
396 | /** | ||
397 | * @brief SPI configuration associated to this LIS3MDL. | ||
398 | */ | ||
399 | const SPIConfig *spicfg; | ||
400 | #endif /* LIS3MDL_USE_SPI */ | ||
401 | #if (LIS3MDL_USE_I2C) || defined(__DOXYGEN__) | ||
402 | /** | ||
403 | * @brief I2C driver associated to this LIS3MDL. | ||
404 | */ | ||
405 | I2CDriver *i2cp; | ||
406 | /** | ||
407 | * @brief I2C configuration associated to this LIS3MDL. | ||
408 | */ | ||
409 | const I2CConfig *i2ccfg; | ||
410 | /** | ||
411 | * @brief LIS3MDL slave address | ||
412 | */ | ||
413 | lis3mdl_sad_t slaveaddress; | ||
414 | #endif /* LIS3MDL_USE_I2C */ | ||
415 | /** | ||
416 | * @brief LIS3MDL compass subsystem initial sensitivity. | ||
417 | */ | ||
418 | float *compsensitivity; | ||
419 | /** | ||
420 | * @brief LIS3MDL compass subsystem initial bias. | ||
421 | */ | ||
422 | float *compbias; | ||
423 | /** | ||
424 | * @brief LIS3MDL compass subsystem full scale. | ||
425 | */ | ||
426 | lis3mdl_comp_fs_t compfullscale; | ||
427 | /** | ||
428 | * @brief LIS3MDL compass subsystem output data rate. | ||
429 | */ | ||
430 | lis3mdl_comp_odr_t compoutputdatarate; | ||
431 | #if LIS3MDL_USE_ADVANCED || defined(__DOXYGEN__) | ||
432 | /** | ||
433 | * @brief LIS3MDL compass subsystem low power mode configuration. | ||
434 | */ | ||
435 | lis3mdl_comp_lp_t complowpowermode; | ||
436 | /** | ||
437 | * @brief LIS3MDL compass subsystem conversion mode. | ||
438 | */ | ||
439 | lis3mdl_comp_md_t compconversionmode; | ||
440 | /** | ||
441 | * @brief LIS3MDL compass subsystem operation mode for X and Y axes. | ||
442 | */ | ||
443 | lis3mdl_comp_omxy_t compoperationmodexy; | ||
444 | /** | ||
445 | * @brief LIS3MDL compass subsystem operation mode for Z axis. | ||
446 | */ | ||
447 | lis3mdl_comp_omz_t compoperationmodez; | ||
448 | /** | ||
449 | * @brief LIS3MDL block data update. | ||
450 | */ | ||
451 | lis3mdl_bdu_t blockdataupdate; | ||
452 | /** | ||
453 | * @brief LIS3MDL endianness. | ||
454 | */ | ||
455 | lis3mdl_end_t endianness; | ||
456 | #endif | ||
457 | } LIS3MDLConfig; | ||
458 | |||
459 | /** | ||
460 | * @brief @p LIS3MDL specific methods. | ||
461 | */ | ||
462 | #define _lis3msl_methods_alone \ | ||
463 | /* Change full scale value of LIS3MDL compass subsystem.*/ \ | ||
464 | msg_t (*comp_set_full_scale)(LIS3MDLDriver *devp, lis3mdl_comp_fs_t fs); | ||
465 | |||
466 | /** | ||
467 | * @brief @p LIS3MDL specific methods with inherited ones. | ||
468 | */ | ||
469 | #define _lis3mdl_methods \ | ||
470 | _base_object_methods \ | ||
471 | _lis3msl_methods_alone | ||
472 | |||
473 | /** | ||
474 | * @extends BaseCompassVMT | ||
475 | * | ||
476 | * @brief @p LIS3MDL virtual methods table. | ||
477 | */ | ||
478 | struct LIS3MDLVMT { | ||
479 | _lis3mdl_methods | ||
480 | }; | ||
481 | |||
482 | /** | ||
483 | * @brief @p LIS3MDLDriver specific data. | ||
484 | */ | ||
485 | #define _lis3mdl_data \ | ||
486 | _base_compass_data \ | ||
487 | /* Driver state.*/ \ | ||
488 | lis3mdl_state_t state; \ | ||
489 | /* Current configuration data.*/ \ | ||
490 | const LIS3MDLConfig *config; \ | ||
491 | /* Compass subsystem axes number.*/ \ | ||
492 | size_t compaxes; \ | ||
493 | /* Compass subsystem current sensitivity.*/ \ | ||
494 | float compsensitivity[LIS3MDL_COMP_NUMBER_OF_AXES]; \ | ||
495 | /* Compass subsystem current bias.*/ \ | ||
496 | float compbias[LIS3MDL_COMP_NUMBER_OF_AXES]; \ | ||
497 | /* Compass subsystem current full scale value.*/ \ | ||
498 | float compfullscale; | ||
499 | |||
500 | /** | ||
501 | * @brief LIS3MDL 3-axis compass class. | ||
502 | */ | ||
503 | struct LIS3MDLDriver { | ||
504 | /** @brief Virtual Methods Table.*/ | ||
505 | const struct LIS3MDLVMT *vmt; | ||
506 | /** @brief Base compass interface.*/ | ||
507 | BaseCompass comp_if; | ||
508 | _lis3mdl_data | ||
509 | }; | ||
510 | /** @} */ | ||
511 | |||
512 | /*===========================================================================*/ | ||
513 | /* Driver macros. */ | ||
514 | /*===========================================================================*/ | ||
515 | |||
516 | /** | ||
517 | * @brief Return the number of axes of the BaseCompass. | ||
518 | * | ||
519 | * @param[in] devp pointer to @p LIS3MDLDriver. | ||
520 | * | ||
521 | * @return the number of axes. | ||
522 | * | ||
523 | * @api | ||
524 | */ | ||
525 | #define lis3mdlCompassGetAxesNumber(devp) \ | ||
526 | compassGetAxesNumber(&((devp)->comp_if)) | ||
527 | |||
528 | /** | ||
529 | * @brief Retrieves raw data from the BaseCompass. | ||
530 | * @note This data is retrieved from MEMS register without any algebraical | ||
531 | * manipulation. | ||
532 | * @note The axes array must be at least the same size of the | ||
533 | * BaseCompass axes number. | ||
534 | * | ||
535 | * @param[in] devp pointer to @p BaseCompass interface. | ||
536 | * @param[out] axes a buffer which would be filled with raw data. | ||
537 | * | ||
538 | * @return The operation status. | ||
539 | * @retval MSG_OK if the function succeeded. | ||
540 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
541 | * be retrieved using @p i2cGetErrors(). | ||
542 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
543 | * | ||
544 | * @api | ||
545 | */ | ||
546 | #define lis3mdlCompassReadRaw(devp, axes) \ | ||
547 | compassReadRaw(&((devp)->comp_if), axes) | ||
548 | |||
549 | /** | ||
550 | * @brief Retrieves cooked data from the BaseCompass. | ||
551 | * @note This data is manipulated according to the formula | ||
552 | * cooked = (raw * sensitivity) - bias. | ||
553 | * @note Final data is expressed as G. | ||
554 | * @note The axes array must be at least the same size of the | ||
555 | * BaseCompass axes number. | ||
556 | * | ||
557 | * @param[in] devp pointer to @p BaseCompass interface. | ||
558 | * @param[out] axes a buffer which would be filled with cooked data. | ||
559 | * | ||
560 | * @return The operation status. | ||
561 | * @retval MSG_OK if the function succeeded. | ||
562 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
563 | * be retrieved using @p i2cGetErrors(). | ||
564 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
565 | * | ||
566 | * @api | ||
567 | */ | ||
568 | #define lis3mdlCompassReadCooked(devp, axes) \ | ||
569 | compassReadCooked(&((devp)->comp_if), axes) | ||
570 | |||
571 | /** | ||
572 | * @brief Set bias values for the BaseCompass. | ||
573 | * @note Bias must be expressed as G. | ||
574 | * @note The bias buffer must be at least the same size of the | ||
575 | * BaseCompass axes number. | ||
576 | * | ||
577 | * @param[in] devp pointer to @p BaseCompass interface. | ||
578 | * @param[in] bp a buffer which contains biases. | ||
579 | * | ||
580 | * @return The operation status. | ||
581 | * @retval MSG_OK if the function succeeded. | ||
582 | * | ||
583 | * @api | ||
584 | */ | ||
585 | #define lis3mdlCompassSetBias(devp, bp) \ | ||
586 | compassSetBias(&((devp)->comp_if), bp) | ||
587 | |||
588 | /** | ||
589 | * @brief Reset bias values for the BaseCompass. | ||
590 | * @note Default biases value are obtained from device datasheet when | ||
591 | * available otherwise they are considered zero. | ||
592 | * | ||
593 | * @param[in] devp pointer to @p LIS3MDLDriver. | ||
594 | * | ||
595 | * @return The operation status. | ||
596 | * @retval MSG_OK if the function succeeded. | ||
597 | * | ||
598 | * @api | ||
599 | */ | ||
600 | #define lis3mdlCompassResetBias(devp) \ | ||
601 | compassResetBias(&((devp)->comp_if)) | ||
602 | |||
603 | /** | ||
604 | * @brief Set sensitivity values for the BaseCompass. | ||
605 | * @note Sensitivity must be expressed as G/LSB. | ||
606 | * @note The sensitivity buffer must be at least the same size of the | ||
607 | * BaseCompass axes number. | ||
608 | * | ||
609 | * @param[in] devp pointer to @p LIS3MDLDriver. | ||
610 | * @param[in] sp a buffer which contains sensitivities. | ||
611 | * | ||
612 | * @return The operation status. | ||
613 | * @retval MSG_OK if the function succeeded. | ||
614 | * | ||
615 | * @api | ||
616 | */ | ||
617 | #define lis3mdlCompassSetSensitivity(devp, sp) \ | ||
618 | compassSetSensitivity(&((devp)->comp_if), sp) | ||
619 | |||
620 | /** | ||
621 | * @brief Reset sensitivity values for the BaseCompass. | ||
622 | * @note Default sensitivities value are obtained from device datasheet. | ||
623 | * | ||
624 | * @param[in] devp pointer to @p LIS3MDLDriver. | ||
625 | * | ||
626 | * @return The operation status. | ||
627 | * @retval MSG_OK if the function succeeded. | ||
628 | * @retval MSG_RESET otherwise. | ||
629 | * | ||
630 | * @api | ||
631 | */ | ||
632 | #define lis3mdlCompassResetSensitivity(devp) \ | ||
633 | compassResetSensitivity(&((devp)->comp_if)) | ||
634 | |||
635 | /** | ||
636 | * @brief Changes the LIS3MDLDriver compass fullscale value. | ||
637 | * @note This function also rescale sensitivities and biases based on | ||
638 | * previous and next fullscale value. | ||
639 | * @note A recalibration is highly suggested after calling this function. | ||
640 | * | ||
641 | * @param[in] devp pointer to @p LIS3MDLDriver. | ||
642 | * @param[in] fs new fullscale value. | ||
643 | * | ||
644 | * @return The operation status. | ||
645 | * @retval MSG_OK if the function succeeded. | ||
646 | * @retval MSG_RESET otherwise. | ||
647 | * | ||
648 | * @api | ||
649 | */ | ||
650 | #define lis3mdlCompassSetFullScale(devp, fs) \ | ||
651 | (devp)->vmt->comp_set_full_scale(devp, fs) | ||
652 | |||
653 | /*===========================================================================*/ | ||
654 | /* External declarations. */ | ||
655 | /*===========================================================================*/ | ||
656 | |||
657 | #ifdef __cplusplus | ||
658 | extern "C" { | ||
659 | #endif | ||
660 | void lis3mdlObjectInit(LIS3MDLDriver *devp); | ||
661 | void lis3mdlStart(LIS3MDLDriver *devp, const LIS3MDLConfig *config); | ||
662 | void lis3mdlStop(LIS3MDLDriver *devp); | ||
663 | #ifdef __cplusplus | ||
664 | } | ||
665 | #endif | ||
666 | |||
667 | #endif /* _LIS3MDL_H_ */ | ||
668 | |||
669 | /** @} */ | ||
670 | |||
diff --git a/lib/chibios/os/ex/devices/ST/lis3mdl.mk b/lib/chibios/os/ex/devices/ST/lis3mdl.mk new file mode 100644 index 000000000..941c34e17 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lis3mdl.mk | |||
@@ -0,0 +1,10 @@ | |||
1 | # List of all the LIS3MDL device files. | ||
2 | LIS3MDLSRC := $(CHIBIOS)/os/ex/devices/ST/lis3mdl.c | ||
3 | |||
4 | # Required include directories | ||
5 | LIS3MDLINC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(LIS3MDLSRC) | ||
10 | ALLINC += $(LIS3MDLINC) \ No newline at end of file | ||
diff --git a/lib/chibios/os/ex/devices/ST/lps22hb.c b/lib/chibios/os/ex/devices/ST/lps22hb.c new file mode 100644 index 000000000..d153a0d67 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lps22hb.c | |||
@@ -0,0 +1,686 @@ | |||
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 lps22hb.c | ||
23 | * @brief LPS22HB MEMS interface module code. | ||
24 | * | ||
25 | * @addtogroup LPS22HB | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #include "hal.h" | ||
31 | #include "lps22hb.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 (LPS22HB_USE_I2C) || defined(__DOXYGEN__) | ||
50 | /** | ||
51 | * @brief Reads registers value using I2C. | ||
52 | * @pre The I2C interface must be initialized and the driver started. | ||
53 | * | ||
54 | * @param[in] i2cp pointer to the I2C interface | ||
55 | * @param[in] sad slave address without R bit | ||
56 | * @param[in] reg first sub-register address | ||
57 | * @param[out] rxbuf pointer to an output buffer | ||
58 | * @param[in] n number of consecutive register to read | ||
59 | * @return the operation status. | ||
60 | * | ||
61 | * @notapi | ||
62 | */ | ||
63 | static msg_t lps22hbI2CReadRegister(I2CDriver *i2cp, lps22hb_sad_t sad, | ||
64 | uint8_t reg, uint8_t* rxbuf, size_t n) { | ||
65 | |||
66 | return i2cMasterTransmitTimeout(i2cp, sad, ®, 1, rxbuf, n, | ||
67 | TIME_INFINITE); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * @brief Writes a value into a register using I2C. | ||
72 | * @pre The I2C interface must be initialized and the driver started. | ||
73 | * | ||
74 | * @param[in] i2cp pointer to the I2C interface | ||
75 | * @param[in] sad slave address without R bit | ||
76 | * @param[in] txbuf buffer containing sub-address value in first position | ||
77 | * and values to write | ||
78 | * @param[in] n size of txbuf less one (not considering the first | ||
79 | * element) | ||
80 | * @return the operation status. | ||
81 | * | ||
82 | * @notapi | ||
83 | */ | ||
84 | #define lps22hbI2CWriteRegister(i2cp, sad, txbuf, n) \ | ||
85 | i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, \ | ||
86 | TIME_INFINITE) | ||
87 | #endif /* LPS22HB_USE_I2C */ | ||
88 | |||
89 | /** | ||
90 | * @brief Return the number of axes of the BaseBarometer. | ||
91 | * | ||
92 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
93 | * | ||
94 | * @return the number of axes. | ||
95 | */ | ||
96 | static size_t baro_get_axes_number(void *ip) { | ||
97 | (void)ip; | ||
98 | |||
99 | return LPS22HB_BARO_NUMBER_OF_AXES; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * @brief Retrieves raw data from the BaseBarometer. | ||
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 | * BaseBarometer axes number. | ||
108 | * | ||
109 | * @param[in] ip pointer to @p BaseBarometer 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 baro_read_raw(void *ip, int32_t axes[]) { | ||
119 | LPS22HBDriver* devp; | ||
120 | uint8_t buff[3]; | ||
121 | msg_t msg; | ||
122 | |||
123 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
124 | |||
125 | /* Getting parent instance pointer.*/ | ||
126 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
127 | |||
128 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
129 | "baro_read_raw(), invalid state"); | ||
130 | |||
131 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
132 | "baro_read_raw(), channel not ready"); | ||
133 | |||
134 | #if LPS22HB_SHARED_I2C | ||
135 | i2cAcquireBus(devp->config->i2cp); | ||
136 | i2cStart(devp->config->i2cp, | ||
137 | devp->config->i2ccfg); | ||
138 | #endif /* LPS22HB_SHARED_I2C */ | ||
139 | |||
140 | msg = lps22hbI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
141 | LPS22HB_AD_PRESS_OUT_XL, buff, 3); | ||
142 | |||
143 | #if LPS22HB_SHARED_I2C | ||
144 | i2cReleaseBus(devp->config->i2cp); | ||
145 | #endif /* LPS22HB_SHARED_I2C */ | ||
146 | |||
147 | if(msg == MSG_OK) { | ||
148 | *axes = buff[0] + (buff[1] << 8) + (buff[2] << 16); | ||
149 | } | ||
150 | return msg; | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * @brief Retrieves cooked data from the BaseBarometer. | ||
155 | * @note This data is manipulated according to the formula | ||
156 | * cooked = (raw * sensitivity) - bias. | ||
157 | * @note Final data is expressed as hPa. | ||
158 | * @note The axes array must be at least the same size of the | ||
159 | * BaseBarometer axes number. | ||
160 | * | ||
161 | * @param[in] ip pointer to @p BaseBarometer 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 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
167 | * be retrieved using @p i2cGetErrors(). | ||
168 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
169 | */ | ||
170 | static msg_t baro_read_cooked(void *ip, float axes[]) { | ||
171 | LPS22HBDriver* devp; | ||
172 | int32_t raw; | ||
173 | msg_t msg; | ||
174 | |||
175 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
176 | |||
177 | /* Getting parent instance pointer.*/ | ||
178 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
179 | |||
180 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
181 | "baro_read_cooked(), invalid state"); | ||
182 | |||
183 | msg = baro_read_raw(ip, &raw); | ||
184 | |||
185 | *axes = (raw * devp->barosensitivity) - devp->barobias; | ||
186 | |||
187 | return msg; | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * @brief Set bias values for the BaseBarometer. | ||
192 | * @note Bias must be expressed as hPa. | ||
193 | * @note The bias buffer must be at least the same size of the | ||
194 | * BaseBarometer axes number. | ||
195 | * | ||
196 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
197 | * @param[in] bp a buffer which contains biases. | ||
198 | * | ||
199 | * @return The operation status. | ||
200 | * @retval MSG_OK if the function succeeded. | ||
201 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
202 | * be retrieved using @p i2cGetErrors(). | ||
203 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
204 | */ | ||
205 | static msg_t baro_set_bias(void *ip, float *bp) { | ||
206 | LPS22HBDriver* devp; | ||
207 | msg_t msg = MSG_OK; | ||
208 | |||
209 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
210 | |||
211 | /* Getting parent instance pointer.*/ | ||
212 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
213 | |||
214 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
215 | "baro_set_bias(), invalid state"); | ||
216 | |||
217 | devp->barobias = *bp; | ||
218 | return msg; | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * @brief Reset bias values for the BaseBarometer. | ||
223 | * @note Default biases value are obtained from device datasheet when | ||
224 | * available otherwise they are considered zero. | ||
225 | * | ||
226 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
227 | * | ||
228 | * @return The operation status. | ||
229 | * @retval MSG_OK if the function succeeded. | ||
230 | */ | ||
231 | static msg_t baro_reset_bias(void *ip) { | ||
232 | LPS22HBDriver* devp; | ||
233 | msg_t msg = MSG_OK; | ||
234 | |||
235 | osalDbgCheck(ip != NULL); | ||
236 | |||
237 | /* Getting parent instance pointer.*/ | ||
238 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
239 | |||
240 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
241 | "baro_reset_bias(), invalid state"); | ||
242 | |||
243 | devp->barobias = LPS22HB_BARO_SENS; | ||
244 | return msg; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * @brief Set sensitivity values for the BaseBarometer. | ||
249 | * @note Sensitivity must be expressed as hPa/LSB. | ||
250 | * @note The sensitivity buffer must be at least the same size of the | ||
251 | * BaseBarometer axes number. | ||
252 | * | ||
253 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
254 | * @param[in] sp a buffer which contains sensitivities. | ||
255 | * | ||
256 | * @return The operation status. | ||
257 | * @retval MSG_OK if the function succeeded. | ||
258 | */ | ||
259 | static msg_t baro_set_sensitivity(void *ip, float *sp) { | ||
260 | LPS22HBDriver* devp; | ||
261 | msg_t msg = MSG_OK; | ||
262 | |||
263 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
264 | |||
265 | /* Getting parent instance pointer.*/ | ||
266 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
267 | |||
268 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
269 | "baro_set_sensitivity(), invalid state"); | ||
270 | |||
271 | devp->barosensitivity = *sp; | ||
272 | return msg; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * @brief Reset sensitivity values for the BaseBarometer. | ||
277 | * @note Default sensitivities value are obtained from device datasheet. | ||
278 | * | ||
279 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
280 | * | ||
281 | * @return The operation status. | ||
282 | * @retval MSG_OK if the function succeeded. | ||
283 | */ | ||
284 | static msg_t baro_reset_sensitivity(void *ip) { | ||
285 | LPS22HBDriver* devp; | ||
286 | msg_t msg = MSG_OK; | ||
287 | |||
288 | osalDbgCheck(ip != NULL); | ||
289 | |||
290 | /* Getting parent instance pointer.*/ | ||
291 | devp = objGetInstance(LPS22HBDriver*, (BaseBarometer*)ip); | ||
292 | |||
293 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
294 | "baro_reset_sensitivity(), invalid state"); | ||
295 | |||
296 | devp->barosensitivity = LPS22HB_BARO_SENS; | ||
297 | return msg; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * @brief Return the number of axes of the BaseThermometer. | ||
302 | * | ||
303 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
304 | * | ||
305 | * @return the number of axes. | ||
306 | */ | ||
307 | static size_t thermo_get_axes_number(void *ip) { | ||
308 | (void)ip; | ||
309 | |||
310 | return LPS22HB_THERMO_NUMBER_OF_AXES; | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * @brief Retrieves raw data from the BaseThermometer. | ||
315 | * @note This data is retrieved from MEMS register without any algebraical | ||
316 | * manipulation. | ||
317 | * @note The axes array must be at least the same size of the | ||
318 | * BaseThermometer axes number. | ||
319 | * | ||
320 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
321 | * @param[out] axes a buffer which would be filled with raw data. | ||
322 | * | ||
323 | * @return The operation status. | ||
324 | * @retval MSG_OK if the function succeeded. | ||
325 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
326 | * be retrieved using @p i2cGetErrors(). | ||
327 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
328 | */ | ||
329 | static msg_t thermo_read_raw(void *ip, int32_t axes[]) { | ||
330 | LPS22HBDriver* devp; | ||
331 | int16_t tmp; | ||
332 | uint8_t buff[2]; | ||
333 | msg_t msg; | ||
334 | |||
335 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
336 | |||
337 | /* Getting parent instance pointer.*/ | ||
338 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
339 | |||
340 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
341 | "thermo_read_raw(), invalid state"); | ||
342 | |||
343 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
344 | "thermo_read_raw(), channel not ready"); | ||
345 | |||
346 | #if LPS22HB_SHARED_I2C | ||
347 | i2cAcquireBus(devp->config->i2cp); | ||
348 | i2cStart(devp->config->i2cp, | ||
349 | devp->config->i2ccfg); | ||
350 | #endif /* LPS22HB_SHARED_I2C */ | ||
351 | |||
352 | msg = lps22hbI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
353 | LPS22HB_AD_TEMP_OUT_L, buff, 2); | ||
354 | |||
355 | #if LPS22HB_SHARED_I2C | ||
356 | i2cReleaseBus(devp->config->i2cp); | ||
357 | #endif /* LPS22HB_SHARED_I2C */ | ||
358 | |||
359 | if (msg == MSG_OK) { | ||
360 | tmp = buff[0] + (buff[1] << 8); | ||
361 | *axes = (int32_t)tmp; | ||
362 | } | ||
363 | return msg; | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * @brief Retrieves cooked data from the BaseThermometer. | ||
368 | * @note This data is manipulated according to the formula | ||
369 | * cooked = (raw * sensitivity) - bias. | ||
370 | * @note Final data is expressed as °C. | ||
371 | * @note The axes array must be at least the same size of the | ||
372 | * BaseThermometer axes number. | ||
373 | * | ||
374 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
375 | * @param[out] axis a buffer which would be filled with cooked data. | ||
376 | * | ||
377 | * @return The operation status. | ||
378 | * @retval MSG_OK if the function succeeded. | ||
379 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
380 | * be retrieved using @p i2cGetErrors(). | ||
381 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
382 | */ | ||
383 | static msg_t thermo_read_cooked(void *ip, float* axis) { | ||
384 | LPS22HBDriver* devp; | ||
385 | int32_t raw; | ||
386 | msg_t msg; | ||
387 | |||
388 | osalDbgCheck((ip != NULL) && (axis != NULL)); | ||
389 | |||
390 | /* Getting parent instance pointer.*/ | ||
391 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
392 | |||
393 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
394 | "thermo_read_cooked(), invalid state"); | ||
395 | |||
396 | msg = thermo_read_raw(devp, &raw); | ||
397 | |||
398 | *axis = (raw * devp->thermosensitivity) - devp->thermobias; | ||
399 | |||
400 | return msg; | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * @brief Set bias values for the BaseThermometer. | ||
405 | * @note Bias must be expressed as °C. | ||
406 | * @note The bias buffer must be at least the same size of the | ||
407 | * BaseThermometer axes number. | ||
408 | * | ||
409 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
410 | * @param[in] bp a buffer which contains biases. | ||
411 | * | ||
412 | * @return The operation status. | ||
413 | * @retval MSG_OK if the function succeeded. | ||
414 | */ | ||
415 | static msg_t thermo_set_bias(void *ip, float *bp) { | ||
416 | LPS22HBDriver* devp; | ||
417 | msg_t msg = MSG_OK; | ||
418 | |||
419 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
420 | |||
421 | /* Getting parent instance pointer.*/ | ||
422 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
423 | |||
424 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
425 | "thermo_set_bias(), invalid state"); | ||
426 | |||
427 | devp->thermobias = *bp; | ||
428 | |||
429 | return msg; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * @brief Reset bias values for the BaseThermometer. | ||
434 | * @note Default biases value are obtained from device datasheet when | ||
435 | * available otherwise they are considered zero. | ||
436 | * | ||
437 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
438 | * | ||
439 | * @return The operation status. | ||
440 | * @retval MSG_OK if the function succeeded. | ||
441 | */ | ||
442 | static msg_t thermo_reset_bias(void *ip) { | ||
443 | LPS22HBDriver* devp; | ||
444 | msg_t msg = MSG_OK; | ||
445 | |||
446 | osalDbgCheck(ip != NULL); | ||
447 | |||
448 | /* Getting parent instance pointer.*/ | ||
449 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
450 | |||
451 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
452 | "thermo_reset_bias(), invalid state"); | ||
453 | |||
454 | devp->thermobias = LPS22HB_THERMO_BIAS; | ||
455 | |||
456 | return msg; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * @brief Set sensitivity values for the BaseThermometer. | ||
461 | * @note Sensitivity must be expressed as °C/LSB. | ||
462 | * @note The sensitivity buffer must be at least the same size of the | ||
463 | * BaseThermometer axes number. | ||
464 | * | ||
465 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
466 | * @param[in] sp a buffer which contains sensitivities. | ||
467 | * | ||
468 | * @return The operation status. | ||
469 | * @retval MSG_OK if the function succeeded. | ||
470 | */ | ||
471 | static msg_t thermo_set_sensitivity(void *ip, float *sp) { | ||
472 | LPS22HBDriver* devp; | ||
473 | msg_t msg = MSG_OK; | ||
474 | |||
475 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
476 | |||
477 | /* Getting parent instance pointer.*/ | ||
478 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
479 | |||
480 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
481 | "thermo_set_sensitivity(), invalid state"); | ||
482 | |||
483 | devp->thermosensitivity = *sp; | ||
484 | |||
485 | return msg; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * @brief Reset sensitivity values for the BaseThermometer. | ||
490 | * @note Default sensitivities value are obtained from device datasheet. | ||
491 | * | ||
492 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
493 | * | ||
494 | * @return The operation status. | ||
495 | * @retval MSG_OK if the function succeeded. | ||
496 | */ | ||
497 | static msg_t thermo_reset_sensitivity(void *ip) { | ||
498 | LPS22HBDriver* devp; | ||
499 | msg_t msg = MSG_OK; | ||
500 | |||
501 | osalDbgCheck(ip != NULL); | ||
502 | |||
503 | /* Getting parent instance pointer.*/ | ||
504 | devp = objGetInstance(LPS22HBDriver*, (BaseThermometer*)ip); | ||
505 | |||
506 | osalDbgAssert((devp->state == LPS22HB_READY), | ||
507 | "thermo_reset_sensitivity(), invalid state"); | ||
508 | |||
509 | devp->thermosensitivity = LPS22HB_THERMO_SENS; | ||
510 | |||
511 | return msg; | ||
512 | } | ||
513 | |||
514 | static const struct LPS22HBVMT vmt_device = { | ||
515 | (size_t)0 | ||
516 | }; | ||
517 | |||
518 | static const struct BaseBarometerVMT vmt_barometer = { | ||
519 | sizeof(struct LPS22HBVMT*), | ||
520 | baro_get_axes_number, baro_read_raw, baro_read_cooked, | ||
521 | baro_set_bias, baro_reset_bias, baro_set_sensitivity, | ||
522 | baro_reset_sensitivity | ||
523 | }; | ||
524 | |||
525 | static const struct BaseThermometerVMT vmt_thermometer = { | ||
526 | sizeof(struct LPS22HBVMT*) + sizeof(BaseBarometer), | ||
527 | thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, | ||
528 | thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity, | ||
529 | thermo_reset_sensitivity | ||
530 | }; | ||
531 | |||
532 | /*===========================================================================*/ | ||
533 | /* Driver exported functions. */ | ||
534 | /*===========================================================================*/ | ||
535 | |||
536 | /** | ||
537 | * @brief Initializes an instance. | ||
538 | * | ||
539 | * @param[out] devp pointer to the @p LPS22HBDriver object | ||
540 | * | ||
541 | * @init | ||
542 | */ | ||
543 | void lps22hbObjectInit(LPS22HBDriver *devp) { | ||
544 | |||
545 | devp->vmt = &vmt_device; | ||
546 | devp->baro_if.vmt = &vmt_barometer; | ||
547 | devp->thermo_if.vmt = &vmt_thermometer; | ||
548 | |||
549 | devp->config = NULL; | ||
550 | |||
551 | devp->baroaxes = LPS22HB_BARO_NUMBER_OF_AXES; | ||
552 | devp->thermoaxes = LPS22HB_THERMO_NUMBER_OF_AXES; | ||
553 | |||
554 | devp->state = LPS22HB_STOP; | ||
555 | } | ||
556 | |||
557 | /** | ||
558 | * @brief Configures and activates LPS22HB Complex Driver peripheral. | ||
559 | * | ||
560 | * @param[in] devp pointer to the @p LPS22HBDriver object | ||
561 | * @param[in] config pointer to the @p LPS22HBConfig object | ||
562 | * | ||
563 | * @api | ||
564 | */ | ||
565 | void lps22hbStart(LPS22HBDriver *devp, const LPS22HBConfig *config) { | ||
566 | uint8_t cr[2]; | ||
567 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
568 | |||
569 | osalDbgAssert((devp->state == LPS22HB_STOP) || (devp->state == LPS22HB_READY), | ||
570 | "lps22hbStart(), invalid state"); | ||
571 | |||
572 | devp->config = config; | ||
573 | |||
574 | /* Enabling register auto-increment.*/ | ||
575 | /* Control register 1 configuration block.*/ | ||
576 | { | ||
577 | cr[0] = LPS22HB_AD_CTRL_REG2; | ||
578 | cr[1] = LPS22HB_CTRL_REG2_IF_ADD_INC; | ||
579 | } | ||
580 | #if LPS22HB_SHARED_I2C | ||
581 | i2cAcquireBus(devp->config->i2cp); | ||
582 | #endif /* LPS22HB_SHARED_I2C */ | ||
583 | |||
584 | i2cStart(devp->config->i2cp, devp->config->i2ccfg); | ||
585 | lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
586 | cr, 1); | ||
587 | |||
588 | #if LPS22HB_SHARED_I2C | ||
589 | i2cReleaseBus((devp)->config->i2cp); | ||
590 | #endif /* LPS22HB_SHARED_I2C */ | ||
591 | |||
592 | /* Control register 1 configuration block.*/ | ||
593 | { | ||
594 | cr[0] = LPS22HB_AD_CTRL_REG1; | ||
595 | cr[1] = devp->config->outputdatarate; | ||
596 | #if LPS22HB_USE_ADVANCED || defined(__DOXYGEN__) | ||
597 | cr[1] |= devp->config->blockdataupdate; | ||
598 | cr[1] |= devp->config->lowpass_filter; | ||
599 | #endif | ||
600 | } | ||
601 | |||
602 | #if LPS22HB_SHARED_I2C | ||
603 | i2cAcquireBus((devp)->config->i2cp); | ||
604 | i2cStart((devp)->config->i2cp, | ||
605 | (devp)->config->i2ccfg); | ||
606 | #endif /* LPS22HB_SHARED_I2C */ | ||
607 | |||
608 | lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, cr, 1); | ||
609 | |||
610 | #if LPS22HB_SHARED_I2C | ||
611 | i2cReleaseBus((devp)->config->i2cp); | ||
612 | #endif /* LPS22HB_SHARED_I2C */ | ||
613 | |||
614 | if(devp->config->barosensitivity == NULL) { | ||
615 | devp->barosensitivity = LPS22HB_BARO_SENS; | ||
616 | } | ||
617 | else{ | ||
618 | /* Taking barometer sensitivity from user configurations */ | ||
619 | devp->barosensitivity = *(devp->config->barosensitivity); | ||
620 | } | ||
621 | |||
622 | if(devp->config->barobias == NULL) { | ||
623 | devp->barobias = LPS22HB_BARO_BIAS; | ||
624 | } | ||
625 | else{ | ||
626 | /* Taking barometer bias from user configurations */ | ||
627 | devp->barobias = *(devp->config->barobias); | ||
628 | } | ||
629 | |||
630 | if(devp->config->thermosensitivity == NULL) { | ||
631 | devp->thermosensitivity = LPS22HB_THERMO_SENS; | ||
632 | } | ||
633 | else{ | ||
634 | /* Taking thermometer sensitivity from user configurations */ | ||
635 | devp->thermosensitivity = *(devp->config->thermosensitivity); | ||
636 | } | ||
637 | |||
638 | if(devp->config->thermobias == NULL) { | ||
639 | devp->thermobias = LPS22HB_THERMO_BIAS; | ||
640 | } | ||
641 | else{ | ||
642 | /* Taking thermometer bias from user configurations */ | ||
643 | devp->thermobias = *(devp->config->thermobias); | ||
644 | } | ||
645 | |||
646 | /* This is the Barometer transient recovery time */ | ||
647 | osalThreadSleepMilliseconds(5); | ||
648 | |||
649 | devp->state = LPS22HB_READY; | ||
650 | } | ||
651 | |||
652 | /** | ||
653 | * @brief Deactivates the LPS22HB Complex Driver peripheral. | ||
654 | * | ||
655 | * @param[in] devp pointer to the @p LPS22HBDriver object | ||
656 | * | ||
657 | * @api | ||
658 | */ | ||
659 | void lps22hbStop(LPS22HBDriver *devp) { | ||
660 | uint8_t cr[2]; | ||
661 | |||
662 | osalDbgCheck(devp != NULL); | ||
663 | |||
664 | osalDbgAssert((devp->state == LPS22HB_STOP) || (devp->state == LPS22HB_READY), | ||
665 | "lps22hbStop(), invalid state"); | ||
666 | |||
667 | if (devp->state == LPS22HB_READY) { | ||
668 | #if LPS22HB_SHARED_I2C | ||
669 | i2cAcquireBus((devp)->config->i2cp); | ||
670 | i2cStart((devp)->config->i2cp, | ||
671 | (devp)->config->i2ccfg); | ||
672 | #endif /* LPS22HB_SHARED_I2C */ | ||
673 | |||
674 | cr[0] = LPS22HB_AD_CTRL_REG1; | ||
675 | cr[1] = 0; | ||
676 | lps22hbI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
677 | cr, 1); | ||
678 | |||
679 | i2cStop((devp)->config->i2cp); | ||
680 | #if LPS22HB_SHARED_I2C | ||
681 | i2cReleaseBus((devp)->config->i2cp); | ||
682 | #endif /* LPS22HB_SHARED_I2C */ | ||
683 | } | ||
684 | devp->state = LPS22HB_STOP; | ||
685 | } | ||
686 | /** @} */ | ||
diff --git a/lib/chibios/os/ex/devices/ST/lps22hb.h b/lib/chibios/os/ex/devices/ST/lps22hb.h new file mode 100644 index 000000000..47cd5123b --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lps22hb.h | |||
@@ -0,0 +1,724 @@ | |||
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 lps22hb.h | ||
23 | * @brief LPS22HB MEMS interface module header. | ||
24 | * | ||
25 | * @addtogroup LPS22HB | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | #ifndef _LPS22HB_H_ | ||
30 | #define _LPS22HB_H_ | ||
31 | |||
32 | #include "ex_barometer.h" | ||
33 | #include "ex_thermometer.h" | ||
34 | |||
35 | /*===========================================================================*/ | ||
36 | /* Driver constants. */ | ||
37 | /*===========================================================================*/ | ||
38 | |||
39 | /** | ||
40 | * @name Version identification | ||
41 | * @{ | ||
42 | */ | ||
43 | /** | ||
44 | * @brief LPS22HB driver version string. | ||
45 | */ | ||
46 | #define EX_LPS22HB_VERSION "1.0.2" | ||
47 | |||
48 | /** | ||
49 | * @brief LPS22HB driver version major number. | ||
50 | */ | ||
51 | #define EX_LPS22HB_MAJOR 1 | ||
52 | |||
53 | /** | ||
54 | * @brief LPS22HB driver version minor number. | ||
55 | */ | ||
56 | #define EX_LPS22HB_MINOR 0 | ||
57 | |||
58 | /** | ||
59 | * @brief LPS22HB driver version patch number. | ||
60 | */ | ||
61 | #define EX_LPS22HB_PATCH 2 | ||
62 | /** @} */ | ||
63 | |||
64 | /** | ||
65 | * @brief LPS22HB barometer subsystem characteristics. | ||
66 | * @note Sensitivity is expressed as hPa/LSB whereas hPa stand for | ||
67 | * hectopascal. | ||
68 | * @note Bias is expressed as hPa. | ||
69 | * | ||
70 | * @{ | ||
71 | */ | ||
72 | #define LPS22HB_BARO_NUMBER_OF_AXES 1U | ||
73 | |||
74 | #define LPS22HB_BARO_SENS 0.00024414f | ||
75 | #define LPS22HB_BARO_BIAS 0.0f | ||
76 | /** @} */ | ||
77 | |||
78 | /** | ||
79 | * @brief LPS22HB thermometer subsystem characteristics. | ||
80 | * @note Sensitivity is expressed as �C/LSB. | ||
81 | * @note Bias is expressed as �C. | ||
82 | * | ||
83 | * @{ | ||
84 | */ | ||
85 | #define LPS22HB_THERMO_NUMBER_OF_AXES 1U | ||
86 | |||
87 | #define LPS22HB_THERMO_SENS 0.01f | ||
88 | #define LPS22HB_THERMO_BIAS 0.0f | ||
89 | /** @} */ | ||
90 | |||
91 | /** | ||
92 | * @name LPS22HB communication interfaces related bit masks | ||
93 | * @{ | ||
94 | */ | ||
95 | #define LPS22HB_DI_MASK 0xFF | ||
96 | #define LPS22HB_DI(n) (1 << n) | ||
97 | #define LPS22HB_AD_MASK 0x3F | ||
98 | #define LPS22HB_AD(n) (1 << n) | ||
99 | #define LPS22HB_MS (1 << 6) | ||
100 | #define LPS22HB_RW (1 << 7) | ||
101 | |||
102 | #define LPS22HB_SUB_MS (1 << 7) | ||
103 | /** @} */ | ||
104 | |||
105 | /** | ||
106 | * @name LPS22HB register addresses | ||
107 | * @{ | ||
108 | */ | ||
109 | #define LPS22HB_AD_INT_CFG 0x0B | ||
110 | #define LPS22HB_AD_THS_P_L 0x0C | ||
111 | #define LPS22HB_AD_THS_P_H 0x0D | ||
112 | #define LPS22HB_AD_WHO_AM_I 0x0F | ||
113 | #define LPS22HB_AD_CTRL_REG1 0x10 | ||
114 | #define LPS22HB_AD_CTRL_REG2 0x11 | ||
115 | #define LPS22HB_AD_CTRL_REG3 0x12 | ||
116 | #define LPS22HB_AD_FIFO_CTRL 0x14 | ||
117 | #define LPS22HB_AD_REF_P_XL 0x15 | ||
118 | #define LPS22HB_AD_REF_P_L 0x16 | ||
119 | #define LPS22HB_AD_REF_P_H 0x17 | ||
120 | #define LPS22HB_AD_RPDS_L 0x18 | ||
121 | #define LPS22HB_AD_RPDS_H 0x19 | ||
122 | #define LPS22HB_AD_RES_CONF 0x1A | ||
123 | #define LPS22HB_AD_INT_SRC 0x25 | ||
124 | #define LPS22HB_AD_FIFO_SRC 0x26 | ||
125 | #define LPS22HB_AD_STATUS_REG 0x27 | ||
126 | #define LPS22HB_AD_PRESS_OUT_XL 0x28 | ||
127 | #define LPS22HB_AD_PRESS_OUT_L 0x29 | ||
128 | #define LPS22HB_AD_PRESS_OUT_H 0x2A | ||
129 | #define LPS22HB_AD_TEMP_OUT_L 0x2B | ||
130 | #define LPS22HB_AD_TEMP_OUT_H 0x2C | ||
131 | #define LPS22HB_AD_LPFP_RES 0x33 | ||
132 | /** @} */ | ||
133 | |||
134 | /** | ||
135 | * @name LPS22HB_INT_CFG register bits definitions | ||
136 | * @{ | ||
137 | */ | ||
138 | #define LPS22HB_INT_CFG_MASK 0xFF | ||
139 | #define LPS22HB_INT_CFG_PHE (1 << 0) | ||
140 | #define LPS22HB_INT_CFG_PLE (1 << 1) | ||
141 | #define LPS22HB_INT_CFG_LIR (1 << 2) | ||
142 | #define LPS22HB_INT_CFG_DIFF_EN (1 << 3) | ||
143 | #define LPS22HB_INT_CFG_RESET_AZ (1 << 4) | ||
144 | #define LPS22HB_INT_CFG_AUTOZERO (1 << 5) | ||
145 | #define LPS22HB_INT_CFG_RESET_ARP (1 << 6) | ||
146 | #define LPS22HB_INT_CFG_AUTORIFP (1 << 7) | ||
147 | /** @} */ | ||
148 | |||
149 | /** | ||
150 | * @name LPS22HB_CTRL_REG1 register bits definitions | ||
151 | * @{ | ||
152 | */ | ||
153 | #define LPS22HB_CTRL_REG1_MASK 0x7F | ||
154 | #define LPS22HB_CTRL_REG1_SIM (1 << 0) | ||
155 | #define LPS22HB_CTRL_REG1_BDU (1 << 1) | ||
156 | #define LPS22HB_CTRL_REG1_LPFP_CFG (1 << 2) | ||
157 | #define LPS22HB_CTRL_REG1_LPFP_EN (1 << 3) | ||
158 | #define LPS22HB_CTRL_REG1_ODR0 (1 << 4) | ||
159 | #define LPS22HB_CTRL_REG1_ODR1 (1 << 5) | ||
160 | #define LPS22HB_CTRL_REG1_ODR2 (1 << 6) | ||
161 | /** @} */ | ||
162 | |||
163 | /** | ||
164 | * @name LPS22HB_CTRL_REG2 register bits definitions | ||
165 | * @{ | ||
166 | */ | ||
167 | #define LPS22HB_CTRL_REG2_MASK 0xFD | ||
168 | #define LPS22HB_CTRL_REG2_ONE_SHOT (1 << 0) | ||
169 | #define LPS22HB_CTRL_REG2_SWRESET (1 << 2) | ||
170 | #define LPS22HB_CTRL_REG2_I2C_DIS (1 << 3) | ||
171 | #define LPS22HB_CTRL_REG2_IF_ADD_INC (1 << 4) | ||
172 | #define LPS22HB_CTRL_REG2_STOP_ON_FTH (1 << 5) | ||
173 | #define LPS22HB_CTRL_REG2_FIFO_EN (1 << 6) | ||
174 | #define LPS22HB_CTRL_REG2_BOOT (1 << 7) | ||
175 | /** @} */ | ||
176 | |||
177 | /** | ||
178 | * @name LPS22HB_CTRL_REG3 register bits definitions | ||
179 | * @{ | ||
180 | */ | ||
181 | #define LPS22HB_CTRL_REG3_MASK 0xFF | ||
182 | #define LPS22HB_CTRL_REG3_INT_S1 (1 << 0) | ||
183 | #define LPS22HB_CTRL_REG3_INT_S2 (1 << 1) | ||
184 | #define LPS22HB_CTRL_REG3_DRDY (1 << 2) | ||
185 | #define LPS22HB_CTRL_REG3_F_OVR (1 << 3) | ||
186 | #define LPS22HB_CTRL_REG3_F_FTH (1 << 4) | ||
187 | #define LPS22HB_CTRL_REG3_F_FSS5 (1 << 5) | ||
188 | #define LPS22HB_CTRL_REG3_PP_OD (1 << 6) | ||
189 | #define LPS22HB_CTRL_REG3_INT_H_L (1 << 7) | ||
190 | /** @} */ | ||
191 | |||
192 | /** | ||
193 | * @name LPS22HB_INT_SRC register bits definitions | ||
194 | * @{ | ||
195 | */ | ||
196 | #define LPS22HB_INT_SRC_MASK 0x87 | ||
197 | #define LPS22HB_INT_SRC_PH (1 << 0) | ||
198 | #define LPS22HB_INT_SRC_PL (1 << 1) | ||
199 | #define LPS22HB_INT_SRC_IA (1 << 2) | ||
200 | #define LPS22HB_INT_SRC_BOOT_STATUS (1 << 8) | ||
201 | /** @} */ | ||
202 | |||
203 | /*===========================================================================*/ | ||
204 | /* Driver pre-compile time settings. */ | ||
205 | /*===========================================================================*/ | ||
206 | |||
207 | /** | ||
208 | * @name Configuration options | ||
209 | * @{ | ||
210 | */ | ||
211 | /** | ||
212 | * @brief LPS22HB SPI interface switch. | ||
213 | * @details If set to @p TRUE the support for SPI is included. | ||
214 | * @note The default is @p FALSE. | ||
215 | */ | ||
216 | #if !defined(LPS22HB_USE_SPI) || defined(__DOXYGEN__) | ||
217 | #define LPS22HB_USE_SPI FALSE | ||
218 | #endif | ||
219 | |||
220 | /** | ||
221 | * @brief LPS22HB shared SPI switch. | ||
222 | * @details If set to @p TRUE the device acquires SPI bus ownership | ||
223 | * on each transaction. | ||
224 | * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. | ||
225 | */ | ||
226 | #if !defined(LPS22HB_SHARED_SPI) || defined(__DOXYGEN__) | ||
227 | #define LPS22HB_SHARED_SPI FALSE | ||
228 | #endif | ||
229 | |||
230 | /** | ||
231 | * @brief LPS22HB I2C interface switch. | ||
232 | * @details If set to @p TRUE the support for I2C is included. | ||
233 | * @note The default is @p TRUE. | ||
234 | */ | ||
235 | #if !defined(LPS22HB_USE_I2C) || defined(__DOXYGEN__) | ||
236 | #define LPS22HB_USE_I2C TRUE | ||
237 | #endif | ||
238 | |||
239 | /** | ||
240 | * @brief LPS22HB shared I2C switch. | ||
241 | * @details If set to @p TRUE the device acquires I2C bus ownership | ||
242 | * on each transaction. | ||
243 | * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. | ||
244 | */ | ||
245 | #if !defined(LPS22HB_SHARED_I2C) || defined(__DOXYGEN__) | ||
246 | #define LPS22HB_SHARED_I2C FALSE | ||
247 | #endif | ||
248 | |||
249 | /** | ||
250 | * @brief LPS22HB advanced configurations switch. | ||
251 | * @details If set to @p TRUE more configurations are available. | ||
252 | * @note The default is @p FALSE. | ||
253 | */ | ||
254 | #if !defined(LPS22HB_USE_ADVANCED) || defined(__DOXYGEN__) | ||
255 | #define LPS22HB_USE_ADVANCED FALSE | ||
256 | #endif | ||
257 | /** @} */ | ||
258 | |||
259 | /*===========================================================================*/ | ||
260 | /* Derived constants and error checks. */ | ||
261 | /*===========================================================================*/ | ||
262 | |||
263 | #if !(LPS22HB_USE_SPI ^ LPS22HB_USE_I2C) | ||
264 | #error "LPS22HB_USE_SPI and LPS22HB_USE_I2C cannot be both true or both false" | ||
265 | #endif | ||
266 | |||
267 | #if LPS22HB_USE_SPI && !HAL_USE_SPI | ||
268 | #error "LPS22HB_USE_SPI requires HAL_USE_SPI" | ||
269 | #endif | ||
270 | |||
271 | #if LPS22HB_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION | ||
272 | #error "LPS22HB_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" | ||
273 | #endif | ||
274 | |||
275 | #if LPS22HB_USE_I2C && !HAL_USE_I2C | ||
276 | #error "LPS22HB_USE_I2C requires HAL_USE_I2C" | ||
277 | #endif | ||
278 | |||
279 | #if LPS22HB_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION | ||
280 | #error "LPS22HB_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" | ||
281 | #endif | ||
282 | |||
283 | /* | ||
284 | * CHTODO: Add support for LPS22HB over SPI. | ||
285 | */ | ||
286 | #if LPS22HB_USE_SPI | ||
287 | #error "LPS22HB over SPI still not supported" | ||
288 | #endif | ||
289 | |||
290 | /*===========================================================================*/ | ||
291 | /* Driver data structures and types. */ | ||
292 | /*===========================================================================*/ | ||
293 | |||
294 | /** | ||
295 | * @name LPS22HB data structures and types. | ||
296 | * @{ | ||
297 | */ | ||
298 | /** | ||
299 | * @brief Structure representing a LPS22HB driver. | ||
300 | */ | ||
301 | typedef struct LPS22HBDriver LPS22HBDriver; | ||
302 | |||
303 | /** | ||
304 | * @brief LPS22HB slave address | ||
305 | */ | ||
306 | typedef enum { | ||
307 | LPS22HB_SAD_GND = 0x5C, /**< Slave Address when SA0 is to GND */ | ||
308 | LPS22HB_SAD_VCC = 0x5D /**< Slave Address when SA0 is to VCC */ | ||
309 | }lps22hb_sad_t; | ||
310 | |||
311 | /** | ||
312 | * @brief LPS22HB output data rate and bandwidth. | ||
313 | */ | ||
314 | typedef enum { | ||
315 | LPS22HB_ODR_PD = 0x00, /**< Power down. */ | ||
316 | LPS22HB_ODR_1HZ = 0x10, /**< Output data rate 1 Hz. */ | ||
317 | LPS22HB_ODR_10HZ = 0x20, /**< Output data rate 10 Hz. */ | ||
318 | LPS22HB_ODR_25HZ = 0x30, /**< Output data rate 25 Hz. */ | ||
319 | LPS22HB_ODR_50HZ = 0x40, /**< Output data rate 50 Hz. */ | ||
320 | LPS22HB_ODR_75HZ = 0x50 /**< Output data rate 75 Hz. */ | ||
321 | }lps22hb_odr_t; | ||
322 | |||
323 | /** | ||
324 | * @brief LPS22HB pressure resolution. | ||
325 | */ | ||
326 | typedef enum { | ||
327 | LPS22HB_LP_DISABLED = 0x00, /**< LP Filter disabled. */ | ||
328 | LPS22HB_LP_ODR_9 = 0x08, /**< LP Filter enabled. Cut-off ORD/9. */ | ||
329 | LPS22HB_LP_ODR_20 = 0x0C /**< LP Filter enabled. Cut-off ORD/20. */ | ||
330 | }lps22hb_lp_t; | ||
331 | |||
332 | /** | ||
333 | * @brief LPS22HB block data update. | ||
334 | */ | ||
335 | typedef enum { | ||
336 | LPS22HB_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ | ||
337 | LPS22HB_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ | ||
338 | }lps22hb_bdu_t; | ||
339 | |||
340 | /** | ||
341 | * @brief Driver state machine possible states. | ||
342 | */ | ||
343 | typedef enum { | ||
344 | LPS22HB_UNINIT = 0, /**< Not initialized. */ | ||
345 | LPS22HB_STOP = 1, /**< Stopped. */ | ||
346 | LPS22HB_READY = 2, /**< Ready. */ | ||
347 | } lps22hb_state_t; | ||
348 | |||
349 | /** | ||
350 | * @brief LPS22HB configuration structure. | ||
351 | */ | ||
352 | typedef struct { | ||
353 | |||
354 | #if LPS22HB_USE_SPI || defined(__DOXYGEN__) | ||
355 | /** | ||
356 | * @brief SPI driver associated to this LPS22HB. | ||
357 | */ | ||
358 | SPIDriver *spip; | ||
359 | /** | ||
360 | * @brief SPI configuration associated to this LPS22HB. | ||
361 | */ | ||
362 | const SPIConfig *spicfg; | ||
363 | #endif /* LPS22HB_USE_SPI */ | ||
364 | #if LPS22HB_USE_I2C || defined(__DOXYGEN__) | ||
365 | /** | ||
366 | * @brief I2C driver associated to this LPS22HB. | ||
367 | */ | ||
368 | I2CDriver *i2cp; | ||
369 | /** | ||
370 | * @brief I2C configuration associated to this LPS22HB. | ||
371 | */ | ||
372 | const I2CConfig *i2ccfg; | ||
373 | /** | ||
374 | * @brief LPS22HB slave address | ||
375 | */ | ||
376 | lps22hb_sad_t slaveaddress; | ||
377 | #endif /* LPS22HB_USE_I2C */ | ||
378 | /** | ||
379 | * @brief LPS22HB barometer subsystem initial sensitivity. | ||
380 | */ | ||
381 | float *barosensitivity; | ||
382 | /** | ||
383 | * @brief LPS22HB barometer subsystem initial bias. | ||
384 | */ | ||
385 | float *barobias; | ||
386 | /** | ||
387 | * @brief LPS22HB thermometer subsystem initial sensitivity. | ||
388 | */ | ||
389 | float *thermosensitivity; | ||
390 | /** | ||
391 | * @brief LPS22HB thermometer subsystem initial bias. | ||
392 | */ | ||
393 | float *thermobias; | ||
394 | /** | ||
395 | * @brief LPS22HB output data rate selection. | ||
396 | */ | ||
397 | lps22hb_odr_t outputdatarate; | ||
398 | #if LPS22HB_USE_ADVANCED || defined(__DOXYGEN__) | ||
399 | /** | ||
400 | * @brief LPS22HB block data update. | ||
401 | */ | ||
402 | lps22hb_bdu_t blockdataupdate; | ||
403 | /** | ||
404 | * @brief LPS22HB barometer subsystem resolution. | ||
405 | */ | ||
406 | lps22hb_lp_t lowpass_filter; | ||
407 | #endif | ||
408 | } LPS22HBConfig; | ||
409 | |||
410 | /** | ||
411 | * @brief @p LPS22HB specific methods. | ||
412 | * @note No methods so far, just a common ancestor interface. | ||
413 | */ | ||
414 | #define _lps22hb_methods_alone | ||
415 | |||
416 | /** | ||
417 | * @brief @p LPS22HB specific methods with inherited ones. | ||
418 | */ | ||
419 | #define _lps22hb_methods \ | ||
420 | _base_object_methods \ | ||
421 | _lps22hb_methods_alone | ||
422 | |||
423 | /** | ||
424 | * @extends BaseObjectVMT | ||
425 | * | ||
426 | * @brief @p LPS22HB virtual methods table. | ||
427 | */ | ||
428 | struct LPS22HBVMT { | ||
429 | _lps22hb_methods | ||
430 | }; | ||
431 | |||
432 | /** | ||
433 | * @brief @p LPS22HBDriver specific data. | ||
434 | */ | ||
435 | #define _lps22hb_data \ | ||
436 | /* Driver state.*/ \ | ||
437 | lps22hb_state_t state; \ | ||
438 | /* Current configuration data.*/ \ | ||
439 | const LPS22HBConfig *config; \ | ||
440 | /* Barometer subsystem axes number.*/ \ | ||
441 | size_t baroaxes; \ | ||
442 | /* Barometer subsystem current sensitivity.*/ \ | ||
443 | float barosensitivity; \ | ||
444 | /* Barometer subsystem current bias .*/ \ | ||
445 | float barobias; \ | ||
446 | /* Thermometer subsystem axes number.*/ \ | ||
447 | size_t thermoaxes; \ | ||
448 | /* Thermometer subsystem current sensitivity.*/ \ | ||
449 | float thermosensitivity; \ | ||
450 | /* Thermometer subsystem current bias.*/ \ | ||
451 | float thermobias; | ||
452 | |||
453 | /** | ||
454 | * @brief LPS22HB 2-axis barometer/thermometer class. | ||
455 | */ | ||
456 | struct LPS22HBDriver { | ||
457 | /** @brief Virtual Methods Table.*/ | ||
458 | const struct LPS22HBVMT *vmt; | ||
459 | /** @brief Base barometer interface.*/ | ||
460 | BaseBarometer baro_if; | ||
461 | /** @brief Base thermometer interface.*/ | ||
462 | BaseThermometer thermo_if; | ||
463 | _lps22hb_data | ||
464 | }; | ||
465 | /** @} */ | ||
466 | |||
467 | /*===========================================================================*/ | ||
468 | /* Driver macros. */ | ||
469 | /*===========================================================================*/ | ||
470 | |||
471 | /** | ||
472 | * @brief Return the number of axes of the BaseBarometer. | ||
473 | * | ||
474 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
475 | * | ||
476 | * @return the number of axes. | ||
477 | * | ||
478 | * @api | ||
479 | */ | ||
480 | #define lps22hbBarometerGetAxesNumber(devp) \ | ||
481 | barometerGetAxesNumber(&((devp)->baro_if)) | ||
482 | |||
483 | /** | ||
484 | * @brief Retrieves raw data from the BaseBarometer. | ||
485 | * @note This data is retrieved from MEMS register without any algebraical | ||
486 | * manipulation. | ||
487 | * @note The axes array must be at least the same size of the | ||
488 | * BaseBarometer axes number. | ||
489 | * | ||
490 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
491 | * @param[out] axes a buffer which would be filled with raw data. | ||
492 | * | ||
493 | * @return The operation status. | ||
494 | * @retval MSG_OK if the function succeeded. | ||
495 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
496 | * be retrieved using @p i2cGetErrors(). | ||
497 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
498 | * | ||
499 | * @api | ||
500 | */ | ||
501 | #define lps22hbBarometerReadRaw(devp, axes) \ | ||
502 | barometerReadRaw(&((devp)->baro_if), axes) | ||
503 | |||
504 | /** | ||
505 | * @brief Retrieves cooked data from the BaseBarometer. | ||
506 | * @note This data is manipulated according to the formula | ||
507 | * cooked = (raw * sensitivity) - bias. | ||
508 | * @note Final data is expressed as hPa. | ||
509 | * @note The axes array must be at least the same size of the | ||
510 | * BaseBarometer axes number. | ||
511 | * | ||
512 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
513 | * @param[out] axes a buffer which would be filled with cooked data. | ||
514 | * | ||
515 | * @return The operation status. | ||
516 | * @retval MSG_OK if the function succeeded. | ||
517 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
518 | * be retrieved using @p i2cGetErrors(). | ||
519 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
520 | * | ||
521 | * @api | ||
522 | */ | ||
523 | #define lps22hbBarometerReadCooked(devp, axes) \ | ||
524 | barometerReadCooked(&((devp)->baro_if), axes) | ||
525 | |||
526 | /** | ||
527 | * @brief Set bias values for the BaseBarometer. | ||
528 | * @note Bias must be expressed as hPa. | ||
529 | * @note The bias buffer must be at least the same size of the | ||
530 | * BaseBarometer axes number. | ||
531 | * | ||
532 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
533 | * @param[in] bp a buffer which contains biases. | ||
534 | * | ||
535 | * @return The operation status. | ||
536 | * @retval MSG_OK if the function succeeded. | ||
537 | * | ||
538 | * @api | ||
539 | */ | ||
540 | #define lps22hbBarometerSetBias(devp, bp) \ | ||
541 | barometerSetBias(&((devp)->baro_if), bp) | ||
542 | |||
543 | /** | ||
544 | * @brief Reset bias values for the BaseBarometer. | ||
545 | * @note Default biases value are obtained from device datasheet when | ||
546 | * available otherwise they are considered zero. | ||
547 | * | ||
548 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
549 | * | ||
550 | * @return The operation status. | ||
551 | * @retval MSG_OK if the function succeeded. | ||
552 | * | ||
553 | * @api | ||
554 | */ | ||
555 | #define lps22hbBarometerResetBias(devp) \ | ||
556 | barometerResetBias(&((devp)->baro_if)) | ||
557 | |||
558 | /** | ||
559 | * @brief Set sensitivity values for the BaseBarometer. | ||
560 | * @note Sensitivity must be expressed as hPa/LSB. | ||
561 | * @note The sensitivity buffer must be at least the same size of the | ||
562 | * BaseBarometer axes number. | ||
563 | * | ||
564 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
565 | * @param[in] sp a buffer which contains sensitivities. | ||
566 | * | ||
567 | * @return The operation status. | ||
568 | * @retval MSG_OK if the function succeeded. | ||
569 | * | ||
570 | * @api | ||
571 | */ | ||
572 | #define lps22hbBarometerSetSensitivity(devp, sp) \ | ||
573 | barometerSetSensitivity(&((devp)->baro_if), sp) | ||
574 | |||
575 | /** | ||
576 | * @brief Reset sensitivity values for the BaseBarometer. | ||
577 | * @note Default sensitivities value are obtained from device datasheet. | ||
578 | * | ||
579 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
580 | * | ||
581 | * @return The operation status. | ||
582 | * @retval MSG_OK if the function succeeded. | ||
583 | * | ||
584 | * @api | ||
585 | */ | ||
586 | #define lps22hbBarometerResetSensitivity(devp) \ | ||
587 | barometerResetSensitivity(&((devp)->baro_if)) | ||
588 | |||
589 | /** | ||
590 | * @brief Return the number of axes of the BaseThermometer. | ||
591 | * | ||
592 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
593 | * | ||
594 | * @return the number of axes. | ||
595 | * | ||
596 | * @api | ||
597 | */ | ||
598 | #define lps22hbThermometerGetAxesNumber(devp) \ | ||
599 | thermometerGetAxesNumber(&((devp)->thermo_if)) | ||
600 | |||
601 | /** | ||
602 | * @brief Retrieves raw data from the BaseThermometer. | ||
603 | * @note This data is retrieved from MEMS register without any algebraical | ||
604 | * manipulation. | ||
605 | * @note The axes array must be at least the same size of the | ||
606 | * BaseThermometer axes number. | ||
607 | * | ||
608 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
609 | * @param[out] axes a buffer which would be filled with raw data. | ||
610 | * | ||
611 | * @return The operation status. | ||
612 | * @retval MSG_OK if the function succeeded. | ||
613 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
614 | * be retrieved using @p i2cGetErrors(). | ||
615 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
616 | * | ||
617 | * @api | ||
618 | */ | ||
619 | #define lps22hbThermometerReadRaw(devp, axes) \ | ||
620 | thermometerReadRaw(&((devp)->thermo_if), axes) | ||
621 | |||
622 | /** | ||
623 | * @brief Retrieves cooked data from the BaseThermometer. | ||
624 | * @note This data is manipulated according to the formula | ||
625 | * cooked = (raw * sensitivity) - bias. | ||
626 | * @note Final data is expressed as °C. | ||
627 | * @note The axes array must be at least the same size of the | ||
628 | * BaseThermometer axes number. | ||
629 | * | ||
630 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
631 | * @param[out] axes a buffer which would be filled with cooked data. | ||
632 | * | ||
633 | * @return The operation status. | ||
634 | * @retval MSG_OK if the function succeeded. | ||
635 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
636 | * be retrieved using @p i2cGetErrors(). | ||
637 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
638 | * | ||
639 | * @api | ||
640 | */ | ||
641 | #define lps22hbThermometerReadCooked(devp, axes) \ | ||
642 | thermometerReadCooked(&((devp)->thermo_if), axes) | ||
643 | |||
644 | /** | ||
645 | * @brief Set bias values for the BaseThermometer. | ||
646 | * @note Bias must be expressed as °C. | ||
647 | * @note The bias buffer must be at least the same size of the | ||
648 | * BaseThermometer axes number. | ||
649 | * | ||
650 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
651 | * @param[in] bp a buffer which contains biases. | ||
652 | * | ||
653 | * @return The operation status. | ||
654 | * @retval MSG_OK if the function succeeded. | ||
655 | * | ||
656 | * @api | ||
657 | */ | ||
658 | #define lps22hbThermometerSetBias(devp, bp) \ | ||
659 | thermometerSetBias(&((devp)->thermo_if), bp) | ||
660 | |||
661 | /** | ||
662 | * @brief Reset bias values for the BaseThermometer. | ||
663 | * @note Default biases value are obtained from device datasheet when | ||
664 | * available otherwise they are considered zero. | ||
665 | * | ||
666 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
667 | * | ||
668 | * @return The operation status. | ||
669 | * @retval MSG_OK if the function succeeded. | ||
670 | * | ||
671 | * @api | ||
672 | */ | ||
673 | #define lps22hbThermometerResetBias(devp) \ | ||
674 | thermometerResetBias(&((devp)->thermo_if)) | ||
675 | |||
676 | /** | ||
677 | * @brief Set sensitivity values for the BaseThermometer. | ||
678 | * @note Sensitivity must be expressed as °C/LSB. | ||
679 | * @note The sensitivity buffer must be at least the same size of the | ||
680 | * BaseThermometer axes number. | ||
681 | * | ||
682 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
683 | * @param[in] sp a buffer which contains sensitivities. | ||
684 | * | ||
685 | * @return The operation status. | ||
686 | * @retval MSG_OK if the function succeeded. | ||
687 | * | ||
688 | * @api | ||
689 | */ | ||
690 | #define lps22hbThermometerSetSensitivity(devp, sp) \ | ||
691 | thermometerSetSensitivity(&((devp)->thermo_if), sp) | ||
692 | |||
693 | /** | ||
694 | * @brief Reset sensitivity values for the BaseThermometer. | ||
695 | * @note Default sensitivities value are obtained from device datasheet. | ||
696 | * | ||
697 | * @param[in] devp pointer to @p LPS22HBDriver. | ||
698 | * | ||
699 | * @return The operation status. | ||
700 | * @retval MSG_OK if the function succeeded. | ||
701 | * | ||
702 | * @api | ||
703 | */ | ||
704 | #define lps22hbThermometerResetSensitivity(devp) \ | ||
705 | thermometerResetSensitivity(&((devp)->thermo_if)) | ||
706 | |||
707 | /*===========================================================================*/ | ||
708 | /* External declarations. */ | ||
709 | /*===========================================================================*/ | ||
710 | |||
711 | #ifdef __cplusplus | ||
712 | extern "C" { | ||
713 | #endif | ||
714 | void lps22hbObjectInit(LPS22HBDriver *devp); | ||
715 | void lps22hbStart(LPS22HBDriver *devp, const LPS22HBConfig *config); | ||
716 | void lps22hbStop(LPS22HBDriver *devp); | ||
717 | #ifdef __cplusplus | ||
718 | } | ||
719 | #endif | ||
720 | |||
721 | #endif /* _LPS22HB_H_ */ | ||
722 | |||
723 | /** @} */ | ||
724 | |||
diff --git a/lib/chibios/os/ex/devices/ST/lps22hb.mk b/lib/chibios/os/ex/devices/ST/lps22hb.mk new file mode 100644 index 000000000..7dde418d0 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lps22hb.mk | |||
@@ -0,0 +1,10 @@ | |||
1 | # List of all the LPS22HB device files. | ||
2 | LPS22HBSRC := $(CHIBIOS)/os/ex/devices/ST/lps22hb.c | ||
3 | |||
4 | # Required include directories | ||
5 | LPS22HBINC := $(CHIBIOS)/os/ex/include \ | ||
6 | $(CHIBIOS)/os/ex/devices/ST | ||
7 | |||
8 | # Shared variables | ||
9 | ALLCSRC += $(LPS22HBSRC) | ||
10 | ALLINC += $(LPS22HBINC) \ No newline at end of file | ||
diff --git a/lib/chibios/os/ex/devices/ST/lps25h.c b/lib/chibios/os/ex/devices/ST/lps25h.c new file mode 100644 index 000000000..80dbe241c --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lps25h.c | |||
@@ -0,0 +1,696 @@ | |||
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 lps25h.c | ||
23 | * @brief LPS25H MEMS interface module code. | ||
24 | * | ||
25 | * @addtogroup LPS25H | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #include "hal.h" | ||
31 | #include "lps25h.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 (LPS25H_USE_I2C) || defined(__DOXYGEN__) | ||
50 | /** | ||
51 | * @brief Reads registers value using I2C. | ||
52 | * @pre The I2C interface must be initialized and the driver started. | ||
53 | * | ||
54 | * @param[in] i2cp pointer to the I2C interface | ||
55 | * @param[in] sad slave address without R bit | ||
56 | * @param[in] reg first sub-register address | ||
57 | * @param[out] rxbuf pointer to an output buffer | ||
58 | * @param[in] n number of consecutive register to read | ||
59 | * @return the operation status. | ||
60 | * | ||
61 | * @notapi | ||
62 | */ | ||
63 | static msg_t lps25hI2CReadRegister(I2CDriver *i2cp, lps25h_sad_t sad, | ||
64 | uint8_t reg, uint8_t* rxbuf, size_t n) { | ||
65 | uint8_t txbuf = reg; | ||
66 | if(n > 1) | ||
67 | txbuf |= LPS25H_SUB_MS; | ||
68 | |||
69 | return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, | ||
70 | TIME_INFINITE); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * @brief Writes a value into a register using I2C. | ||
75 | * @pre The I2C interface must be initialized and the driver started. | ||
76 | * | ||
77 | * @param[in] i2cp pointer to the I2C interface | ||
78 | * @param[in] sad slave address without R bit | ||
79 | * @param[in] txbuf buffer containing sub-address value in first position | ||
80 | * and values to write | ||
81 | * @param[in] n size of txbuf less one (not considering the first | ||
82 | * element) | ||
83 | * @return the operation status. | ||
84 | * | ||
85 | * @notapi | ||
86 | */ | ||
87 | static msg_t lps25hI2CWriteRegister(I2CDriver *i2cp, lps25h_sad_t sad, | ||
88 | uint8_t* txbuf, size_t n) { | ||
89 | if (n > 1) | ||
90 | (*txbuf) |= LPS25H_SUB_MS; | ||
91 | return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, | ||
92 | TIME_INFINITE); | ||
93 | } | ||
94 | #endif /* LPS25H_USE_I2C */ | ||
95 | |||
96 | /** | ||
97 | * @brief Return the number of axes of the BaseBarometer. | ||
98 | * | ||
99 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
100 | * | ||
101 | * @return the number of axes. | ||
102 | */ | ||
103 | static size_t baro_get_axes_number(void *ip) { | ||
104 | (void)ip; | ||
105 | |||
106 | return LPS25H_BARO_NUMBER_OF_AXES; | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * @brief Retrieves raw data from the BaseBarometer. | ||
111 | * @note This data is retrieved from MEMS register without any algebraical | ||
112 | * manipulation. | ||
113 | * @note The axes array must be at least the same size of the | ||
114 | * BaseBarometer axes number. | ||
115 | * | ||
116 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
117 | * @param[out] axes a buffer which would be filled with raw data. | ||
118 | * | ||
119 | * @return The operation status. | ||
120 | * @retval MSG_OK if the function succeeded. | ||
121 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
122 | * be retrieved using @p i2cGetErrors(). | ||
123 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
124 | */ | ||
125 | static msg_t baro_read_raw(void *ip, int32_t axes[]) { | ||
126 | LPS25HDriver* devp; | ||
127 | uint8_t buff[3]; | ||
128 | msg_t msg; | ||
129 | |||
130 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
131 | |||
132 | /* Getting parent instance pointer.*/ | ||
133 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
134 | |||
135 | osalDbgAssert((devp->state == LPS25H_READY), | ||
136 | "baro_read_raw(), invalid state"); | ||
137 | |||
138 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
139 | "baro_read_raw(), channel not ready"); | ||
140 | |||
141 | #if LPS25H_SHARED_I2C | ||
142 | i2cAcquireBus(devp->config->i2cp); | ||
143 | i2cStart(devp->config->i2cp, | ||
144 | devp->config->i2ccfg); | ||
145 | #endif /* LPS25H_SHARED_I2C */ | ||
146 | |||
147 | msg = lps25hI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
148 | LPS25H_AD_PRESS_OUT_XL, buff, 3); | ||
149 | |||
150 | #if LPS25H_SHARED_I2C | ||
151 | i2cReleaseBus(devp->config->i2cp); | ||
152 | #endif /* LPS25H_SHARED_I2C */ | ||
153 | |||
154 | if(msg == MSG_OK) { | ||
155 | *axes = buff[0] + (buff[1] << 8) + (buff[2] << 16); | ||
156 | } | ||
157 | return msg; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * @brief Retrieves cooked data from the BaseBarometer. | ||
162 | * @note This data is manipulated according to the formula | ||
163 | * cooked = (raw * sensitivity) - bias. | ||
164 | * @note Final data is expressed as hPa. | ||
165 | * @note The axes array must be at least the same size of the | ||
166 | * BaseBarometer axes number. | ||
167 | * | ||
168 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
169 | * @param[out] axes a buffer which would be filled with cooked data. | ||
170 | * | ||
171 | * @return The operation status. | ||
172 | * @retval MSG_OK if the function succeeded. | ||
173 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
174 | * be retrieved using @p i2cGetErrors(). | ||
175 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
176 | */ | ||
177 | static msg_t baro_read_cooked(void *ip, float axes[]) { | ||
178 | LPS25HDriver* devp; | ||
179 | int32_t raw; | ||
180 | msg_t msg; | ||
181 | |||
182 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
183 | |||
184 | /* Getting parent instance pointer.*/ | ||
185 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
186 | |||
187 | osalDbgAssert((devp->state == LPS25H_READY), | ||
188 | "baro_read_cooked(), invalid state"); | ||
189 | |||
190 | msg = baro_read_raw(ip, &raw); | ||
191 | |||
192 | *axes = (raw * devp->barosensitivity) - devp->barobias; | ||
193 | |||
194 | return msg; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * @brief Set bias values for the BaseBarometer. | ||
199 | * @note Bias must be expressed as hPa. | ||
200 | * @note The bias buffer must be at least the same size of the | ||
201 | * BaseBarometer axes number. | ||
202 | * | ||
203 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
204 | * @param[in] bp a buffer which contains biases. | ||
205 | * | ||
206 | * @return The operation status. | ||
207 | * @retval MSG_OK if the function succeeded. | ||
208 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
209 | * be retrieved using @p i2cGetErrors(). | ||
210 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
211 | */ | ||
212 | static msg_t baro_set_bias(void *ip, float *bp) { | ||
213 | LPS25HDriver* devp; | ||
214 | msg_t msg = MSG_OK; | ||
215 | |||
216 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
217 | |||
218 | /* Getting parent instance pointer.*/ | ||
219 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
220 | |||
221 | osalDbgAssert((devp->state == LPS25H_READY), | ||
222 | "baro_set_bias(), invalid state"); | ||
223 | |||
224 | devp->barobias = *bp; | ||
225 | return msg; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * @brief Reset bias values for the BaseBarometer. | ||
230 | * @note Default biases value are obtained from device datasheet when | ||
231 | * available otherwise they are considered zero. | ||
232 | * | ||
233 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
234 | * | ||
235 | * @return The operation status. | ||
236 | * @retval MSG_OK if the function succeeded. | ||
237 | */ | ||
238 | static msg_t baro_reset_bias(void *ip) { | ||
239 | LPS25HDriver* devp; | ||
240 | msg_t msg = MSG_OK; | ||
241 | |||
242 | osalDbgCheck(ip != NULL); | ||
243 | |||
244 | /* Getting parent instance pointer.*/ | ||
245 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
246 | |||
247 | osalDbgAssert((devp->state == LPS25H_READY), | ||
248 | "baro_reset_bias(), invalid state"); | ||
249 | |||
250 | devp->barobias = LPS25H_BARO_SENS; | ||
251 | return msg; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * @brief Set sensitivity values for the BaseBarometer. | ||
256 | * @note Sensitivity must be expressed as hPa/LSB. | ||
257 | * @note The sensitivity buffer must be at least the same size of the | ||
258 | * BaseBarometer axes number. | ||
259 | * | ||
260 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
261 | * @param[in] sp a buffer which contains sensitivities. | ||
262 | * | ||
263 | * @return The operation status. | ||
264 | * @retval MSG_OK if the function succeeded. | ||
265 | */ | ||
266 | static msg_t baro_set_sensitivity(void *ip, float *sp) { | ||
267 | LPS25HDriver* devp; | ||
268 | msg_t msg = MSG_OK; | ||
269 | |||
270 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
271 | |||
272 | /* Getting parent instance pointer.*/ | ||
273 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
274 | |||
275 | osalDbgAssert((devp->state == LPS25H_READY), | ||
276 | "baro_set_sensitivity(), invalid state"); | ||
277 | |||
278 | devp->barosensitivity = *sp; | ||
279 | return msg; | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * @brief Reset sensitivity values for the BaseBarometer. | ||
284 | * @note Default sensitivities value are obtained from device datasheet. | ||
285 | * | ||
286 | * @param[in] ip pointer to @p BaseBarometer interface. | ||
287 | * | ||
288 | * @return The operation status. | ||
289 | * @retval MSG_OK if the function succeeded. | ||
290 | */ | ||
291 | static msg_t baro_reset_sensitivity(void *ip) { | ||
292 | LPS25HDriver* devp; | ||
293 | msg_t msg = MSG_OK; | ||
294 | |||
295 | osalDbgCheck(ip != NULL); | ||
296 | |||
297 | /* Getting parent instance pointer.*/ | ||
298 | devp = objGetInstance(LPS25HDriver*, (BaseBarometer*)ip); | ||
299 | |||
300 | osalDbgAssert((devp->state == LPS25H_READY), | ||
301 | "baro_reset_sensitivity(), invalid state"); | ||
302 | |||
303 | devp->barosensitivity = LPS25H_BARO_SENS; | ||
304 | return msg; | ||
305 | } | ||
306 | |||
307 | /** | ||
308 | * @brief Return the number of axes of the BaseThermometer. | ||
309 | * | ||
310 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
311 | * | ||
312 | * @return the number of axes. | ||
313 | */ | ||
314 | static size_t thermo_get_axes_number(void *ip) { | ||
315 | (void)ip; | ||
316 | |||
317 | return LPS25H_THERMO_NUMBER_OF_AXES; | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * @brief Retrieves raw data from the BaseThermometer. | ||
322 | * @note This data is retrieved from MEMS register without any algebraical | ||
323 | * manipulation. | ||
324 | * @note The axes array must be at least the same size of the | ||
325 | * BaseThermometer axes number. | ||
326 | * | ||
327 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
328 | * @param[out] axes a buffer which would be filled with raw data. | ||
329 | * | ||
330 | * @return The operation status. | ||
331 | * @retval MSG_OK if the function succeeded. | ||
332 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
333 | * be retrieved using @p i2cGetErrors(). | ||
334 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
335 | */ | ||
336 | static msg_t thermo_read_raw(void *ip, int32_t axes[]) { | ||
337 | LPS25HDriver* devp; | ||
338 | int16_t tmp; | ||
339 | uint8_t buff[2]; | ||
340 | msg_t msg; | ||
341 | |||
342 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
343 | |||
344 | /* Getting parent instance pointer.*/ | ||
345 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
346 | |||
347 | osalDbgAssert((devp->state == LPS25H_READY), | ||
348 | "thermo_read_raw(), invalid state"); | ||
349 | |||
350 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
351 | "thermo_read_raw(), channel not ready"); | ||
352 | |||
353 | #if LPS25H_SHARED_I2C | ||
354 | i2cAcquireBus(devp->config->i2cp); | ||
355 | i2cStart(devp->config->i2cp, | ||
356 | devp->config->i2ccfg); | ||
357 | #endif /* LPS25H_SHARED_I2C */ | ||
358 | |||
359 | msg = lps25hI2CReadRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
360 | LPS25H_AD_TEMP_OUT_L, buff, 2); | ||
361 | |||
362 | #if LPS25H_SHARED_I2C | ||
363 | i2cReleaseBus(devp->config->i2cp); | ||
364 | #endif /* LPS25H_SHARED_I2C */ | ||
365 | |||
366 | if (msg == MSG_OK) { | ||
367 | tmp = buff[0] + (buff[1] << 8); | ||
368 | *axes = (int32_t)tmp; | ||
369 | } | ||
370 | return msg; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * @brief Retrieves cooked data from the BaseThermometer. | ||
375 | * @note This data is manipulated according to the formula | ||
376 | * cooked = (raw * sensitivity) - bias. | ||
377 | * @note Final data is expressed as °C. | ||
378 | * @note The axes array must be at least the same size of the | ||
379 | * BaseThermometer axes number. | ||
380 | * | ||
381 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
382 | * @param[out] axis a buffer which would be filled with cooked data. | ||
383 | * | ||
384 | * @return The operation status. | ||
385 | * @retval MSG_OK if the function succeeded. | ||
386 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
387 | * be retrieved using @p i2cGetErrors(). | ||
388 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
389 | */ | ||
390 | static msg_t thermo_read_cooked(void *ip, float* axis) { | ||
391 | LPS25HDriver* devp; | ||
392 | int32_t raw; | ||
393 | msg_t msg; | ||
394 | |||
395 | osalDbgCheck((ip != NULL) && (axis != NULL)); | ||
396 | |||
397 | /* Getting parent instance pointer.*/ | ||
398 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
399 | |||
400 | osalDbgAssert((devp->state == LPS25H_READY), | ||
401 | "thermo_read_cooked(), invalid state"); | ||
402 | |||
403 | msg = thermo_read_raw(devp, &raw); | ||
404 | |||
405 | *axis = (raw * devp->thermosensitivity) - devp->thermobias; | ||
406 | |||
407 | return msg; | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * @brief Set bias values for the BaseThermometer. | ||
412 | * @note Bias must be expressed as °C. | ||
413 | * @note The bias buffer must be at least the same size of the | ||
414 | * BaseThermometer axes number. | ||
415 | * | ||
416 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
417 | * @param[in] bp a buffer which contains biases. | ||
418 | * | ||
419 | * @return The operation status. | ||
420 | * @retval MSG_OK if the function succeeded. | ||
421 | */ | ||
422 | static msg_t thermo_set_bias(void *ip, float *bp) { | ||
423 | LPS25HDriver* devp; | ||
424 | msg_t msg = MSG_OK; | ||
425 | |||
426 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
427 | |||
428 | /* Getting parent instance pointer.*/ | ||
429 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
430 | |||
431 | osalDbgAssert((devp->state == LPS25H_READY), | ||
432 | "thermo_set_bias(), invalid state"); | ||
433 | |||
434 | devp->thermobias = *bp; | ||
435 | |||
436 | return msg; | ||
437 | } | ||
438 | |||
439 | /** | ||
440 | * @brief Reset bias values for the BaseThermometer. | ||
441 | * @note Default biases value are obtained from device datasheet when | ||
442 | * available otherwise they are considered zero. | ||
443 | * | ||
444 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
445 | * | ||
446 | * @return The operation status. | ||
447 | * @retval MSG_OK if the function succeeded. | ||
448 | */ | ||
449 | static msg_t thermo_reset_bias(void *ip) { | ||
450 | LPS25HDriver* devp; | ||
451 | msg_t msg = MSG_OK; | ||
452 | |||
453 | osalDbgCheck(ip != NULL); | ||
454 | |||
455 | /* Getting parent instance pointer.*/ | ||
456 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
457 | |||
458 | osalDbgAssert((devp->state == LPS25H_READY), | ||
459 | "thermo_reset_bias(), invalid state"); | ||
460 | |||
461 | devp->thermobias = LPS25H_THERMO_BIAS; | ||
462 | |||
463 | return msg; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * @brief Set sensitivity values for the BaseThermometer. | ||
468 | * @note Sensitivity must be expressed as °C/LSB. | ||
469 | * @note The sensitivity buffer must be at least the same size of the | ||
470 | * BaseThermometer axes number. | ||
471 | * | ||
472 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
473 | * @param[in] sp a buffer which contains sensitivities. | ||
474 | * | ||
475 | * @return The operation status. | ||
476 | * @retval MSG_OK if the function succeeded. | ||
477 | */ | ||
478 | static msg_t thermo_set_sensitivity(void *ip, float *sp) { | ||
479 | LPS25HDriver* devp; | ||
480 | msg_t msg = MSG_OK; | ||
481 | |||
482 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
483 | |||
484 | /* Getting parent instance pointer.*/ | ||
485 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
486 | |||
487 | osalDbgAssert((devp->state == LPS25H_READY), | ||
488 | "thermo_set_sensitivity(), invalid state"); | ||
489 | |||
490 | devp->thermosensitivity = *sp; | ||
491 | |||
492 | return msg; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * @brief Reset sensitivity values for the BaseThermometer. | ||
497 | * @note Default sensitivities value are obtained from device datasheet. | ||
498 | * | ||
499 | * @param[in] ip pointer to @p BaseThermometer interface. | ||
500 | * | ||
501 | * @return The operation status. | ||
502 | * @retval MSG_OK if the function succeeded. | ||
503 | */ | ||
504 | static msg_t thermo_reset_sensitivity(void *ip) { | ||
505 | LPS25HDriver* devp; | ||
506 | msg_t msg = MSG_OK; | ||
507 | |||
508 | osalDbgCheck(ip != NULL); | ||
509 | |||
510 | /* Getting parent instance pointer.*/ | ||
511 | devp = objGetInstance(LPS25HDriver*, (BaseThermometer*)ip); | ||
512 | |||
513 | osalDbgAssert((devp->state == LPS25H_READY), | ||
514 | "thermo_reset_sensitivity(), invalid state"); | ||
515 | |||
516 | devp->thermosensitivity = LPS25H_THERMO_SENS; | ||
517 | |||
518 | return msg; | ||
519 | } | ||
520 | |||
521 | static const struct LPS25HVMT vmt_device = { | ||
522 | (size_t)0 | ||
523 | }; | ||
524 | |||
525 | static const struct BaseBarometerVMT vmt_barometer = { | ||
526 | sizeof(struct LPS25HVMT*), | ||
527 | baro_get_axes_number, baro_read_raw, baro_read_cooked, | ||
528 | baro_set_bias, baro_reset_bias, baro_set_sensitivity, | ||
529 | baro_reset_sensitivity | ||
530 | }; | ||
531 | |||
532 | static const struct BaseThermometerVMT vmt_thermometer = { | ||
533 | sizeof(struct LPS25HVMT*) + sizeof(BaseBarometer), | ||
534 | thermo_get_axes_number, thermo_read_raw, thermo_read_cooked, | ||
535 | thermo_set_bias, thermo_reset_bias, thermo_set_sensitivity, | ||
536 | thermo_reset_sensitivity | ||
537 | }; | ||
538 | |||
539 | /*===========================================================================*/ | ||
540 | /* Driver exported functions. */ | ||
541 | /*===========================================================================*/ | ||
542 | |||
543 | /** | ||
544 | * @brief Initializes an instance. | ||
545 | * | ||
546 | * @param[out] devp pointer to the @p LPS25HDriver object | ||
547 | * | ||
548 | * @init | ||
549 | */ | ||
550 | void lps25hObjectInit(LPS25HDriver *devp) { | ||
551 | |||
552 | devp->vmt = &vmt_device; | ||
553 | devp->baro_if.vmt = &vmt_barometer; | ||
554 | devp->thermo_if.vmt = &vmt_thermometer; | ||
555 | |||
556 | devp->config = NULL; | ||
557 | |||
558 | devp->baroaxes = LPS25H_BARO_NUMBER_OF_AXES; | ||
559 | devp->thermoaxes = LPS25H_THERMO_NUMBER_OF_AXES; | ||
560 | |||
561 | devp->state = LPS25H_STOP; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * @brief Configures and activates LPS25H Complex Driver peripheral. | ||
566 | * | ||
567 | * @param[in] devp pointer to the @p LPS25HDriver object | ||
568 | * @param[in] config pointer to the @p LPS25HConfig object | ||
569 | * | ||
570 | * @api | ||
571 | */ | ||
572 | void lps25hStart(LPS25HDriver *devp, const LPS25HConfig *config) { | ||
573 | uint8_t cr[2]; | ||
574 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
575 | |||
576 | osalDbgAssert((devp->state == LPS25H_STOP) || (devp->state == LPS25H_READY), | ||
577 | "lps25hStart(), invalid state"); | ||
578 | |||
579 | devp->config = config; | ||
580 | |||
581 | /* Control register 1 configuration block.*/ | ||
582 | { | ||
583 | cr[0] = LPS25H_AD_CTRL_REG1; | ||
584 | cr[1] = devp->config->outputdatarate | LPS25H_CTRL_REG1_PD; | ||
585 | #if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) | ||
586 | cr[1] |= devp->config->blockdataupdate; | ||
587 | #endif | ||
588 | } | ||
589 | |||
590 | #if LPS25H_SHARED_I2C | ||
591 | i2cAcquireBus((devp)->config->i2cp); | ||
592 | #endif /* LPS25H_SHARED_I2C */ | ||
593 | i2cStart((devp)->config->i2cp, | ||
594 | (devp)->config->i2ccfg); | ||
595 | |||
596 | lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, cr, 1); | ||
597 | |||
598 | #if LPS25H_SHARED_I2C | ||
599 | i2cReleaseBus((devp)->config->i2cp); | ||
600 | #endif /* LPS25H_SHARED_I2C */ | ||
601 | |||
602 | /* Resolution configuration block.*/ | ||
603 | { | ||
604 | cr[0] = LPS25H_AD_RES_CONF; | ||
605 | cr[1] = 0x05; | ||
606 | #if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) | ||
607 | cr[1] = devp->config->baroresolution | devp->config->thermoresolution; | ||
608 | #endif | ||
609 | |||
610 | } | ||
611 | #if LPS25H_SHARED_I2C | ||
612 | i2cAcquireBus((devp)->config->i2cp); | ||
613 | i2cStart((devp)->config->i2cp, | ||
614 | (devp)->config->i2ccfg); | ||
615 | #endif /* LPS25H_SHARED_I2C */ | ||
616 | |||
617 | lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
618 | cr, 1); | ||
619 | |||
620 | #if LPS25H_SHARED_I2C | ||
621 | i2cReleaseBus((devp)->config->i2cp); | ||
622 | #endif /* LPS25H_SHARED_I2C */ | ||
623 | |||
624 | if(devp->config->barosensitivity == NULL) { | ||
625 | devp->barosensitivity = LPS25H_BARO_SENS; | ||
626 | } | ||
627 | else{ | ||
628 | /* Taking barometer sensitivity from user configurations */ | ||
629 | devp->barosensitivity = *(devp->config->barosensitivity); | ||
630 | } | ||
631 | |||
632 | if(devp->config->barobias == NULL) { | ||
633 | devp->barobias = LPS25H_BARO_BIAS; | ||
634 | } | ||
635 | else{ | ||
636 | /* Taking barometer bias from user configurations */ | ||
637 | devp->barobias = *(devp->config->barobias); | ||
638 | } | ||
639 | |||
640 | if(devp->config->thermosensitivity == NULL) { | ||
641 | devp->thermosensitivity = LPS25H_THERMO_SENS; | ||
642 | } | ||
643 | else{ | ||
644 | /* Taking thermometer sensitivity from user configurations */ | ||
645 | devp->thermosensitivity = *(devp->config->thermosensitivity); | ||
646 | } | ||
647 | |||
648 | if(devp->config->thermobias == NULL) { | ||
649 | devp->thermobias = LPS25H_THERMO_BIAS; | ||
650 | } | ||
651 | else{ | ||
652 | /* Taking thermometer bias from user configurations */ | ||
653 | devp->thermobias = *(devp->config->thermobias); | ||
654 | } | ||
655 | |||
656 | /* This is the Barometer transient recovery time */ | ||
657 | osalThreadSleepMilliseconds(5); | ||
658 | |||
659 | devp->state = LPS25H_READY; | ||
660 | } | ||
661 | |||
662 | /** | ||
663 | * @brief Deactivates the LPS25H Complex Driver peripheral. | ||
664 | * | ||
665 | * @param[in] devp pointer to the @p LPS25HDriver object | ||
666 | * | ||
667 | * @api | ||
668 | */ | ||
669 | void lps25hStop(LPS25HDriver *devp) { | ||
670 | uint8_t cr[2]; | ||
671 | |||
672 | osalDbgCheck(devp != NULL); | ||
673 | |||
674 | osalDbgAssert((devp->state == LPS25H_STOP) || (devp->state == LPS25H_READY), | ||
675 | "lps25hStop(), invalid state"); | ||
676 | |||
677 | if (devp->state == LPS25H_READY) { | ||
678 | #if LPS25H_SHARED_I2C | ||
679 | i2cAcquireBus((devp)->config->i2cp); | ||
680 | i2cStart((devp)->config->i2cp, | ||
681 | (devp)->config->i2ccfg); | ||
682 | #endif /* LPS25H_SHARED_I2C */ | ||
683 | |||
684 | cr[0] = LPS25H_AD_CTRL_REG1; | ||
685 | cr[1] = 0; | ||
686 | lps25hI2CWriteRegister(devp->config->i2cp, devp->config->slaveaddress, | ||
687 | cr, 1); | ||
688 | |||
689 | i2cStop((devp)->config->i2cp); | ||
690 | #if LPS25H_SHARED_I2C | ||
691 | i2cReleaseBus((devp)->config->i2cp); | ||
692 | #endif /* LPS25H_SHARED_I2C */ | ||
693 | } | ||
694 | devp->state = LPS25H_STOP; | ||
695 | } | ||
696 | /** @} */ | ||
diff --git a/lib/chibios/os/ex/devices/ST/lps25h.h b/lib/chibios/os/ex/devices/ST/lps25h.h new file mode 100644 index 000000000..333a97bc0 --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lps25h.h | |||
@@ -0,0 +1,740 @@ | |||
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 lps25h.h | ||
23 | * @brief LPS25H MEMS interface module header. | ||
24 | * | ||
25 | * @addtogroup LPS25H | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | #ifndef _LPS25H_H_ | ||
30 | #define _LPS25H_H_ | ||
31 | |||
32 | #include "ex_barometer.h" | ||
33 | #include "ex_thermometer.h" | ||
34 | |||
35 | /*===========================================================================*/ | ||
36 | /* Driver constants. */ | ||
37 | /*===========================================================================*/ | ||
38 | |||
39 | /** | ||
40 | * @name Version identification | ||
41 | * @{ | ||
42 | */ | ||
43 | /** | ||
44 | * @brief LPS25H driver version string. | ||
45 | */ | ||
46 | #define EX_LPS25H_VERSION "1.1.2" | ||
47 | |||
48 | /** | ||
49 | * @brief LPS25H driver version major number. | ||
50 | */ | ||
51 | #define EX_LPS25H_MAJOR 1 | ||
52 | |||
53 | /** | ||
54 | * @brief LPS25H driver version minor number. | ||
55 | */ | ||
56 | #define EX_LPS25H_MINOR 1 | ||
57 | |||
58 | /** | ||
59 | * @brief LPS25H driver version patch number. | ||
60 | */ | ||
61 | #define EX_LPS25H_PATCH 2 | ||
62 | /** @} */ | ||
63 | |||
64 | /** | ||
65 | * @brief LPS25H barometer subsystem characteristics. | ||
66 | * @note Sensitivity is expressed as hPa/LSB whereas hPa stand for | ||
67 | * hectopascal. | ||
68 | * @note Bias is expressed as hPa. | ||
69 | * | ||
70 | * @{ | ||
71 | */ | ||
72 | #define LPS25H_BARO_NUMBER_OF_AXES 1U | ||
73 | |||
74 | #define LPS25H_BARO_SENS 0.00024414f | ||
75 | #define LPS25H_BARO_BIAS 0.0f | ||
76 | /** @} */ | ||
77 | |||
78 | /** | ||
79 | * @brief LPS25H thermometer subsystem characteristics. | ||
80 | * @note Sensitivity is expressed as �C/LSB. | ||
81 | * @note Bias is expressed as �C. | ||
82 | * | ||
83 | * @{ | ||
84 | */ | ||
85 | #define LPS25H_THERMO_NUMBER_OF_AXES 1U | ||
86 | |||
87 | #define LPS25H_THERMO_SENS 0.00208333f | ||
88 | #define LPS25H_THERMO_BIAS -42.5f | ||
89 | /** @} */ | ||
90 | |||
91 | /** | ||
92 | * @name LPS25H communication interfaces related bit masks | ||
93 | * @{ | ||
94 | */ | ||
95 | #define LPS25H_DI_MASK 0xFF | ||
96 | #define LPS25H_DI(n) (1 << n) | ||
97 | #define LPS25H_AD_MASK 0x3F | ||
98 | #define LPS25H_AD(n) (1 << n) | ||
99 | #define LPS25H_MS (1 << 6) | ||
100 | #define LPS25H_RW (1 << 7) | ||
101 | |||
102 | #define LPS25H_SUB_MS (1 << 7) | ||
103 | /** @} */ | ||
104 | |||
105 | /** | ||
106 | * @name LPS25H register addresses | ||
107 | * @{ | ||
108 | */ | ||
109 | #define LPS25H_AD_REF_P_XL 0x08 | ||
110 | #define LPS25H_AD_REF_P_L 0x09 | ||
111 | #define LPS25H_AD_REF_P_H 0x0A | ||
112 | #define LPS25H_AD_WHO_AM_I 0x0F | ||
113 | #define LPS25H_AD_RES_CONF 0x10 | ||
114 | #define LPS25H_AD_CTRL_REG1 0x20 | ||
115 | #define LPS25H_AD_CTRL_REG2 0x21 | ||
116 | #define LPS25H_AD_CTRL_REG3 0x22 | ||
117 | #define LPS25H_AD_CTRL_REG4 0x23 | ||
118 | #define LPS25H_AD_INT_CFG 0x24 | ||
119 | #define LPS25H_AD_INT_SRC 0x25 | ||
120 | #define LPS25H_AD_STATUS_REG 0x27 | ||
121 | #define LPS25H_AD_PRESS_OUT_XL 0x28 | ||
122 | #define LPS25H_AD_PRESS_OUT_L 0x29 | ||
123 | #define LPS25H_AD_PRESS_OUT_H 0x2A | ||
124 | #define LPS25H_AD_TEMP_OUT_L 0x2B | ||
125 | #define LPS25H_AD_TEMP_OUT_H 0x2C | ||
126 | #define LPS25H_AD_FIFO_CTRL 0x2E | ||
127 | #define LPS25H_AD_FIFO_SRC 0x2F | ||
128 | #define LPS25H_AD_THS_P_L 0x30 | ||
129 | #define LPS25H_AD_THS_P_H 0x31 | ||
130 | #define LPS25H_AD_RPDS_L 0x39 | ||
131 | #define LPS25H_AD_RPDS_H 0x3A | ||
132 | /** @} */ | ||
133 | |||
134 | /** | ||
135 | * @name LPS25H_CTRL_REG1 register bits definitions | ||
136 | * @{ | ||
137 | */ | ||
138 | #define LPS25H_CTRL_REG1_MASK 0xFF | ||
139 | #define LPS25H_CTRL_REG1_SIM (1 << 0) | ||
140 | #define LPS25H_CTRL_REG1_RESET_AZ (1 << 1) | ||
141 | #define LPS25H_CTRL_REG1_BDU (1 << 2) | ||
142 | #define LPS25H_CTRL_REG1_DIFF_EN (1 << 3) | ||
143 | #define LPS25H_CTRL_REG1_ODR0 (1 << 4) | ||
144 | #define LPS25H_CTRL_REG1_ODR1 (1 << 5) | ||
145 | #define LPS25H_CTRL_REG1_ODR2 (1 << 6) | ||
146 | #define LPS25H_CTRL_REG1_PD (1 << 7) | ||
147 | /** @} */ | ||
148 | |||
149 | /** | ||
150 | * @name LPS25H_CTRL_REG2 register bits definitions | ||
151 | * @{ | ||
152 | */ | ||
153 | #define LPS25H_CTRL_REG2_MASK 0xF3 | ||
154 | #define LPS25H_CTRL_REG2_ONE_SHOT (1 << 0) | ||
155 | #define LPS25H_CTRL_REG2_AUTO_ZERO (1 << 1) | ||
156 | #define LPS25H_CTRL_REG2_SWRESET (1 << 2) | ||
157 | #define LPS25H_CTRL_REG2_FIFO_MEAN_DEC (1 << 4) | ||
158 | #define LPS25H_CTRL_REG2_WTM_EN (1 << 5) | ||
159 | #define LPS25H_CTRL_REG2_FIFO_EN (1 << 6) | ||
160 | #define LPS25H_CTRL_REG2_BOOT (1 << 7) | ||
161 | /** @} */ | ||
162 | |||
163 | /** | ||
164 | * @name LPS25H_CTRL_REG3 register bits definitions | ||
165 | * @{ | ||
166 | */ | ||
167 | #define LPS25H_CTRL_REG3_MASK 0xC3 | ||
168 | #define LPS25H_CTRL_REG3_INT_S1 (1 << 0) | ||
169 | #define LPS25H_CTRL_REG3_INT_S2 (1 << 1) | ||
170 | #define LPS25H_CTRL_REG3_PP_OD (1 << 6) | ||
171 | #define LPS25H_CTRL_REG3_INT_H_L (1 << 7) | ||
172 | /** @} */ | ||
173 | |||
174 | /** | ||
175 | * @name LPS25H_CTRL_REG4 register bits definitions | ||
176 | * @{ | ||
177 | */ | ||
178 | #define LPS25H_CTRL_REG4_MASK 0x0F | ||
179 | #define LPS25H_CTRL_REG4_P1_DRDY (1 << 0) | ||
180 | #define LPS25H_CTRL_REG4_P1_OVERRUN (1 << 1) | ||
181 | #define LPS25H_CTRL_REG4_P1_WTM (1 << 2) | ||
182 | #define LPS25H_CTRL_REG4_P1_EMPTY (1 << 3) | ||
183 | /** @} */ | ||
184 | |||
185 | /** | ||
186 | * @name LPS25H_INT1_CFG register bits definitions | ||
187 | * @{ | ||
188 | */ | ||
189 | #define LPS25H_INT1_CFG_MASK 0x07 | ||
190 | #define LPS25H_INT1_CFG_PH_E (1 << 0) | ||
191 | #define LPS25H_INT1_CFG_PL_E (1 << 1) | ||
192 | #define LPS25H_INT1_CFG_LIR (1 << 2) | ||
193 | /** @} */ | ||
194 | |||
195 | /** | ||
196 | * @name LPS25H_INT1_SRC register bits definitions | ||
197 | * @{ | ||
198 | */ | ||
199 | #define LPS25H_INT1_SRC_MASK 0x07 | ||
200 | #define LPS25H_INT1_SRC_PH (1 << 0) | ||
201 | #define LPS25H_INT1_SRC_PL (1 << 1) | ||
202 | #define LPS25H_INT1_SRC_IA (1 << 2) | ||
203 | /** @} */ | ||
204 | |||
205 | /*===========================================================================*/ | ||
206 | /* Driver pre-compile time settings. */ | ||
207 | /*===========================================================================*/ | ||
208 | |||
209 | /** | ||
210 | * @name Configuration options | ||
211 | * @{ | ||
212 | */ | ||
213 | /** | ||
214 | * @brief LPS25H SPI interface switch. | ||
215 | * @details If set to @p TRUE the support for SPI is included. | ||
216 | * @note The default is @p FALSE. | ||
217 | */ | ||
218 | #if !defined(LPS25H_USE_SPI) || defined(__DOXYGEN__) | ||
219 | #define LPS25H_USE_SPI FALSE | ||
220 | #endif | ||
221 | |||
222 | /** | ||
223 | * @brief LPS25H shared SPI switch. | ||
224 | * @details If set to @p TRUE the device acquires SPI bus ownership | ||
225 | * on each transaction. | ||
226 | * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION. | ||
227 | */ | ||
228 | #if !defined(LPS25H_SHARED_SPI) || defined(__DOXYGEN__) | ||
229 | #define LPS25H_SHARED_SPI FALSE | ||
230 | #endif | ||
231 | |||
232 | /** | ||
233 | * @brief LPS25H I2C interface switch. | ||
234 | * @details If set to @p TRUE the support for I2C is included. | ||
235 | * @note The default is @p TRUE. | ||
236 | */ | ||
237 | #if !defined(LPS25H_USE_I2C) || defined(__DOXYGEN__) | ||
238 | #define LPS25H_USE_I2C TRUE | ||
239 | #endif | ||
240 | |||
241 | /** | ||
242 | * @brief LPS25H shared I2C switch. | ||
243 | * @details If set to @p TRUE the device acquires I2C bus ownership | ||
244 | * on each transaction. | ||
245 | * @note The default is @p FALSE. Requires I2C_USE_MUTUAL_EXCLUSION. | ||
246 | */ | ||
247 | #if !defined(LPS25H_SHARED_I2C) || defined(__DOXYGEN__) | ||
248 | #define LPS25H_SHARED_I2C FALSE | ||
249 | #endif | ||
250 | |||
251 | /** | ||
252 | * @brief LPS25H advanced configurations switch. | ||
253 | * @details If set to @p TRUE more configurations are available. | ||
254 | * @note The default is @p FALSE. | ||
255 | */ | ||
256 | #if !defined(LPS25H_USE_ADVANCED) || defined(__DOXYGEN__) | ||
257 | #define LPS25H_USE_ADVANCED FALSE | ||
258 | #endif | ||
259 | /** @} */ | ||
260 | |||
261 | /*===========================================================================*/ | ||
262 | /* Derived constants and error checks. */ | ||
263 | /*===========================================================================*/ | ||
264 | |||
265 | #if !(LPS25H_USE_SPI ^ LPS25H_USE_I2C) | ||
266 | #error "LPS25H_USE_SPI and LPS25H_USE_I2C cannot be both true or both false" | ||
267 | #endif | ||
268 | |||
269 | #if LPS25H_USE_SPI && !HAL_USE_SPI | ||
270 | #error "LPS25H_USE_SPI requires HAL_USE_SPI" | ||
271 | #endif | ||
272 | |||
273 | #if LPS25H_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION | ||
274 | #error "LPS25H_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" | ||
275 | #endif | ||
276 | |||
277 | #if LPS25H_USE_I2C && !HAL_USE_I2C | ||
278 | #error "LPS25H_USE_I2C requires HAL_USE_I2C" | ||
279 | #endif | ||
280 | |||
281 | #if LPS25H_SHARED_I2C && !I2C_USE_MUTUAL_EXCLUSION | ||
282 | #error "LPS25H_SHARED_I2C requires I2C_USE_MUTUAL_EXCLUSION" | ||
283 | #endif | ||
284 | |||
285 | /* | ||
286 | * CHTODO: Add support for LPS25H over SPI. | ||
287 | */ | ||
288 | #if LPS25H_USE_SPI | ||
289 | #error "LPS25H over SPI still not supported" | ||
290 | #endif | ||
291 | |||
292 | /*===========================================================================*/ | ||
293 | /* Driver data structures and types. */ | ||
294 | /*===========================================================================*/ | ||
295 | |||
296 | /** | ||
297 | * @name LPS25H data structures and types. | ||
298 | * @{ | ||
299 | */ | ||
300 | /** | ||
301 | * @brief Structure representing a LPS25H driver. | ||
302 | */ | ||
303 | typedef struct LPS25HDriver LPS25HDriver; | ||
304 | |||
305 | /** | ||
306 | * @brief LPS25H slave address | ||
307 | */ | ||
308 | typedef enum { | ||
309 | LPS25H_SAD_GND = 0x5C, /**< Slave Address when SA0 is to GND */ | ||
310 | LPS25H_SAD_VCC = 0x5D /**< Slave Address when SA0 is to VCC */ | ||
311 | }lps25h_sad_t; | ||
312 | |||
313 | /** | ||
314 | * @brief LPS25H output data rate and bandwidth. | ||
315 | */ | ||
316 | typedef enum { | ||
317 | LPS25H_ODR_ONE_SHOT = 0x00, /**< One shot. */ | ||
318 | LPS25H_ODR_1HZ = 0x10, /**< Output data rate 1 Hz. */ | ||
319 | LPS25H_ODR_7HZ = 0x20, /**< Output data rate 7 Hz. */ | ||
320 | LPS25H_ODR_12P5HZ = 0x30, /**< Output data rate 12.5 Hz. */ | ||
321 | LPS25H_ODR_25HZ = 0x40 /**< Output data rate 25 Hz. */ | ||
322 | }lps25h_odr_t; | ||
323 | |||
324 | /** | ||
325 | * @brief LPS25H pressure resolution. | ||
326 | */ | ||
327 | typedef enum { | ||
328 | LPS25H_AVGP_8 = 0x00, /**< Number of internal average is 8. */ | ||
329 | LPS25H_AVGP_32 = 0x01, /**< Number of internal average is 32. */ | ||
330 | LPS25H_AVGP_128 = 0x02, /**< Number of internal average is 128. */ | ||
331 | LPS25H_AVGP_512 = 0x03, /**< Number of internal average is 512. */ | ||
332 | }lps25h_avgp_t; | ||
333 | |||
334 | /** | ||
335 | * @brief LPS25H temperature resolution. | ||
336 | */ | ||
337 | typedef enum { | ||
338 | LPS25H_AVGT_8 = 0x00, /**< Number of internal average is 8. */ | ||
339 | LPS25H_AVGT_32 = 0x04, /**< Number of internal average is 32. */ | ||
340 | LPS25H_AVGT_128 = 0x08, /**< Number of internal average is 128. */ | ||
341 | LPS25H_AVGT_512 = 0x0C, /**< Number of internal average is 512. */ | ||
342 | }lps25h_avgt_t; | ||
343 | |||
344 | /** | ||
345 | * @brief LPS25H block data update. | ||
346 | */ | ||
347 | typedef enum { | ||
348 | LPS25H_BDU_CONTINUOUS = 0x00, /**< Block data continuously updated. */ | ||
349 | LPS25H_BDU_BLOCKED = 0x40 /**< Block data updated after reading. */ | ||
350 | }lps25h_bdu_t; | ||
351 | |||
352 | /** | ||
353 | * @brief Driver state machine possible states. | ||
354 | */ | ||
355 | typedef enum { | ||
356 | LPS25H_UNINIT = 0, /**< Not initialized. */ | ||
357 | LPS25H_STOP = 1, /**< Stopped. */ | ||
358 | LPS25H_READY = 2, /**< Ready. */ | ||
359 | } lps25h_state_t; | ||
360 | |||
361 | /** | ||
362 | * @brief LPS25H configuration structure. | ||
363 | */ | ||
364 | typedef struct { | ||
365 | |||
366 | #if LPS25H_USE_SPI || defined(__DOXYGEN__) | ||
367 | /** | ||
368 | * @brief SPI driver associated to this LPS25H. | ||
369 | */ | ||
370 | SPIDriver *spip; | ||
371 | /** | ||
372 | * @brief SPI configuration associated to this LPS25H. | ||
373 | */ | ||
374 | const SPIConfig *spicfg; | ||
375 | #endif /* LPS25H_USE_SPI */ | ||
376 | #if LPS25H_USE_I2C || defined(__DOXYGEN__) | ||
377 | /** | ||
378 | * @brief I2C driver associated to this LPS25H. | ||
379 | */ | ||
380 | I2CDriver *i2cp; | ||
381 | /** | ||
382 | * @brief I2C configuration associated to this LPS25H. | ||
383 | */ | ||
384 | const I2CConfig *i2ccfg; | ||
385 | /** | ||
386 | * @brief LPS25H slave address | ||
387 | */ | ||
388 | lps25h_sad_t slaveaddress; | ||
389 | #endif /* LPS25H_USE_I2C */ | ||
390 | /** | ||
391 | * @brief LPS25H barometer subsystem initial sensitivity. | ||
392 | */ | ||
393 | float *barosensitivity; | ||
394 | /** | ||
395 | * @brief LPS25H barometer subsystem initial bias. | ||
396 | */ | ||
397 | float *barobias; | ||
398 | /** | ||
399 | * @brief LPS25H thermometer subsystem initial sensitivity. | ||
400 | */ | ||
401 | float *thermosensitivity; | ||
402 | /** | ||
403 | * @brief LPS25H thermometer subsystem initial bias. | ||
404 | */ | ||
405 | float *thermobias; | ||
406 | /** | ||
407 | * @brief LPS25H output data rate selection. | ||
408 | */ | ||
409 | lps25h_odr_t outputdatarate; | ||
410 | #if LPS25H_USE_ADVANCED || defined(__DOXYGEN__) | ||
411 | /** | ||
412 | * @brief LPS25H block data update. | ||
413 | */ | ||
414 | lps25h_bdu_t blockdataupdate; | ||
415 | /** | ||
416 | * @brief LPS25H barometer subsystem resolution. | ||
417 | */ | ||
418 | lps25h_avgp_t baroresolution; | ||
419 | /** | ||
420 | * @brief LPS25H thermometer subsystem resolution. | ||
421 | */ | ||
422 | lps25h_avgt_t thermoresolution; | ||
423 | #endif | ||
424 | } LPS25HConfig; | ||
425 | |||
426 | /** | ||
427 | * @brief @p LPS25H specific methods. | ||
428 | * @note No methods so far, just a common ancestor interface. | ||
429 | */ | ||
430 | #define _lps25h_methods_alone | ||
431 | |||
432 | /** | ||
433 | * @brief @p LPS25H specific methods with inherited ones. | ||
434 | */ | ||
435 | #define _lps25h_methods \ | ||
436 | _base_object_methods \ | ||
437 | _lps25h_methods_alone | ||
438 | |||
439 | /** | ||
440 | * @extends BaseObjectVMT | ||
441 | * | ||
442 | * @brief @p LPS25H virtual methods table. | ||
443 | */ | ||
444 | struct LPS25HVMT { | ||
445 | _lps25h_methods | ||
446 | }; | ||
447 | |||
448 | /** | ||
449 | * @brief @p LPS25HDriver specific data. | ||
450 | */ | ||
451 | #define _lps25h_data \ | ||
452 | /* Driver state.*/ \ | ||
453 | lps25h_state_t state; \ | ||
454 | /* Current configuration data.*/ \ | ||
455 | const LPS25HConfig *config; \ | ||
456 | /* Barometer subsystem axes number.*/ \ | ||
457 | size_t baroaxes; \ | ||
458 | /* Barometer subsystem current sensitivity.*/ \ | ||
459 | float barosensitivity; \ | ||
460 | /* Barometer subsystem current bias .*/ \ | ||
461 | float barobias; \ | ||
462 | /* Thermometer subsystem axes number.*/ \ | ||
463 | size_t thermoaxes; \ | ||
464 | /* Thermometer subsystem current sensitivity.*/ \ | ||
465 | float thermosensitivity; \ | ||
466 | /* Thermometer subsystem current bias.*/ \ | ||
467 | float thermobias; | ||
468 | |||
469 | /** | ||
470 | * @brief LPS25H 2-axis barometer/thermometer class. | ||
471 | */ | ||
472 | struct LPS25HDriver { | ||
473 | /** @brief Virtual Methods Table.*/ | ||
474 | const struct LPS25HVMT *vmt; | ||
475 | /** @brief Base barometer interface.*/ | ||
476 | BaseBarometer baro_if; | ||
477 | /** @brief Base thermometer interface.*/ | ||
478 | BaseThermometer thermo_if; | ||
479 | _lps25h_data | ||
480 | }; | ||
481 | /** @} */ | ||
482 | |||
483 | /*===========================================================================*/ | ||
484 | /* Driver macros. */ | ||
485 | /*===========================================================================*/ | ||
486 | |||
487 | /** | ||
488 | * @brief Return the number of axes of the BaseBarometer. | ||
489 | * | ||
490 | * @param[in] devp pointer to @p LPS25HDriver. | ||
491 | * | ||
492 | * @return the number of axes. | ||
493 | * | ||
494 | * @api | ||
495 | */ | ||
496 | #define lps25hBarometerGetAxesNumber(devp) \ | ||
497 | barometerGetAxesNumber(&((devp)->baro_if)) | ||
498 | |||
499 | /** | ||
500 | * @brief Retrieves raw data from the BaseBarometer. | ||
501 | * @note This data is retrieved from MEMS register without any algebraical | ||
502 | * manipulation. | ||
503 | * @note The axes array must be at least the same size of the | ||
504 | * BaseBarometer axes number. | ||
505 | * | ||
506 | * @param[in] devp pointer to @p LPS25HDriver. | ||
507 | * @param[out] axes a buffer which would be filled with raw data. | ||
508 | * | ||
509 | * @return The operation status. | ||
510 | * @retval MSG_OK if the function succeeded. | ||
511 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
512 | * be retrieved using @p i2cGetErrors(). | ||
513 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
514 | * | ||
515 | * @api | ||
516 | */ | ||
517 | #define lps25hBarometerReadRaw(devp, axes) \ | ||
518 | barometerReadRaw(&((devp)->baro_if), axes) | ||
519 | |||
520 | /** | ||
521 | * @brief Retrieves cooked data from the BaseBarometer. | ||
522 | * @note This data is manipulated according to the formula | ||
523 | * cooked = (raw * sensitivity) - bias. | ||
524 | * @note Final data is expressed as hPa. | ||
525 | * @note The axes array must be at least the same size of the | ||
526 | * BaseBarometer axes number. | ||
527 | * | ||
528 | * @param[in] devp pointer to @p LPS25HDriver. | ||
529 | * @param[out] axes a buffer which would be filled with cooked data. | ||
530 | * | ||
531 | * @return The operation status. | ||
532 | * @retval MSG_OK if the function succeeded. | ||
533 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
534 | * be retrieved using @p i2cGetErrors(). | ||
535 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
536 | * | ||
537 | * @api | ||
538 | */ | ||
539 | #define lps25hBarometerReadCooked(devp, axes) \ | ||
540 | barometerReadCooked(&((devp)->baro_if), axes) | ||
541 | |||
542 | /** | ||
543 | * @brief Set bias values for the BaseBarometer. | ||
544 | * @note Bias must be expressed as hPa. | ||
545 | * @note The bias buffer must be at least the same size of the | ||
546 | * BaseBarometer axes number. | ||
547 | * | ||
548 | * @param[in] devp pointer to @p LPS25HDriver. | ||
549 | * @param[in] bp a buffer which contains biases. | ||
550 | * | ||
551 | * @return The operation status. | ||
552 | * @retval MSG_OK if the function succeeded. | ||
553 | * | ||
554 | * @api | ||
555 | */ | ||
556 | #define lps25hBarometerSetBias(devp, bp) \ | ||
557 | barometerSetBias(&((devp)->baro_if), bp) | ||
558 | |||
559 | /** | ||
560 | * @brief Reset bias values for the BaseBarometer. | ||
561 | * @note Default biases value are obtained from device datasheet when | ||
562 | * available otherwise they are considered zero. | ||
563 | * | ||
564 | * @param[in] devp pointer to @p LPS25HDriver. | ||
565 | * | ||
566 | * @return The operation status. | ||
567 | * @retval MSG_OK if the function succeeded. | ||
568 | * | ||
569 | * @api | ||
570 | */ | ||
571 | #define lps25hBarometerResetBias(devp) \ | ||
572 | barometerResetBias(&((devp)->baro_if)) | ||
573 | |||
574 | /** | ||
575 | * @brief Set sensitivity values for the BaseBarometer. | ||
576 | * @note Sensitivity must be expressed as hPa/LSB. | ||
577 | * @note The sensitivity buffer must be at least the same size of the | ||
578 | * BaseBarometer axes number. | ||
579 | * | ||
580 | * @param[in] devp pointer to @p LPS25HDriver. | ||
581 | * @param[in] sp a buffer which contains sensitivities. | ||
582 | * | ||
583 | * @return The operation status. | ||
584 | * @retval MSG_OK if the function succeeded. | ||