2 * Copyright © 2019 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 #include <ao_bmx160.h>
23 static uint8_t ao_bmx160_configured;
25 static struct ao_bmm150_trim ao_bmm150_trim;
27 #define AO_BMX160_SPI_SPEED ao_spi_speed(10000000)
29 #define ao_bmx160_spi_get() ao_spi_get(AO_BMX160_SPI_BUS, AO_BMX160_SPI_SPEED)
30 #define ao_bmx160_spi_put() ao_spi_put(AO_BMX160_SPI_BUS)
32 #define ao_bmx160_spi_start() ao_spi_set_cs(AO_BMX160_SPI_CS_PORT, \
33 (1 << AO_BMX160_SPI_CS_PIN))
35 #define ao_bmx160_spi_end() ao_spi_clr_cs(AO_BMX160_SPI_CS_PORT, \
36 (1 << AO_BMX160_SPI_CS_PIN))
39 _ao_bmx160_reg_write(uint8_t addr, uint8_t value)
41 uint8_t d[2] = { addr, value };
42 ao_bmx160_spi_start();
43 ao_spi_send(d, 2, AO_BMX160_SPI_BUS);
48 _ao_bmx160_read(uint8_t addr, void *data, uint8_t len)
51 ao_bmx160_spi_start();
52 ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
53 ao_spi_recv(data, len, AO_BMX160_SPI_BUS);
58 _ao_bmx160_reg_read(uint8_t addr)
62 ao_bmx160_spi_start();
63 ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
64 ao_spi_recv(&value, 1, AO_BMX160_SPI_BUS);
70 _ao_bmx160_cmd(uint8_t cmd)
73 _ao_bmx160_reg_write(BMX160_CMD, cmd);
74 for (i = 0; i < 50; i++) {
76 cmd_read = _ao_bmx160_reg_read(BMX160_CMD);
83 _ao_bmm150_wait_manual(void)
85 while (_ao_bmx160_reg_read(BMX160_STATUS) & (1 << BMX160_STATUS_MAG_MAN_OP))
90 _ao_bmm150_reg_write(uint8_t addr, uint8_t data)
92 _ao_bmx160_reg_write(BMX160_MAG_IF_3, data);
93 _ao_bmx160_reg_write(BMX160_MAG_IF_2, addr);
94 _ao_bmm150_wait_manual();
98 _ao_bmm150_reg_read(uint8_t addr)
100 _ao_bmx160_reg_write(BMX160_MAG_IF_1, addr);
101 _ao_bmm150_wait_manual();
102 uint8_t ret = _ao_bmx160_reg_read(BMX160_DATA_0);
107 _ao_bmm150_reg_read2(uint8_t lo_addr, uint8_t hi_addr)
109 uint8_t lo = _ao_bmm150_reg_read(lo_addr);
110 uint8_t hi = _ao_bmm150_reg_read(hi_addr);
112 return ((uint16_t) hi << 8) | lo;
116 * The compensate functions are taken from the BMM150 sample
117 * driver which has the following copyright:
119 * Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved.
123 * Redistribution and use in source and binary forms, with or without
124 * modification, are permitted provided that the following conditions are met:
126 * 1. Redistributions of source code must retain the above copyright
127 * notice, this list of conditions and the following disclaimer.
129 * 2. Redistributions in binary form must reproduce the above copyright
130 * notice, this list of conditions and the following disclaimer in the
131 * documentation and/or other materials provided with the distribution.
133 * 3. Neither the name of the copyright holder nor the names of its
134 * contributors may be used to endorse or promote products derived from
135 * this software without specific prior written permission.
137 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
138 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
139 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
140 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
141 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
142 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
143 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
144 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
145 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
146 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
147 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
148 * POSSIBILITY OF SUCH DAMAGE.
157 * @brief This internal API is used to obtain the compensated
158 * magnetometer X axis data(micro-tesla) in int16_t.
160 static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall)
163 uint16_t process_comp_x0 = 0;
164 int32_t process_comp_x1;
165 uint16_t process_comp_x2;
166 int32_t process_comp_x3;
167 int32_t process_comp_x4;
168 int32_t process_comp_x5;
169 int32_t process_comp_x6;
170 int32_t process_comp_x7;
171 int32_t process_comp_x8;
172 int32_t process_comp_x9;
173 int32_t process_comp_x10;
175 /* Overflow condition check */
176 if (mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
180 /* Availability of valid data*/
181 process_comp_x0 = data_rhall;
182 //printf("using data_rhall %d\n", data_rhall);
184 else if (ao_bmm150_trim.dig_xyz1 != 0)
186 process_comp_x0 = ao_bmm150_trim.dig_xyz1;
187 //printf("using trim value %d\n", process_comp_x0);
192 //printf("no valid rhall\n");
194 if (process_comp_x0 != 0)
196 /* Processing compensation equations*/
197 process_comp_x1 = ((int32_t)ao_bmm150_trim.dig_xyz1) * 16384;
198 //printf("comp_x1 %d\n", process_comp_x1);
199 process_comp_x2 = ((uint16_t)(process_comp_x1 / process_comp_x0)) - ((uint16_t)0x4000);
200 //printf("comp_x2 %d\n", process_comp_x2);
201 retval = ((int16_t)process_comp_x2);
202 process_comp_x3 = (((int32_t)retval) * ((int32_t)retval));
203 //printf("comp_x3 %d\n", process_comp_x3);
204 process_comp_x4 = (((int32_t)ao_bmm150_trim.dig_xy2) * (process_comp_x3 / 128));
205 //printf("comp_x4 %d\n", process_comp_x4);
206 process_comp_x5 = (int32_t)(((int16_t)ao_bmm150_trim.dig_xy1) * 128);
207 //printf("comp_x5 %d\n", process_comp_x5);
208 process_comp_x6 = ((int32_t)retval) * process_comp_x5;
209 //printf("comp_x6 %d\n", process_comp_x6);
210 process_comp_x7 = (((process_comp_x4 + process_comp_x6) / 512) + ((int32_t)0x100000));
211 //printf("comp_x7 %d\n", process_comp_x7);
212 process_comp_x8 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_x2) + ((int16_t)0xA0)));
213 //printf("comp_x8 %d\n", process_comp_x8);
214 process_comp_x9 = ((process_comp_x7 * process_comp_x8) / 4096);
215 //printf("comp_x9 %d\n", process_comp_x9);
216 process_comp_x10 = ((int32_t)mag_data_x) * process_comp_x9;
217 //printf("comp_x10 %d\n", process_comp_x10);
218 retval = ((int16_t)(process_comp_x10 / 8192));
219 //printf("ret 1 %d\n", retval);
220 retval = (retval + (((int16_t)ao_bmm150_trim.dig_x1) * 8)) / 16;
221 //printf("final %d\n", retval);
225 retval = BMM150_OVERFLOW_OUTPUT;
230 /* Overflow condition */
231 retval = BMM150_OVERFLOW_OUTPUT;
238 * @brief This internal API is used to obtain the compensated
239 * magnetometer Y axis data(micro-tesla) in int16_t.
241 static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall)
244 uint16_t process_comp_y0 = 0;
245 int32_t process_comp_y1;
246 uint16_t process_comp_y2;
247 int32_t process_comp_y3;
248 int32_t process_comp_y4;
249 int32_t process_comp_y5;
250 int32_t process_comp_y6;
251 int32_t process_comp_y7;
252 int32_t process_comp_y8;
253 int32_t process_comp_y9;
255 /* Overflow condition check */
256 if (mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
260 /* Availability of valid data*/
261 process_comp_y0 = data_rhall;
263 else if (ao_bmm150_trim.dig_xyz1 != 0)
265 process_comp_y0 = ao_bmm150_trim.dig_xyz1;
271 if (process_comp_y0 != 0)
273 /*Processing compensation equations*/
274 process_comp_y1 = (((int32_t)ao_bmm150_trim.dig_xyz1) * 16384) / process_comp_y0;
275 process_comp_y2 = ((uint16_t)process_comp_y1) - ((uint16_t)0x4000);
276 retval = ((int16_t)process_comp_y2);
277 process_comp_y3 = ((int32_t) retval) * ((int32_t)retval);
278 process_comp_y4 = ((int32_t)ao_bmm150_trim.dig_xy2) * (process_comp_y3 / 128);
279 process_comp_y5 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_xy1) * 128));
280 process_comp_y6 = ((process_comp_y4 + (((int32_t)retval) * process_comp_y5)) / 512);
281 process_comp_y7 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_y2) + ((int16_t)0xA0)));
282 process_comp_y8 = (((process_comp_y6 + ((int32_t)0x100000)) * process_comp_y7) / 4096);
283 process_comp_y9 = (((int32_t)mag_data_y) * process_comp_y8);
284 retval = (int16_t)(process_comp_y9 / 8192);
285 retval = (retval + (((int16_t)ao_bmm150_trim.dig_y1) * 8)) / 16;
289 retval = BMM150_OVERFLOW_OUTPUT;
294 /* Overflow condition*/
295 retval = BMM150_OVERFLOW_OUTPUT;
302 * @brief This internal API is used to obtain the compensated
303 * magnetometer Z axis data(micro-tesla) in int16_t.
305 static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall)
308 int16_t process_comp_z0;
309 int32_t process_comp_z1;
310 int32_t process_comp_z2;
311 int32_t process_comp_z3;
312 int16_t process_comp_z4;
314 if (mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL)
316 if ((ao_bmm150_trim.dig_z2 != 0) && (ao_bmm150_trim.dig_z1 != 0) && (data_rhall != 0) &&
317 (ao_bmm150_trim.dig_xyz1 != 0))
319 /*Processing compensation equations*/
320 process_comp_z0 = ((int16_t)data_rhall) - ((int16_t) ao_bmm150_trim.dig_xyz1);
321 process_comp_z1 = (((int32_t)ao_bmm150_trim.dig_z3) * ((int32_t)(process_comp_z0))) / 4;
322 process_comp_z2 = (((int32_t)(mag_data_z - ao_bmm150_trim.dig_z4)) * 32768);
323 process_comp_z3 = ((int32_t)ao_bmm150_trim.dig_z1) * (((int16_t)data_rhall) * 2);
324 process_comp_z4 = (int16_t)((process_comp_z3 + (32768)) / 65536);
325 retval = ((process_comp_z2 - process_comp_z1) / (ao_bmm150_trim.dig_z2 + process_comp_z4));
327 /* saturate result to +/- 2 micro-tesla */
328 if (retval > BMM150_POSITIVE_SATURATION_Z)
330 retval = BMM150_POSITIVE_SATURATION_Z;
332 else if (retval < BMM150_NEGATIVE_SATURATION_Z)
334 retval = BMM150_NEGATIVE_SATURATION_Z;
337 /* Conversion of LSB to micro-tesla*/
338 retval = retval / 16;
342 retval = BMM150_OVERFLOW_OUTPUT;
347 /* Overflow condition*/
348 retval = BMM150_OVERFLOW_OUTPUT;
351 return (int16_t)retval;
355 _ao_bmx160_sample(struct ao_bmx160_sample *sample)
357 _ao_bmx160_read(BMX160_MAG_X_0_7, sample, sizeof (*sample));
358 #if __BYTE_ORDER != __LITTLE_ENDIAN
359 int i = sizeof (*sample) / 2;
360 uint16_t *d = (uint16_t *) sample;
365 *d++ = (t >> 8) | (t << 8);
368 uint16_t rhall = sample->rhall >> 2;
369 sample->mag_x = compensate_x(sample->mag_x >> 3, rhall);
370 sample->mag_y = compensate_y(sample->mag_y >> 3, rhall);
371 sample->mag_z = compensate_z(sample->mag_z >> 1, rhall);
374 #define G 981 /* in cm/s² */
377 static int16_t /* cm/s² */
378 ao_bmx160_accel(int16_t v)
380 return (int16_t) ((v * (int32_t) (16.0 * 980.665 + 0.5)) / 32767);
383 static int16_t /* deg*10/s */
384 ao_bmx160_gyro(int16_t v)
386 return (int16_t) ((v * (int32_t) 20000) / 32767);
390 ao_bmx160_accel_check(int16_t normal, int16_t test)
392 int16_t diff = test - normal;
394 if (diff < BMX160_ST_ACCEL(16) / 4) {
397 if (diff > BMX160_ST_ACCEL(16) * 4) {
404 ao_bmx160_gyro_check(int16_t normal, int16_t test)
406 int16_t diff = test - normal;
410 if (diff < BMX160_ST_GYRO(2000) / 4) {
413 if (diff > BMX160_ST_GYRO(2000) * 4) {
421 _ao_bmx160_wait_alive(void)
425 /* Wait for the chip to wake up */
426 for (i = 0; i < 30; i++) {
427 ao_delay(AO_MS_TO_TICKS(100));
428 if (_ao_bmx160_reg_read(BMX160_CHIPID) == BMX160_CHIPID_BMX160)
432 ao_panic(AO_PANIC_SELF_TEST_BMX160);
439 _ao_bmx160_setup(void)
443 if (ao_bmx160_configured)
446 /* Dummy read of 0x7f register to enable SPI interface */
447 (void) _ao_bmx160_reg_read(0x7f);
449 /* Make sure the chip is responding */
450 _ao_bmx160_wait_alive();
453 _ao_bmx160_reg_write(BMX160_NV_CONF, 1 << BMX160_NV_CONF_SPI_EN);
455 /* Enable acc and gyr
458 _ao_bmx160_cmd(BMX160_CMD_ACC_SET_PMU_MODE(BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL));
460 for (r = 0; r < 20; r++) {
461 ao_delay(AO_MS_TO_TICKS(100));
462 if (((_ao_bmx160_reg_read(BMX160_PMU_STATUS)
463 >> BMX160_PMU_STATUS_ACC_PMU_STATUS)
464 & BMX160_PMU_STATUS_ACC_PMU_STATUS_MASK)
465 == BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL)
472 AO_SENSOR_ERROR(AO_DATA_BMX160);
474 _ao_bmx160_cmd(BMX160_CMD_GYR_SET_PMU_MODE(BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL));
476 for (r = 0; r < 20; r++) {
477 ao_delay(AO_MS_TO_TICKS(100));
478 if (((_ao_bmx160_reg_read(BMX160_PMU_STATUS)
479 >> BMX160_PMU_STATUS_GYR_PMU_STATUS)
480 & BMX160_PMU_STATUS_GYR_PMU_STATUS_MASK)
481 == BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL)
488 AO_SENSOR_ERROR(AO_DATA_BMX160);
490 /* Configure accelerometer:
492 * undersampling disabled
494 * 200Hz sampling rate
497 * This yields a 3dB cutoff frequency of 80Hz
499 _ao_bmx160_reg_write(BMX160_ACC_CONF,
500 (0 << BMX160_ACC_CONF_ACC_US) |
501 (BMX160_ACC_CONF_ACC_BWP_NORMAL << BMX160_ACC_CONF_ACC_BWP) |
502 (BMX160_ACC_CONF_ACC_ODR_200 << BMX160_ACC_CONF_ACC_ODR));
503 _ao_bmx160_reg_write(BMX160_ACC_RANGE,
504 BMX160_ACC_RANGE_16G);
506 for (r = 0x3; r <= 0x1b; r++)
507 (void) _ao_bmx160_reg_read(r);
511 * 200Hz sampling rate
515 _ao_bmx160_reg_write(BMX160_GYR_CONF,
516 (BMX160_GYR_CONF_GYR_BWP_NORMAL << BMX160_GYR_CONF_GYR_BWP) |
517 (BMX160_GYR_CONF_GYR_ODR_200 << BMX160_GYR_CONF_GYR_ODR));
518 _ao_bmx160_reg_write(BMX160_GYR_RANGE,
519 BMX160_GYR_RANGE_2000);
522 /* Configure magnetometer:
528 _ao_bmx160_cmd(BMX160_CMD_MAG_IF_SET_PMU_MODE(BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_NORMAL));
530 _ao_bmx160_reg_write(BMX160_IF_CONF,
531 (BMX160_IF_CONF_IF_MODE_AUTO_MAG << BMX160_IF_CONF_IF_MODE));
533 /* Enter setup mode */
534 _ao_bmx160_reg_write(BMX160_MAG_IF_0,
535 (1 << BMX160_MAG_IF_0_MAG_MANUAL_EN) |
536 (0 << BMX160_MAG_IF_0_MAG_OFFSET) |
537 (0 << BMX160_MAG_IF_0_MAG_RD_BURST));
539 /* Place in suspend mode to reboot the chip */
540 _ao_bmm150_reg_write(BMM150_POWER_MODE,
541 (0 << BMM150_POWER_MODE_POWER_CONTROL));
544 _ao_bmm150_reg_write(BMM150_POWER_MODE,
545 (1 << BMM150_POWER_MODE_POWER_CONTROL));
547 /* Set data rate and place in sleep mode */
548 _ao_bmm150_reg_write(BMM150_CONTROL,
549 (BMM150_CONTROL_DATA_RATE_30 << BMM150_CONTROL_DATA_RATE) |
550 (BMM150_CONTROL_OP_MODE_SLEEP << BMM150_CONTROL_OP_MODE));
552 /* enable all axes (should already be enabled) */
553 _ao_bmm150_reg_write(BMM150_INT_CONF,
554 (0 << BMM150_INT_CONF_X_DISABLE) |
555 (0 << BMM150_INT_CONF_Y_DISABLE) |
556 (0 << BMM150_INT_CONF_Z_DISABLE));
558 /* Set repetition values (?) */
559 _ao_bmm150_reg_write(BMM150_REPXY, BMM150_REPXY_VALUE(9));
560 _ao_bmm150_reg_write(BMM150_REPZ, BMM150_REPZ_VALUE(15));
562 /* Read Trim values */
563 ao_bmm150_trim.dig_x1 = _ao_bmm150_reg_read(BMM150_DIG_X1);
564 ao_bmm150_trim.dig_y1 = _ao_bmm150_reg_read(BMM150_DIG_Y1);
565 ao_bmm150_trim.dig_z4 = _ao_bmm150_reg_read2(BMM150_DIG_Z4_LSB, BMM150_DIG_Z4_MSB);
566 ao_bmm150_trim.dig_x2 = _ao_bmm150_reg_read(BMM150_DIG_X2);
567 ao_bmm150_trim.dig_y2 = _ao_bmm150_reg_read(BMM150_DIG_Y2);
568 ao_bmm150_trim.dig_z2 = _ao_bmm150_reg_read2(BMM150_DIG_Z2_LSB, BMM150_DIG_Z2_MSB);
569 ao_bmm150_trim.dig_z1 = _ao_bmm150_reg_read2(BMM150_DIG_Z1_LSB, BMM150_DIG_Z1_MSB);
570 ao_bmm150_trim.dig_xyz1 = _ao_bmm150_reg_read2(BMM150_DIG_XYZ1_LSB, BMM150_DIG_XYZ1_MSB);
571 ao_bmm150_trim.dig_z3 = _ao_bmm150_reg_read2(BMM150_DIG_Z3_LSB, BMM150_DIG_Z3_MSB);
572 ao_bmm150_trim.dig_xy2 = _ao_bmm150_reg_read(BMM150_DIG_XY2);
573 ao_bmm150_trim.dig_xy1 = _ao_bmm150_reg_read(BMM150_DIG_XY1);
575 /* To get data out of the magnetometer, set the control op mode to 'forced', then read
576 * from the data registers
578 _ao_bmx160_reg_write(BMX160_MAG_IF_3,
579 (BMM150_CONTROL_DATA_RATE_30 << BMM150_CONTROL_DATA_RATE) |
580 (BMM150_CONTROL_OP_MODE_FORCED << BMM150_CONTROL_OP_MODE));
581 _ao_bmx160_reg_write(BMX160_MAG_IF_2, BMM150_CONTROL);
582 _ao_bmx160_reg_write(BMX160_MAG_IF_1, BMM150_DATA_X_0_4);
584 /* Put magnetometer interface back into 'normal mode'
586 _ao_bmx160_reg_write(BMX160_MAG_IF_0,
587 (0 << BMX160_MAG_IF_0_MAG_MANUAL_EN) |
588 (0 << BMX160_MAG_IF_0_MAG_OFFSET) |
589 (3 << BMX160_MAG_IF_0_MAG_RD_BURST));
591 /* Set data rate to 200Hz */
592 _ao_bmx160_reg_write(BMX160_MAG_CONF,
593 (BMX160_MAG_CONF_MAG_ODR_200 << BMX160_MAG_CONF_MAG_ODR));
595 ao_bmx160_configured = 1;
598 struct ao_bmx160_sample ao_bmx160_current;
603 struct ao_bmx160_sample sample;
605 /* ao_bmx160_init already grabbed the SPI bus and mutex */
611 _ao_bmx160_sample(&sample);
613 ao_arch_block_interrupts();
614 ao_bmx160_current = sample;
615 AO_DATA_PRESENT(AO_DATA_BMX160);
617 ao_arch_release_interrupts();
621 static struct ao_task ao_bmx160_task;
626 printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d Mag: %7d %7d %7d\n",
627 ao_bmx160_current.acc_x,
628 ao_bmx160_current.acc_y,
629 ao_bmx160_current.acc_z,
630 ao_bmx160_current.gyr_x,
631 ao_bmx160_current.gyr_y,
632 ao_bmx160_current.gyr_z,
633 ao_bmx160_current.mag_x,
634 ao_bmx160_current.mag_y,
635 ao_bmx160_current.mag_z);
647 if (ao_cmd_status != ao_cmd_success)
650 val = _ao_bmx160_reg_read(addr);
652 printf("Addr %02x val %02x\n", addr, val);
656 ao_bmx160_write(void)
662 if (ao_cmd_status != ao_cmd_success)
665 if (ao_cmd_status != ao_cmd_success)
667 printf("Addr %02x val %02x\n", addr, val);
669 _ao_bmx160_reg_write(addr, val);
680 if (ao_cmd_status != ao_cmd_success)
683 val = _ao_bmm150_reg_read(addr);
685 printf("Addr %02x val %02x\n", addr, val);
689 ao_bmm150_write(void)
695 if (ao_cmd_status != ao_cmd_success)
698 if (ao_cmd_status != ao_cmd_success)
700 printf("Addr %02x val %02x\n", addr, val);
702 _ao_bmm150_reg_write(addr, val);
706 #endif /* BMX160_TEST */
708 static const struct ao_cmds ao_bmx160_cmds[] = {
709 { ao_bmx160_show, "I\0Show BMX160 status" },
711 { ao_bmx160_read, "R <addr>\0Read BMX160 register" },
712 { ao_bmx160_write, "W <addr> <val>\0Write BMX160 register" },
713 { ao_bmm150_read, "M <addr>\0Read BMM150 register" },
714 { ao_bmm150_write, "N <addr> <val>\0Write BMM150 register" },
722 ao_spi_init_cs(AO_BMX160_SPI_CS_PORT, (1 << AO_BMX160_SPI_CS_PIN));
724 ao_add_task(&ao_bmx160_task, ao_bmx160, "bmx160");
726 /* Pretend to be the bmx160 task. Grab the SPI bus right away and
727 * hold it for the task so that nothing else uses the SPI bus before
728 * we get the I2C mode disabled in the chip
731 ao_cur_task = &ao_bmx160_task;
735 ao_cmd_register(&ao_bmx160_cmds[0]);