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_get() ao_spi_get(AO_BMX160_SPI_BUS, AO_SPI_SPEED_8MHz)
28 #define ao_bmx160_spi_put() ao_spi_put(AO_BMX160_SPI_BUS)
30 #define ao_bmx160_spi_start() ao_spi_set_cs(AO_BMX160_SPI_CS_PORT, \
31 (1 << AO_BMX160_SPI_CS_PIN))
33 #define ao_bmx160_spi_end() ao_spi_clr_cs(AO_BMX160_SPI_CS_PORT, \
34 (1 << AO_BMX160_SPI_CS_PIN))
37 _ao_bmx160_reg_write(uint8_t addr, uint8_t value)
39 uint8_t d[2] = { addr, value };
40 ao_bmx160_spi_start();
41 ao_spi_send(d, 2, AO_BMX160_SPI_BUS);
46 _ao_bmx160_read(uint8_t addr, void *data, uint8_t len)
49 ao_bmx160_spi_start();
50 ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
51 ao_spi_recv(data, len, AO_BMX160_SPI_BUS);
56 _ao_bmx160_reg_read(uint8_t addr)
60 ao_bmx160_spi_start();
61 ao_spi_send(&addr, 1, AO_BMX160_SPI_BUS);
62 ao_spi_recv(&value, 1, AO_BMX160_SPI_BUS);
68 _ao_bmx160_cmd(uint8_t cmd)
71 _ao_bmx160_reg_write(BMX160_CMD, cmd);
72 for (i = 0; i < 50; i++) {
74 cmd_read = _ao_bmx160_reg_read(BMX160_CMD);
81 _ao_bmm150_wait_manual(void)
83 while (_ao_bmx160_reg_read(BMX160_STATUS) & (1 << BMX160_STATUS_MAG_MAN_OP))
88 _ao_bmm150_reg_write(uint8_t addr, uint8_t data)
90 _ao_bmx160_reg_write(BMX160_MAG_IF_3, data);
91 _ao_bmx160_reg_write(BMX160_MAG_IF_2, addr);
92 _ao_bmm150_wait_manual();
96 _ao_bmm150_reg_read(uint8_t addr)
98 _ao_bmx160_reg_write(BMX160_MAG_IF_1, addr);
99 _ao_bmm150_wait_manual();
100 uint8_t ret = _ao_bmx160_reg_read(BMX160_DATA_0);
105 _ao_bmm150_reg_read2(uint8_t lo_addr, uint8_t hi_addr)
107 uint8_t lo = _ao_bmm150_reg_read(lo_addr);
108 uint8_t hi = _ao_bmm150_reg_read(hi_addr);
110 return ((uint16_t) hi << 8) | lo;
114 * The compensate functions are taken from the BMM150 sample
115 * driver which has the following copyright:
117 * Copyright (c) 2020 Bosch Sensortec GmbH. All rights reserved.
121 * Redistribution and use in source and binary forms, with or without
122 * modification, are permitted provided that the following conditions are met:
124 * 1. Redistributions of source code must retain the above copyright
125 * notice, this list of conditions and the following disclaimer.
127 * 2. Redistributions in binary form must reproduce the above copyright
128 * notice, this list of conditions and the following disclaimer in the
129 * documentation and/or other materials provided with the distribution.
131 * 3. Neither the name of the copyright holder nor the names of its
132 * contributors may be used to endorse or promote products derived from
133 * this software without specific prior written permission.
135 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
136 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
137 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
138 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
139 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
140 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
141 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
142 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
143 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
144 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
145 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
146 * POSSIBILITY OF SUCH DAMAGE.
155 * @brief This internal API is used to obtain the compensated
156 * magnetometer X axis data(micro-tesla) in int16_t.
158 static int16_t compensate_x(int16_t mag_data_x, uint16_t data_rhall)
161 uint16_t process_comp_x0 = 0;
162 int32_t process_comp_x1;
163 uint16_t process_comp_x2;
164 int32_t process_comp_x3;
165 int32_t process_comp_x4;
166 int32_t process_comp_x5;
167 int32_t process_comp_x6;
168 int32_t process_comp_x7;
169 int32_t process_comp_x8;
170 int32_t process_comp_x9;
171 int32_t process_comp_x10;
173 /* Overflow condition check */
174 if (mag_data_x != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
178 /* Availability of valid data*/
179 process_comp_x0 = data_rhall;
180 //printf("using data_rhall %d\n", data_rhall);
182 else if (ao_bmm150_trim.dig_xyz1 != 0)
184 process_comp_x0 = ao_bmm150_trim.dig_xyz1;
185 //printf("using trim value %d\n", process_comp_x0);
190 //printf("no valid rhall\n");
192 if (process_comp_x0 != 0)
194 /* Processing compensation equations*/
195 process_comp_x1 = ((int32_t)ao_bmm150_trim.dig_xyz1) * 16384;
196 //printf("comp_x1 %d\n", process_comp_x1);
197 process_comp_x2 = ((uint16_t)(process_comp_x1 / process_comp_x0)) - ((uint16_t)0x4000);
198 //printf("comp_x2 %d\n", process_comp_x2);
199 retval = ((int16_t)process_comp_x2);
200 process_comp_x3 = (((int32_t)retval) * ((int32_t)retval));
201 //printf("comp_x3 %d\n", process_comp_x3);
202 process_comp_x4 = (((int32_t)ao_bmm150_trim.dig_xy2) * (process_comp_x3 / 128));
203 //printf("comp_x4 %d\n", process_comp_x4);
204 process_comp_x5 = (int32_t)(((int16_t)ao_bmm150_trim.dig_xy1) * 128);
205 //printf("comp_x5 %d\n", process_comp_x5);
206 process_comp_x6 = ((int32_t)retval) * process_comp_x5;
207 //printf("comp_x6 %d\n", process_comp_x6);
208 process_comp_x7 = (((process_comp_x4 + process_comp_x6) / 512) + ((int32_t)0x100000));
209 //printf("comp_x7 %d\n", process_comp_x7);
210 process_comp_x8 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_x2) + ((int16_t)0xA0)));
211 //printf("comp_x8 %d\n", process_comp_x8);
212 process_comp_x9 = ((process_comp_x7 * process_comp_x8) / 4096);
213 //printf("comp_x9 %d\n", process_comp_x9);
214 process_comp_x10 = ((int32_t)mag_data_x) * process_comp_x9;
215 //printf("comp_x10 %d\n", process_comp_x10);
216 retval = ((int16_t)(process_comp_x10 / 8192));
217 //printf("ret 1 %d\n", retval);
218 retval = (retval + (((int16_t)ao_bmm150_trim.dig_x1) * 8)) / 16;
219 //printf("final %d\n", retval);
223 retval = BMM150_OVERFLOW_OUTPUT;
228 /* Overflow condition */
229 retval = BMM150_OVERFLOW_OUTPUT;
236 * @brief This internal API is used to obtain the compensated
237 * magnetometer Y axis data(micro-tesla) in int16_t.
239 static int16_t compensate_y(int16_t mag_data_y, uint16_t data_rhall)
242 uint16_t process_comp_y0 = 0;
243 int32_t process_comp_y1;
244 uint16_t process_comp_y2;
245 int32_t process_comp_y3;
246 int32_t process_comp_y4;
247 int32_t process_comp_y5;
248 int32_t process_comp_y6;
249 int32_t process_comp_y7;
250 int32_t process_comp_y8;
251 int32_t process_comp_y9;
253 /* Overflow condition check */
254 if (mag_data_y != BMM150_XYAXES_FLIP_OVERFLOW_ADCVAL)
258 /* Availability of valid data*/
259 process_comp_y0 = data_rhall;
261 else if (ao_bmm150_trim.dig_xyz1 != 0)
263 process_comp_y0 = ao_bmm150_trim.dig_xyz1;
269 if (process_comp_y0 != 0)
271 /*Processing compensation equations*/
272 process_comp_y1 = (((int32_t)ao_bmm150_trim.dig_xyz1) * 16384) / process_comp_y0;
273 process_comp_y2 = ((uint16_t)process_comp_y1) - ((uint16_t)0x4000);
274 retval = ((int16_t)process_comp_y2);
275 process_comp_y3 = ((int32_t) retval) * ((int32_t)retval);
276 process_comp_y4 = ((int32_t)ao_bmm150_trim.dig_xy2) * (process_comp_y3 / 128);
277 process_comp_y5 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_xy1) * 128));
278 process_comp_y6 = ((process_comp_y4 + (((int32_t)retval) * process_comp_y5)) / 512);
279 process_comp_y7 = ((int32_t)(((int16_t)ao_bmm150_trim.dig_y2) + ((int16_t)0xA0)));
280 process_comp_y8 = (((process_comp_y6 + ((int32_t)0x100000)) * process_comp_y7) / 4096);
281 process_comp_y9 = (((int32_t)mag_data_y) * process_comp_y8);
282 retval = (int16_t)(process_comp_y9 / 8192);
283 retval = (retval + (((int16_t)ao_bmm150_trim.dig_y1) * 8)) / 16;
287 retval = BMM150_OVERFLOW_OUTPUT;
292 /* Overflow condition*/
293 retval = BMM150_OVERFLOW_OUTPUT;
300 * @brief This internal API is used to obtain the compensated
301 * magnetometer Z axis data(micro-tesla) in int16_t.
303 static int16_t compensate_z(int16_t mag_data_z, uint16_t data_rhall)
306 int16_t process_comp_z0;
307 int32_t process_comp_z1;
308 int32_t process_comp_z2;
309 int32_t process_comp_z3;
310 int16_t process_comp_z4;
312 if (mag_data_z != BMM150_ZAXIS_HALL_OVERFLOW_ADCVAL)
314 if ((ao_bmm150_trim.dig_z2 != 0) && (ao_bmm150_trim.dig_z1 != 0) && (data_rhall != 0) &&
315 (ao_bmm150_trim.dig_xyz1 != 0))
317 /*Processing compensation equations*/
318 process_comp_z0 = ((int16_t)data_rhall) - ((int16_t) ao_bmm150_trim.dig_xyz1);
319 process_comp_z1 = (((int32_t)ao_bmm150_trim.dig_z3) * ((int32_t)(process_comp_z0))) / 4;
320 process_comp_z2 = (((int32_t)(mag_data_z - ao_bmm150_trim.dig_z4)) * 32768);
321 process_comp_z3 = ((int32_t)ao_bmm150_trim.dig_z1) * (((int16_t)data_rhall) * 2);
322 process_comp_z4 = (int16_t)((process_comp_z3 + (32768)) / 65536);
323 retval = ((process_comp_z2 - process_comp_z1) / (ao_bmm150_trim.dig_z2 + process_comp_z4));
325 /* saturate result to +/- 2 micro-tesla */
326 if (retval > BMM150_POSITIVE_SATURATION_Z)
328 retval = BMM150_POSITIVE_SATURATION_Z;
330 else if (retval < BMM150_NEGATIVE_SATURATION_Z)
332 retval = BMM150_NEGATIVE_SATURATION_Z;
335 /* Conversion of LSB to micro-tesla*/
336 retval = retval / 16;
340 retval = BMM150_OVERFLOW_OUTPUT;
345 /* Overflow condition*/
346 retval = BMM150_OVERFLOW_OUTPUT;
349 return (int16_t)retval;
353 _ao_bmx160_sample(struct ao_bmx160_sample *sample)
355 _ao_bmx160_read(BMX160_MAG_X_0_7, sample, sizeof (*sample));
356 #if __BYTE_ORDER != __LITTLE_ENDIAN
357 int i = sizeof (*sample) / 2;
358 uint16_t *d = (uint16_t *) sample;
363 *d++ = (t >> 8) | (t << 8);
366 uint16_t rhall = sample->rhall >> 2;
367 sample->mag_x = compensate_x(sample->mag_x >> 3, rhall);
368 sample->mag_y = compensate_y(sample->mag_y >> 3, rhall);
369 sample->mag_z = compensate_z(sample->mag_z >> 1, rhall);
372 #define G 981 /* in cm/s² */
375 static int16_t /* cm/s² */
376 ao_bmx160_accel(int16_t v)
378 return (int16_t) ((v * (int32_t) (16.0 * 980.665 + 0.5)) / 32767);
381 static int16_t /* deg*10/s */
382 ao_bmx160_gyro(int16_t v)
384 return (int16_t) ((v * (int32_t) 20000) / 32767);
388 ao_bmx160_accel_check(int16_t normal, int16_t test)
390 int16_t diff = test - normal;
392 if (diff < BMX160_ST_ACCEL(16) / 4) {
395 if (diff > BMX160_ST_ACCEL(16) * 4) {
402 ao_bmx160_gyro_check(int16_t normal, int16_t test)
404 int16_t diff = test - normal;
408 if (diff < BMX160_ST_GYRO(2000) / 4) {
411 if (diff > BMX160_ST_GYRO(2000) * 4) {
419 _ao_bmx160_wait_alive(void)
423 /* Wait for the chip to wake up */
424 for (i = 0; i < 30; i++) {
425 ao_delay(AO_MS_TO_TICKS(100));
426 if (_ao_bmx160_reg_read(BMX160_CHIPID) == BMX160_CHIPID_BMX160)
430 ao_panic(AO_PANIC_SELF_TEST_BMX160);
437 _ao_bmx160_setup(void)
441 if (ao_bmx160_configured)
444 /* Dummy read of 0x7f register to enable SPI interface */
445 (void) _ao_bmx160_reg_read(0x7f);
447 /* Make sure the chip is responding */
448 _ao_bmx160_wait_alive();
451 _ao_bmx160_reg_write(BMX160_NV_CONF, 1 << BMX160_NV_CONF_SPI_EN);
453 /* Enable acc and gyr
456 _ao_bmx160_cmd(BMX160_CMD_ACC_SET_PMU_MODE(BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL));
458 for (r = 0; r < 20; r++) {
459 ao_delay(AO_MS_TO_TICKS(100));
460 if (((_ao_bmx160_reg_read(BMX160_PMU_STATUS)
461 >> BMX160_PMU_STATUS_ACC_PMU_STATUS)
462 & BMX160_PMU_STATUS_ACC_PMU_STATUS_MASK)
463 == BMX160_PMU_STATUS_ACC_PMU_STATUS_NORMAL)
470 AO_SENSOR_ERROR(AO_DATA_BMX160);
472 _ao_bmx160_cmd(BMX160_CMD_GYR_SET_PMU_MODE(BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL));
474 for (r = 0; r < 20; r++) {
475 ao_delay(AO_MS_TO_TICKS(100));
476 if (((_ao_bmx160_reg_read(BMX160_PMU_STATUS)
477 >> BMX160_PMU_STATUS_GYR_PMU_STATUS)
478 & BMX160_PMU_STATUS_GYR_PMU_STATUS_MASK)
479 == BMX160_PMU_STATUS_GYR_PMU_STATUS_NORMAL)
486 AO_SENSOR_ERROR(AO_DATA_BMX160);
488 /* Configure accelerometer:
490 * undersampling disabled
492 * 200Hz sampling rate
495 * This yields a 3dB cutoff frequency of 80Hz
497 _ao_bmx160_reg_write(BMX160_ACC_CONF,
498 (0 << BMX160_ACC_CONF_ACC_US) |
499 (BMX160_ACC_CONF_ACC_BWP_NORMAL << BMX160_ACC_CONF_ACC_BWP) |
500 (BMX160_ACC_CONF_ACC_ODR_200 << BMX160_ACC_CONF_ACC_ODR));
501 _ao_bmx160_reg_write(BMX160_ACC_RANGE,
502 BMX160_ACC_RANGE_16G);
504 for (r = 0x3; r <= 0x1b; r++)
505 (void) _ao_bmx160_reg_read(r);
509 * 200Hz sampling rate
513 _ao_bmx160_reg_write(BMX160_GYR_CONF,
514 (BMX160_GYR_CONF_GYR_BWP_NORMAL << BMX160_GYR_CONF_GYR_BWP) |
515 (BMX160_GYR_CONF_GYR_ODR_200 << BMX160_GYR_CONF_GYR_ODR));
516 _ao_bmx160_reg_write(BMX160_GYR_RANGE,
517 BMX160_GYR_RANGE_2000);
520 /* Configure magnetometer:
526 _ao_bmx160_cmd(BMX160_CMD_MAG_IF_SET_PMU_MODE(BMX160_PMU_STATUS_MAG_IF_PMU_STATUS_NORMAL));
528 _ao_bmx160_reg_write(BMX160_IF_CONF,
529 (BMX160_IF_CONF_IF_MODE_AUTO_MAG << BMX160_IF_CONF_IF_MODE));
531 /* Enter setup mode */
532 _ao_bmx160_reg_write(BMX160_MAG_IF_0,
533 (1 << BMX160_MAG_IF_0_MAG_MANUAL_EN) |
534 (0 << BMX160_MAG_IF_0_MAG_OFFSET) |
535 (0 << BMX160_MAG_IF_0_MAG_RD_BURST));
537 /* Place in suspend mode to reboot the chip */
538 _ao_bmm150_reg_write(BMM150_POWER_MODE,
539 (0 << BMM150_POWER_MODE_POWER_CONTROL));
542 _ao_bmm150_reg_write(BMM150_POWER_MODE,
543 (1 << BMM150_POWER_MODE_POWER_CONTROL));
545 /* Set data rate and place in sleep mode */
546 _ao_bmm150_reg_write(BMM150_CONTROL,
547 (BMM150_CONTROL_DATA_RATE_30 << BMM150_CONTROL_DATA_RATE) |
548 (BMM150_CONTROL_OP_MODE_SLEEP << BMM150_CONTROL_OP_MODE));
550 /* enable all axes (should already be enabled) */
551 _ao_bmm150_reg_write(BMM150_INT_CONF,
552 (0 << BMM150_INT_CONF_X_DISABLE) |
553 (0 << BMM150_INT_CONF_Y_DISABLE) |
554 (0 << BMM150_INT_CONF_Z_DISABLE));
556 /* Set repetition values (?) */
557 _ao_bmm150_reg_write(BMM150_REPXY, BMM150_REPXY_VALUE(9));
558 _ao_bmm150_reg_write(BMM150_REPZ, BMM150_REPZ_VALUE(15));
560 /* Read Trim values */
561 ao_bmm150_trim.dig_x1 = _ao_bmm150_reg_read(BMM150_DIG_X1);
562 ao_bmm150_trim.dig_y1 = _ao_bmm150_reg_read(BMM150_DIG_Y1);
563 ao_bmm150_trim.dig_z4 = _ao_bmm150_reg_read2(BMM150_DIG_Z4_LSB, BMM150_DIG_Z4_MSB);
564 ao_bmm150_trim.dig_x2 = _ao_bmm150_reg_read(BMM150_DIG_X2);
565 ao_bmm150_trim.dig_y2 = _ao_bmm150_reg_read(BMM150_DIG_Y2);
566 ao_bmm150_trim.dig_z2 = _ao_bmm150_reg_read2(BMM150_DIG_Z2_LSB, BMM150_DIG_Z2_MSB);
567 ao_bmm150_trim.dig_z1 = _ao_bmm150_reg_read2(BMM150_DIG_Z1_LSB, BMM150_DIG_Z1_MSB);
568 ao_bmm150_trim.dig_xyz1 = _ao_bmm150_reg_read2(BMM150_DIG_XYZ1_LSB, BMM150_DIG_XYZ1_MSB);
569 ao_bmm150_trim.dig_z3 = _ao_bmm150_reg_read2(BMM150_DIG_Z3_LSB, BMM150_DIG_Z3_MSB);
570 ao_bmm150_trim.dig_xy2 = _ao_bmm150_reg_read(BMM150_DIG_XY2);
571 ao_bmm150_trim.dig_xy1 = _ao_bmm150_reg_read(BMM150_DIG_XY1);
573 /* To get data out of the magnetometer, set the control op mode to 'forced', then read
574 * from the data registers
576 _ao_bmx160_reg_write(BMX160_MAG_IF_3,
577 (BMM150_CONTROL_DATA_RATE_30 << BMM150_CONTROL_DATA_RATE) |
578 (BMM150_CONTROL_OP_MODE_FORCED << BMM150_CONTROL_OP_MODE));
579 _ao_bmx160_reg_write(BMX160_MAG_IF_2, BMM150_CONTROL);
580 _ao_bmx160_reg_write(BMX160_MAG_IF_1, BMM150_DATA_X_0_4);
582 /* Put magnetometer interface back into 'normal mode'
584 _ao_bmx160_reg_write(BMX160_MAG_IF_0,
585 (0 << BMX160_MAG_IF_0_MAG_MANUAL_EN) |
586 (0 << BMX160_MAG_IF_0_MAG_OFFSET) |
587 (3 << BMX160_MAG_IF_0_MAG_RD_BURST));
589 /* Set data rate to 200Hz */
590 _ao_bmx160_reg_write(BMX160_MAG_CONF,
591 (BMX160_MAG_CONF_MAG_ODR_200 << BMX160_MAG_CONF_MAG_ODR));
593 ao_bmx160_configured = 1;
596 struct ao_bmx160_sample ao_bmx160_current;
601 struct ao_bmx160_sample sample;
603 /* ao_bmx160_init already grabbed the SPI bus and mutex */
609 _ao_bmx160_sample(&sample);
611 ao_arch_block_interrupts();
612 ao_bmx160_current = sample;
613 AO_DATA_PRESENT(AO_DATA_BMX160);
615 ao_arch_release_interrupts();
619 static struct ao_task ao_bmx160_task;
624 printf ("Accel: %7d %7d %7d Gyro: %7d %7d %7d Mag: %7d %7d %7d\n",
625 ao_bmx160_current.acc_x,
626 ao_bmx160_current.acc_y,
627 ao_bmx160_current.acc_z,
628 ao_bmx160_current.gyr_x,
629 ao_bmx160_current.gyr_y,
630 ao_bmx160_current.gyr_z,
631 ao_bmx160_current.mag_x,
632 ao_bmx160_current.mag_y,
633 ao_bmx160_current.mag_z);
645 if (ao_cmd_status != ao_cmd_success)
648 val = _ao_bmx160_reg_read(addr);
650 printf("Addr %02x val %02x\n", addr, val);
654 ao_bmx160_write(void)
660 if (ao_cmd_status != ao_cmd_success)
663 if (ao_cmd_status != ao_cmd_success)
665 printf("Addr %02x val %02x\n", addr, val);
667 _ao_bmx160_reg_write(addr, val);
678 if (ao_cmd_status != ao_cmd_success)
681 val = _ao_bmm150_reg_read(addr);
683 printf("Addr %02x val %02x\n", addr, val);
687 ao_bmm150_write(void)
693 if (ao_cmd_status != ao_cmd_success)
696 if (ao_cmd_status != ao_cmd_success)
698 printf("Addr %02x val %02x\n", addr, val);
700 _ao_bmm150_reg_write(addr, val);
704 #endif /* BMX160_TEST */
706 static const struct ao_cmds ao_bmx160_cmds[] = {
707 { ao_bmx160_show, "I\0Show BMX160 status" },
709 { ao_bmx160_read, "R <addr>\0Read BMX160 register" },
710 { ao_bmx160_write, "W <addr> <val>\0Write BMX160 register" },
711 { ao_bmm150_read, "M <addr>\0Read BMM150 register" },
712 { ao_bmm150_write, "N <addr> <val>\0Write BMM150 register" },
720 ao_spi_init_cs(AO_BMX160_SPI_CS_PORT, (1 << AO_BMX160_SPI_CS_PIN));
722 ao_add_task(&ao_bmx160_task, ao_bmx160, "bmx160");
724 /* Pretend to be the bmx160 task. Grab the SPI bus right away and
725 * hold it for the task so that nothing else uses the SPI bus before
726 * we get the I2C mode disabled in the chip
729 ao_cur_task = &ao_bmx160_task;
733 ao_cmd_register(&ao_bmx160_cmds[0]);