aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/ex/devices/ST/lis3mdl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/ex/devices/ST/lis3mdl.c')
-rw-r--r--lib/chibios/os/ex/devices/ST/lis3mdl.c627
1 files changed, 627 insertions, 0 deletions
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 */
62msg_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 */
85msg_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 */
102static 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 */
124static 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 */
178static 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 */
212static 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 */
241static 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 */
271static 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 */
300static 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 */
345static 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
424static const struct LIS3MDLVMT vmt_device = {
425 (size_t)0,
426 comp_set_full_scale
427};
428
429static 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 */
446void 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 */
465void 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 */
598void 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/** @} */