diff options
Diffstat (limited to 'lib/chibios/os/ex/devices/ST/lsm303agr.c')
-rw-r--r-- | lib/chibios/os/ex/devices/ST/lsm303agr.c | 906 |
1 files changed, 906 insertions, 0 deletions
diff --git a/lib/chibios/os/ex/devices/ST/lsm303agr.c b/lib/chibios/os/ex/devices/ST/lsm303agr.c new file mode 100644 index 000000000..ba75ecd6c --- /dev/null +++ b/lib/chibios/os/ex/devices/ST/lsm303agr.c | |||
@@ -0,0 +1,906 @@ | |||
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 lsm303agr.c | ||
23 | * @brief LSM303AGR MEMS interface module code. | ||
24 | * | ||
25 | * @addtogroup LSM303AGR | ||
26 | * @ingroup EX_ST | ||
27 | * @{ | ||
28 | */ | ||
29 | |||
30 | #include "hal.h" | ||
31 | #include "lsm303agr.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 | * @brief Accelerometer and Compass Slave Address. | ||
47 | */ | ||
48 | typedef enum { | ||
49 | LSM303AGR_SAD_ACC = 0x19, /**< SAD for accelerometer. */ | ||
50 | LSM303AGR_SAD_COMP = 0x1E /**< SAD for compass. */ | ||
51 | } lsm303agr_sad_t; | ||
52 | |||
53 | /*===========================================================================*/ | ||
54 | /* Driver local functions. */ | ||
55 | /*===========================================================================*/ | ||
56 | |||
57 | /** | ||
58 | * @brief Reads registers value using I2C. | ||
59 | * @pre The I2C interface must be initialized and the driver started. | ||
60 | * @note IF_ADD_INC bit must be 1 in CTRL_REG8. | ||
61 | * | ||
62 | * @param[in] i2cp pointer to the I2C interface. | ||
63 | * @param[in] sad slave address without R bit. | ||
64 | * @param[in] reg first sub-register address. | ||
65 | * @param[in] rxbuf receiving buffer. | ||
66 | * @param[in] n size of rxbuf. | ||
67 | * @return the operation status. | ||
68 | */ | ||
69 | static msg_t lsm303agrI2CReadRegister(I2CDriver *i2cp, lsm303agr_sad_t sad, | ||
70 | uint8_t reg, uint8_t *rxbuf, size_t n) { | ||
71 | |||
72 | uint8_t txbuf = reg | LSM303AGR_MS; | ||
73 | return i2cMasterTransmitTimeout(i2cp, sad, &txbuf, 1, rxbuf, n, | ||
74 | TIME_INFINITE); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * @brief Writes a value into a register using I2C. | ||
79 | * @pre The I2C interface must be initialized and the driver started. | ||
80 | * | ||
81 | * @param[in] i2cp pointer to the I2C interface. | ||
82 | * @param[in] sad slave address without R bit. | ||
83 | * @param[in] txbuf buffer containing sub-address value in first position | ||
84 | * and values to write. | ||
85 | * @param[in] n size of txbuf less one (not considering the first | ||
86 | * element). | ||
87 | * @return the operation status. | ||
88 | */ | ||
89 | static msg_t lsm303agrI2CWriteRegister(I2CDriver *i2cp, lsm303agr_sad_t sad, | ||
90 | uint8_t *txbuf, size_t n) { | ||
91 | if (n != 1) | ||
92 | *txbuf |= LSM303AGR_MS; | ||
93 | return i2cMasterTransmitTimeout(i2cp, sad, txbuf, n + 1, NULL, 0, | ||
94 | TIME_INFINITE); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * @brief Return the number of axes of the BaseAccelerometer. | ||
99 | * | ||
100 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
101 | * | ||
102 | * @return the number of axes. | ||
103 | */ | ||
104 | static size_t acc_get_axes_number(void *ip) { | ||
105 | (void)ip; | ||
106 | |||
107 | return LSM303AGR_ACC_NUMBER_OF_AXES; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * @brief Retrieves raw data from the BaseAccelerometer. | ||
112 | * @note This data is retrieved from MEMS register without any algebraical | ||
113 | * manipulation. | ||
114 | * @note The axes array must be at least the same size of the | ||
115 | * BaseAccelerometer axes number. | ||
116 | * | ||
117 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
118 | * @param[out] axes a buffer which would be filled with raw data. | ||
119 | * | ||
120 | * @return The operation status. | ||
121 | * @retval MSG_OK if the function succeeded. | ||
122 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
123 | * be retrieved using @p i2cGetErrors(). | ||
124 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
125 | */ | ||
126 | static msg_t acc_read_raw(void *ip, int32_t axes[]) { | ||
127 | LSM303AGRDriver* devp; | ||
128 | uint8_t buff [LSM303AGR_ACC_NUMBER_OF_AXES * 2], i; | ||
129 | int16_t tmp; | ||
130 | msg_t msg; | ||
131 | |||
132 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
133 | |||
134 | /* Getting parent instance pointer.*/ | ||
135 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
136 | |||
137 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
138 | "acc_read_raw(), invalid state"); | ||
139 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
140 | "acc_read_raw(), channel not ready"); | ||
141 | |||
142 | #if LSM303AGR_SHARED_I2C | ||
143 | i2cAcquireBus(devp->config->i2cp); | ||
144 | i2cStart(devp->config->i2cp, | ||
145 | devp->config->i2ccfg); | ||
146 | #endif /* LSM303AGR_SHARED_I2C */ | ||
147 | |||
148 | msg = lsm303agrI2CReadRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, | ||
149 | LSM303AGR_AD_OUT_X_L_A, buff, | ||
150 | LSM303AGR_ACC_NUMBER_OF_AXES * 2); | ||
151 | |||
152 | #if LSM303AGR_SHARED_I2C | ||
153 | i2cReleaseBus(devp->config->i2cp); | ||
154 | #endif /* LSM303AGR_SHARED_I2C */ | ||
155 | |||
156 | if(msg == MSG_OK) | ||
157 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
158 | tmp = buff[2 * i] + (buff[2 * i + 1] << 8); | ||
159 | axes[i] = (int32_t)tmp; | ||
160 | } | ||
161 | return msg; | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * @brief Retrieves cooked data from the BaseAccelerometer. | ||
166 | * @note This data is manipulated according to the formula | ||
167 | * cooked = (raw * sensitivity) - bias. | ||
168 | * @note Final data is expressed as milli-G. | ||
169 | * @note The axes array must be at least the same size of the | ||
170 | * BaseAccelerometer axes number. | ||
171 | * | ||
172 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
173 | * @param[out] axes a buffer which would be filled with cooked data. | ||
174 | * | ||
175 | * @return The operation status. | ||
176 | * @retval MSG_OK if the function succeeded. | ||
177 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
178 | * be retrieved using @p i2cGetErrors(). | ||
179 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
180 | */ | ||
181 | static msg_t acc_read_cooked(void *ip, float axes[]) { | ||
182 | LSM303AGRDriver* devp; | ||
183 | uint32_t i; | ||
184 | int32_t raw[LSM303AGR_ACC_NUMBER_OF_AXES]; | ||
185 | msg_t msg; | ||
186 | |||
187 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
188 | |||
189 | /* Getting parent instance pointer.*/ | ||
190 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
191 | |||
192 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
193 | "acc_read_cooked(), invalid state"); | ||
194 | |||
195 | msg = acc_read_raw(ip, raw); | ||
196 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
197 | axes[i] = (raw[i] * devp->accsensitivity[i]) - devp->accbias[i]; | ||
198 | } | ||
199 | return msg; | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * @brief Set bias values for the BaseAccelerometer. | ||
204 | * @note Bias must be expressed as milli-G. | ||
205 | * @note The bias buffer must be at least the same size of the | ||
206 | * BaseAccelerometer axes number. | ||
207 | * | ||
208 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
209 | * @param[in] bp a buffer which contains biases. | ||
210 | * | ||
211 | * @return The operation status. | ||
212 | * @retval MSG_OK if the function succeeded. | ||
213 | */ | ||
214 | static msg_t acc_set_bias(void *ip, float *bp) { | ||
215 | LSM303AGRDriver* devp; | ||
216 | uint32_t i; | ||
217 | msg_t msg = MSG_OK; | ||
218 | |||
219 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
220 | |||
221 | /* Getting parent instance pointer.*/ | ||
222 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
223 | |||
224 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
225 | "acc_set_bias(), invalid state"); | ||
226 | |||
227 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
228 | devp->accbias[i] = bp[i]; | ||
229 | } | ||
230 | return msg; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * @brief Reset bias values for the BaseAccelerometer. | ||
235 | * @note Default biases value are obtained from device datasheet when | ||
236 | * available otherwise they are considered zero. | ||
237 | * | ||
238 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
239 | * | ||
240 | * @return The operation status. | ||
241 | * @retval MSG_OK if the function succeeded. | ||
242 | */ | ||
243 | static msg_t acc_reset_bias(void *ip) { | ||
244 | LSM303AGRDriver* devp; | ||
245 | uint32_t i; | ||
246 | msg_t msg = MSG_OK; | ||
247 | |||
248 | osalDbgCheck(ip != NULL); | ||
249 | |||
250 | /* Getting parent instance pointer.*/ | ||
251 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
252 | |||
253 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
254 | "acc_reset_bias(), invalid state"); | ||
255 | |||
256 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) | ||
257 | devp->accbias[i] = LSM303AGR_ACC_BIAS; | ||
258 | return msg; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * @brief Set sensitivity values for the BaseAccelerometer. | ||
263 | * @note Sensitivity must be expressed as milli-G/LSB. | ||
264 | * @note The sensitivity buffer must be at least the same size of the | ||
265 | * BaseAccelerometer axes number. | ||
266 | * | ||
267 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
268 | * @param[in] sp a buffer which contains sensitivities. | ||
269 | * | ||
270 | * @return The operation status. | ||
271 | * @retval MSG_OK if the function succeeded. | ||
272 | */ | ||
273 | static msg_t acc_set_sensivity(void *ip, float *sp) { | ||
274 | LSM303AGRDriver* devp; | ||
275 | uint32_t i; | ||
276 | msg_t msg = MSG_OK; | ||
277 | |||
278 | /* Getting parent instance pointer.*/ | ||
279 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
280 | |||
281 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
282 | |||
283 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
284 | "acc_set_sensivity(), invalid state"); | ||
285 | |||
286 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
287 | devp->accsensitivity[i] = sp[i]; | ||
288 | } | ||
289 | return msg; | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * @brief Reset sensitivity values for the BaseAccelerometer. | ||
294 | * @note Default sensitivities value are obtained from device datasheet. | ||
295 | * | ||
296 | * @param[in] ip pointer to @p BaseAccelerometer interface. | ||
297 | * | ||
298 | * @return The operation status. | ||
299 | * @retval MSG_OK if the function succeeded. | ||
300 | * @retval MSG_RESET otherwise. | ||
301 | */ | ||
302 | static msg_t acc_reset_sensivity(void *ip) { | ||
303 | LSM303AGRDriver* devp; | ||
304 | uint32_t i; | ||
305 | msg_t msg = MSG_OK; | ||
306 | |||
307 | osalDbgCheck(ip != NULL); | ||
308 | |||
309 | /* Getting parent instance pointer.*/ | ||
310 | devp = objGetInstance(LSM303AGRDriver*, (BaseAccelerometer*)ip); | ||
311 | |||
312 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
313 | "acc_reset_sensivity(), invalid state"); | ||
314 | |||
315 | if(devp->config->accfullscale == LSM303AGR_ACC_FS_2G) { | ||
316 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
317 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_2G; | ||
318 | } | ||
319 | } | ||
320 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_4G) { | ||
321 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
322 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_4G; | ||
323 | } | ||
324 | } | ||
325 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_8G) { | ||
326 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
327 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_8G; | ||
328 | } | ||
329 | } | ||
330 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_16G) { | ||
331 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
332 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_16G; | ||
333 | } | ||
334 | } | ||
335 | else { | ||
336 | osalDbgAssert(FALSE, "reset_sensivity(), accelerometer full scale issue"); | ||
337 | msg = MSG_RESET; | ||
338 | } | ||
339 | return msg; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * @brief Changes the LSM303AGRDriver accelerometer fullscale value. | ||
344 | * @note This function also rescale sensitivities and biases based on | ||
345 | * previous and next fullscale value. | ||
346 | * @note A recalibration is highly suggested after calling this function. | ||
347 | * | ||
348 | * @param[in] devp pointer to @p LSM303AGRDriver interface. | ||
349 | * @param[in] fs new fullscale value. | ||
350 | * | ||
351 | * @return The operation status. | ||
352 | * @retval MSG_OK if the function succeeded. | ||
353 | * @retval MSG_RESET otherwise. | ||
354 | */ | ||
355 | static msg_t acc_set_full_scale(LSM303AGRDriver *devp, | ||
356 | lsm303agr_acc_fs_t fs) { | ||
357 | float newfs, scale; | ||
358 | uint8_t i, buff[2]; | ||
359 | msg_t msg; | ||
360 | |||
361 | osalDbgCheck(devp != NULL); | ||
362 | |||
363 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
364 | "acc_set_full_scale(), invalid state"); | ||
365 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
366 | "acc_set_full_scale(), channel not ready"); | ||
367 | |||
368 | /* Computing new fullscale value.*/ | ||
369 | if(fs == LSM303AGR_ACC_FS_2G) { | ||
370 | newfs = LSM303AGR_ACC_2G; | ||
371 | } | ||
372 | else if(fs == LSM303AGR_ACC_FS_4G) { | ||
373 | newfs = LSM303AGR_ACC_4G; | ||
374 | } | ||
375 | else if(fs == LSM303AGR_ACC_FS_8G) { | ||
376 | newfs = LSM303AGR_ACC_8G; | ||
377 | } | ||
378 | else if(fs == LSM303AGR_ACC_FS_16G) { | ||
379 | newfs = LSM303AGR_ACC_16G; | ||
380 | } | ||
381 | else { | ||
382 | msg = MSG_RESET; | ||
383 | return msg; | ||
384 | } | ||
385 | |||
386 | if(newfs != devp->accfullscale) { | ||
387 | /* Computing scale value.*/ | ||
388 | scale = newfs / devp->accfullscale; | ||
389 | devp->accfullscale = newfs; | ||
390 | |||
391 | #if LSM303AGR_SHARED_I2C | ||
392 | i2cAcquireBus(devp->config->i2cp); | ||
393 | i2cStart(devp->config->i2cp, | ||
394 | devp->config->i2ccfg); | ||
395 | #endif /* LSM303AGR_SHARED_I2C */ | ||
396 | |||
397 | /* Updating register.*/ | ||
398 | msg = lsm303agrI2CReadRegister(devp->config->i2cp, | ||
399 | LSM303AGR_SAD_ACC, | ||
400 | LSM303AGR_AD_CTRL_REG4_A, | ||
401 | &buff[1], 1); | ||
402 | |||
403 | #if LSM303AGR_SHARED_I2C | ||
404 | i2cReleaseBus(devp->config->i2cp); | ||
405 | #endif /* LSM303AGR_SHARED_I2C */ | ||
406 | |||
407 | if(msg != MSG_OK) | ||
408 | return msg; | ||
409 | |||
410 | buff[1] &= ~(LSM303AGR_CTRL_REG4_A_FS_MASK); | ||
411 | buff[1] |= fs; | ||
412 | buff[0] = LSM303AGR_AD_CTRL_REG4_A; | ||
413 | |||
414 | #if LSM303AGR_SHARED_I2C | ||
415 | i2cAcquireBus(devp->config->i2cp); | ||
416 | i2cStart(devp->config->i2cp, devp->config->i2ccfg); | ||
417 | #endif /* LSM303AGR_SHARED_I2C */ | ||
418 | |||
419 | msg = lsm303agrI2CWriteRegister(devp->config->i2cp, | ||
420 | LSM303AGR_SAD_ACC, buff, 1); | ||
421 | |||
422 | #if LSM303AGR_SHARED_I2C | ||
423 | i2cReleaseBus(devp->config->i2cp); | ||
424 | #endif /* LSM303AGR_SHARED_I2C */ | ||
425 | |||
426 | if(msg != MSG_OK) | ||
427 | return msg; | ||
428 | |||
429 | /* Scaling sensitivity and bias. Re-calibration is suggested anyway.*/ | ||
430 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
431 | devp->accsensitivity[i] *= scale; | ||
432 | devp->accbias[i] *= scale; | ||
433 | } | ||
434 | } | ||
435 | return msg; | ||
436 | } | ||
437 | |||
438 | /** | ||
439 | * @brief Return the number of axes of the BaseCompass. | ||
440 | * | ||
441 | * @param[in] ip pointer to @p BaseCompass interface | ||
442 | * | ||
443 | * @return the number of axes. | ||
444 | */ | ||
445 | static size_t comp_get_axes_number(void *ip) { | ||
446 | |||
447 | osalDbgCheck(ip != NULL); | ||
448 | return LSM303AGR_COMP_NUMBER_OF_AXES; | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * @brief Retrieves raw data from the BaseCompass. | ||
453 | * @note This data is retrieved from MEMS register without any algebraical | ||
454 | * manipulation. | ||
455 | * @note The axes array must be at least the same size of the | ||
456 | * BaseCompass axes number. | ||
457 | * | ||
458 | * @param[in] ip pointer to @p BaseCompass interface. | ||
459 | * @param[out] axes a buffer which would be filled with raw data. | ||
460 | * | ||
461 | * @return The operation status. | ||
462 | * @retval MSG_OK if the function succeeded. | ||
463 | * @retval MSG_RESET if one or more I2C errors occurred, the errors can | ||
464 | * be retrieved using @p i2cGetErrors(). | ||
465 | * @retval MSG_TIMEOUT if a timeout occurred before operation end. | ||
466 | */ | ||
467 | static msg_t comp_read_raw(void *ip, int32_t axes[]) { | ||
468 | LSM303AGRDriver* devp; | ||
469 | uint8_t buff [LSM303AGR_COMP_NUMBER_OF_AXES * 2], i; | ||
470 | int16_t tmp; | ||
471 | msg_t msg; | ||
472 | |||
473 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
474 | |||
475 | /* Getting parent instance pointer.*/ | ||
476 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
477 | |||
478 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
479 | "comp_read_raw(), invalid state"); | ||
480 | osalDbgAssert((devp->config->i2cp->state == I2C_READY), | ||
481 | "comp_read_raw(), channel not ready"); | ||
482 | |||
483 | #if LSM303AGR_SHARED_I2C | ||
484 | i2cAcquireBus(devp->config->i2cp); | ||
485 | i2cStart(devp->config->i2cp, | ||
486 | devp->config->i2ccfg); | ||
487 | #endif /* LSM303AGR_SHARED_I2C */ | ||
488 | msg = lsm303agrI2CReadRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, | ||
489 | LSM303AGR_AD_OUTX_L_REG_M, buff, | ||
490 | LSM303AGR_COMP_NUMBER_OF_AXES * 2); | ||
491 | |||
492 | #if LSM303AGR_SHARED_I2C | ||
493 | i2cReleaseBus(devp->config->i2cp); | ||
494 | #endif /* LSM303AGR_SHARED_I2C */ | ||
495 | |||
496 | if(msg == MSG_OK) | ||
497 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { | ||
498 | tmp = buff[2 * i] + (buff[2 * i + 1] << 8); | ||
499 | axes[i] = (int32_t)tmp; | ||
500 | } | ||
501 | return msg; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * @brief Retrieves cooked data from the BaseCompass. | ||
506 | * @note This data is manipulated according to the formula | ||
507 | * cooked = (raw * sensitivity) - bias. | ||
508 | * @note Final data is expressed as G. | ||
509 | * @note The axes array must be at least the same size of the | ||
510 | * BaseCompass axes number. | ||
511 | * | ||
512 | * @param[in] ip pointer to @p BaseCompass interface. | ||
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 | static msg_t comp_read_cooked(void *ip, float axes[]) { | ||
522 | LSM303AGRDriver* devp; | ||
523 | uint32_t i; | ||
524 | int32_t raw[LSM303AGR_COMP_NUMBER_OF_AXES]; | ||
525 | msg_t msg; | ||
526 | |||
527 | osalDbgCheck((ip != NULL) && (axes != NULL)); | ||
528 | |||
529 | |||
530 | /* Getting parent instance pointer.*/ | ||
531 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
532 | |||
533 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
534 | "comp_read_cooked(), invalid state"); | ||
535 | |||
536 | msg = comp_read_raw(ip, raw); | ||
537 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES ; i++) { | ||
538 | axes[i] = (raw[i] * devp->compsensitivity[i]) - devp->compbias[i]; | ||
539 | } | ||
540 | return msg; | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * @brief Set bias values for the BaseCompass. | ||
545 | * @note Bias must be expressed as G. | ||
546 | * @note The bias buffer must be at least the same size of the | ||
547 | * BaseCompass axes number. | ||
548 | * | ||
549 | * @param[in] ip pointer to @p BaseCompass interface. | ||
550 | * @param[in] bp a buffer which contains biases. | ||
551 | * | ||
552 | * @return The operation status. | ||
553 | * @retval MSG_OK if the function succeeded. | ||
554 | */ | ||
555 | static msg_t comp_set_bias(void *ip, float *bp) { | ||
556 | LSM303AGRDriver* devp; | ||
557 | uint32_t i; | ||
558 | msg_t msg = MSG_OK; | ||
559 | |||
560 | osalDbgCheck((ip != NULL) && (bp != NULL)); | ||
561 | |||
562 | /* Getting parent instance pointer.*/ | ||
563 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
564 | |||
565 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
566 | "comp_set_bias(), invalid state"); | ||
567 | |||
568 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { | ||
569 | devp->compbias[i] = bp[i]; | ||
570 | } | ||
571 | return msg; | ||
572 | } | ||
573 | |||
574 | /** | ||
575 | * @brief Reset bias values for the BaseCompass. | ||
576 | * @note Default biases value are obtained from device datasheet when | ||
577 | * available otherwise they are considered zero. | ||
578 | * | ||
579 | * @param[in] ip pointer to @p BaseCompass interface. | ||
580 | * | ||
581 | * @return The operation status. | ||
582 | * @retval MSG_OK if the function succeeded. | ||
583 | */ | ||
584 | static msg_t comp_reset_bias(void *ip) { | ||
585 | LSM303AGRDriver* devp; | ||
586 | uint32_t i; | ||
587 | msg_t msg = MSG_OK; | ||
588 | |||
589 | osalDbgCheck(ip != NULL); | ||
590 | |||
591 | /* Getting parent instance pointer.*/ | ||
592 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
593 | |||
594 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
595 | "comp_reset_bias(), invalid state"); | ||
596 | |||
597 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) | ||
598 | devp->compbias[i] = LSM303AGR_COMP_BIAS; | ||
599 | return msg; | ||
600 | } | ||
601 | |||
602 | /** | ||
603 | * @brief Set sensitivity values for the BaseCompass. | ||
604 | * @note Sensitivity must be expressed as G/LSB. | ||
605 | * @note The sensitivity buffer must be at least the same size of the | ||
606 | * BaseCompass axes number. | ||
607 | * | ||
608 | * @param[in] ip pointer to @p BaseCompass interface. | ||
609 | * @param[in] sp a buffer which contains sensitivities. | ||
610 | * | ||
611 | * @return The operation status. | ||
612 | * @retval MSG_OK if the function succeeded. | ||
613 | */ | ||
614 | static msg_t comp_set_sensivity(void *ip, float *sp) { | ||
615 | LSM303AGRDriver* devp; | ||
616 | uint32_t i; | ||
617 | msg_t msg = MSG_OK; | ||
618 | |||
619 | /* Getting parent instance pointer.*/ | ||
620 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
621 | |||
622 | osalDbgCheck((ip != NULL) && (sp != NULL)); | ||
623 | |||
624 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
625 | "comp_set_sensivity(), invalid state"); | ||
626 | |||
627 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { | ||
628 | devp->compsensitivity[i] = sp[i]; | ||
629 | } | ||
630 | return msg; | ||
631 | } | ||
632 | |||
633 | /** | ||
634 | * @brief Reset sensitivity values for the BaseCompass. | ||
635 | * @note Default sensitivities value are obtained from device datasheet. | ||
636 | * | ||
637 | * @param[in] ip pointer to @p BaseCompass interface. | ||
638 | * | ||
639 | * @return The operation status. | ||
640 | * @retval MSG_OK if the function succeeded. | ||
641 | * @retval MSG_RESET otherwise. | ||
642 | */ | ||
643 | static msg_t comp_reset_sensivity(void *ip) { | ||
644 | LSM303AGRDriver* devp; | ||
645 | uint32_t i; | ||
646 | msg_t msg = MSG_OK; | ||
647 | |||
648 | osalDbgCheck(ip != NULL); | ||
649 | |||
650 | /* Getting parent instance pointer.*/ | ||
651 | devp = objGetInstance(LSM303AGRDriver*, (BaseCompass*)ip); | ||
652 | |||
653 | osalDbgAssert((devp->state == LSM303AGR_READY), | ||
654 | "comp_reset_sensivity(), invalid state"); | ||
655 | |||
656 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) | ||
657 | devp->compsensitivity[i] = LSM303AGR_COMP_SENS_50GA; | ||
658 | |||
659 | return msg; | ||
660 | } | ||
661 | |||
662 | static const struct LSM303AGRVMT vmt_device = { | ||
663 | (size_t)0, | ||
664 | acc_set_full_scale | ||
665 | }; | ||
666 | |||
667 | static const struct BaseAccelerometerVMT vmt_accelerometer = { | ||
668 | sizeof(struct LSM303AGRVMT*), | ||
669 | acc_get_axes_number, acc_read_raw, acc_read_cooked, | ||
670 | acc_set_bias, acc_reset_bias, acc_set_sensivity, acc_reset_sensivity | ||
671 | }; | ||
672 | |||
673 | static const struct BaseCompassVMT vmt_compass = { | ||
674 | sizeof(struct LSM303AGRVMT*) + sizeof(BaseAccelerometer), | ||
675 | comp_get_axes_number, comp_read_raw, comp_read_cooked, | ||
676 | comp_set_bias, comp_reset_bias, comp_set_sensivity, comp_reset_sensivity | ||
677 | }; | ||
678 | |||
679 | /*===========================================================================*/ | ||
680 | /* Driver exported functions. */ | ||
681 | /*===========================================================================*/ | ||
682 | |||
683 | /** | ||
684 | * @brief Initializes an instance. | ||
685 | * | ||
686 | * @param[out] devp pointer to the @p LSM303AGRDriver object | ||
687 | * | ||
688 | * @init | ||
689 | */ | ||
690 | void lsm303agrObjectInit(LSM303AGRDriver *devp) { | ||
691 | devp->vmt = &vmt_device; | ||
692 | devp->acc_if.vmt = &vmt_accelerometer; | ||
693 | devp->comp_if.vmt = &vmt_compass; | ||
694 | |||
695 | devp->config = NULL; | ||
696 | |||
697 | devp->accaxes = LSM303AGR_ACC_NUMBER_OF_AXES; | ||
698 | devp->compaxes = LSM303AGR_COMP_NUMBER_OF_AXES; | ||
699 | |||
700 | devp->state = LSM303AGR_STOP; | ||
701 | } | ||
702 | |||
703 | /** | ||
704 | * @brief Configures and activates LSM303AGR Complex Driver peripheral. | ||
705 | * | ||
706 | * @param[in] devp pointer to the @p LSM303AGRDriver object | ||
707 | * @param[in] config pointer to the @p LSM303AGRConfig object | ||
708 | * | ||
709 | * @api | ||
710 | */ | ||
711 | void lsm303agrStart(LSM303AGRDriver *devp, const LSM303AGRConfig *config) { | ||
712 | uint32_t i; | ||
713 | uint8_t cr[6]; | ||
714 | osalDbgCheck((devp != NULL) && (config != NULL)); | ||
715 | |||
716 | osalDbgAssert((devp->state == LSM303AGR_STOP) || | ||
717 | (devp->state == LSM303AGR_READY), | ||
718 | "lsm303agrStart(), invalid state"); | ||
719 | |||
720 | devp->config = config; | ||
721 | |||
722 | /* Configuring Accelerometer subsystem.*/ | ||
723 | |||
724 | /* Multiple write starting address.*/ | ||
725 | cr[0] = LSM303AGR_AD_CTRL_REG1_A; | ||
726 | |||
727 | /* Control register 1 configuration block.*/ | ||
728 | { | ||
729 | cr[1] = LSM303AGR_ACC_AE_XYZ | devp->config->accoutdatarate; | ||
730 | #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) | ||
731 | if(devp->config->accmode == LSM303AGR_ACC_MODE_LPOW) | ||
732 | cr[1] |= LSM303AGR_CTRL_REG1_A_LPEN; | ||
733 | #endif | ||
734 | } | ||
735 | |||
736 | /* Control register 2 configuration block.*/ | ||
737 | { | ||
738 | cr[2] = 0; | ||
739 | } | ||
740 | |||
741 | /* Control register 3 configuration block.*/ | ||
742 | { | ||
743 | cr[3] = 0; | ||
744 | } | ||
745 | |||
746 | /* Control register 4 configuration block.*/ | ||
747 | { | ||
748 | cr[4] = devp->config->accfullscale; | ||
749 | #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) | ||
750 | cr[4] |= devp->config->accendianess | | ||
751 | devp->config->accblockdataupdate; | ||
752 | if(devp->config->accmode == LSM303AGR_ACC_MODE_HRES) | ||
753 | cr[4] |= LSM303AGR_CTRL_REG4_A_HR; | ||
754 | #endif | ||
755 | } | ||
756 | |||
757 | /* Storing sensitivity according to user settings */ | ||
758 | if(devp->config->accfullscale == LSM303AGR_ACC_FS_2G) { | ||
759 | devp->accfullscale = LSM303AGR_ACC_2G; | ||
760 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
761 | if(devp->config->accsensitivity == NULL) | ||
762 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_2G; | ||
763 | else | ||
764 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
765 | } | ||
766 | } | ||
767 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_4G) { | ||
768 | devp->accfullscale = LSM303AGR_ACC_4G; | ||
769 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
770 | if(devp->config->accsensitivity == NULL) | ||
771 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_4G; | ||
772 | else | ||
773 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
774 | } | ||
775 | } | ||
776 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_8G) { | ||
777 | devp->accfullscale = LSM303AGR_ACC_8G; | ||
778 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
779 | if(devp->config->accsensitivity == NULL) | ||
780 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_8G; | ||
781 | else | ||
782 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
783 | } | ||
784 | } | ||
785 | else if(devp->config->accfullscale == LSM303AGR_ACC_FS_16G) { | ||
786 | devp->accfullscale = LSM303AGR_ACC_16G; | ||
787 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) { | ||
788 | if(devp->config->accsensitivity == NULL) | ||
789 | devp->accsensitivity[i] = LSM303AGR_ACC_SENS_16G; | ||
790 | else | ||
791 | devp->accsensitivity[i] = devp->config->accsensitivity[i]; | ||
792 | } | ||
793 | } | ||
794 | else | ||
795 | osalDbgAssert(FALSE, "lsm303dlhcStart(), accelerometer full scale issue"); | ||
796 | |||
797 | /* Storing bias information */ | ||
798 | if(devp->config->accbias != NULL) | ||
799 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) | ||
800 | devp->accbias[i] = devp->config->accbias[i]; | ||
801 | else | ||
802 | for(i = 0; i < LSM303AGR_ACC_NUMBER_OF_AXES; i++) | ||
803 | devp->accbias[i] = LSM303AGR_ACC_BIAS; | ||
804 | |||
805 | #if LSM303AGR_SHARED_I2C | ||
806 | i2cAcquireBus((devp)->config->i2cp); | ||
807 | #endif /* LSM303AGR_SHARED_I2C */ | ||
808 | i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); | ||
809 | |||
810 | lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, cr, 4); | ||
811 | |||
812 | #if LSM303AGR_SHARED_I2C | ||
813 | i2cReleaseBus((devp)->config->i2cp); | ||
814 | #endif /* LSM303AGR_SHARED_I2C */ | ||
815 | |||
816 | /* Configuring Compass subsystem */ | ||
817 | /* Multiple write starting address.*/ | ||
818 | cr[0] = LSM303AGR_AD_CFG_REG_A_M; | ||
819 | |||
820 | /* Control register A configuration block.*/ | ||
821 | { | ||
822 | cr[1] = devp->config->compoutputdatarate; | ||
823 | #if LSM303AGR_USE_ADVANCED || defined(__DOXYGEN__) | ||
824 | cr[1] |= devp->config->compmode | devp->config->complp; | ||
825 | #endif | ||
826 | } | ||
827 | |||
828 | /* Control register B configuration block.*/ | ||
829 | { | ||
830 | cr[2] = 0; | ||
831 | } | ||
832 | |||
833 | /* Control register C configuration block.*/ | ||
834 | { | ||
835 | cr[3] = 0; | ||
836 | } | ||
837 | |||
838 | #if LSM303AGR_SHARED_I2C | ||
839 | i2cAcquireBus((devp)->config->i2cp); | ||
840 | i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); | ||
841 | #endif /* LSM303AGR_SHARED_I2C */ | ||
842 | |||
843 | lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, | ||
844 | cr, 3); | ||
845 | |||
846 | #if LSM303AGR_SHARED_I2C | ||
847 | i2cReleaseBus((devp)->config->i2cp); | ||
848 | #endif /* LSM303AGR_SHARED_I2C */ | ||
849 | |||
850 | devp->compfullscale = LSM303AGR_COMP_50GA; | ||
851 | for(i = 0; i < LSM303AGR_COMP_NUMBER_OF_AXES; i++) { | ||
852 | if(devp->config->compsensitivity == NULL) { | ||
853 | devp->compsensitivity[i] = LSM303AGR_COMP_SENS_50GA; | ||
854 | } | ||
855 | else { | ||
856 | devp->compsensitivity[i] = devp->config->compsensitivity[i]; | ||
857 | } | ||
858 | } | ||
859 | |||
860 | /* This is the MEMS transient recovery time */ | ||
861 | osalThreadSleepMilliseconds(5); | ||
862 | |||
863 | devp->state = LSM303AGR_READY; | ||
864 | } | ||
865 | |||
866 | /** | ||
867 | * @brief Deactivates the LSM303AGR Complex Driver peripheral. | ||
868 | * | ||
869 | * @param[in] devp pointer to the @p LSM303AGRDriver object | ||
870 | * | ||
871 | * @api | ||
872 | */ | ||
873 | void lsm303agrStop(LSM303AGRDriver *devp) { | ||
874 | uint8_t cr[2]; | ||
875 | osalDbgCheck(devp != NULL); | ||
876 | |||
877 | osalDbgAssert((devp->state == LSM303AGR_STOP) || | ||
878 | (devp->state == LSM303AGR_READY), | ||
879 | "lsm303agrStop(), invalid state"); | ||
880 | |||
881 | if (devp->state == LSM303AGR_READY) { | ||
882 | #if LSM303AGR_SHARED_I2C | ||
883 | i2cAcquireBus((devp)->config->i2cp); | ||
884 | i2cStart((devp)->config->i2cp, (devp)->config->i2ccfg); | ||
885 | #endif /* LSM303AGR_SHARED_I2C */ | ||
886 | |||
887 | /* Disabling accelerometer. */ | ||
888 | cr[0] = LSM303AGR_AD_CTRL_REG1_A; | ||
889 | cr[1] = LSM303AGR_ACC_AE_DISABLED | LSM303AGR_ACC_ODR_PD; | ||
890 | lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_ACC, | ||
891 | cr, 1); | ||
892 | |||
893 | /* Disabling compass. */ | ||
894 | cr[0] = LSM303AGR_AD_CFG_REG_A_M; | ||
895 | cr[1] = LSM303AGR_COMP_MODE_IDLE; | ||
896 | lsm303agrI2CWriteRegister(devp->config->i2cp, LSM303AGR_SAD_COMP, | ||
897 | cr, 1); | ||
898 | |||
899 | i2cStop((devp)->config->i2cp); | ||
900 | #if LSM303AGR_SHARED_I2C | ||
901 | i2cReleaseBus((devp)->config->i2cp); | ||
902 | #endif /* LSM303AGR_SHARED_I2C */ | ||
903 | } | ||
904 | devp->state = LSM303AGR_STOP; | ||
905 | } | ||
906 | /** @} */ | ||