2 * Copyright © 2018 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.
16 #include "ao_adxl375.h"
24 #define PRINTD(l, ...) do { if (DEBUG & (l)) { printf ("\r%5lu %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } } while(0)
29 #define AO_ADXL375_SPI_SPEED ao_spi_speed(5000000)
31 struct ao_adxl375_sample ao_adxl375_current;
34 ao_adxl375_start(void) {
35 ao_spi_get_bit(AO_ADXL375_CS_PORT,
38 AO_ADXL375_SPI_SPEED);
42 ao_adxl375_stop(void) {
43 ao_spi_put_bit(AO_ADXL375_CS_PORT,
45 AO_ADXL375_SPI_INDEX);
49 ao_adxl375_reg_read(uint8_t addr)
53 d[0] = addr | AO_ADXL375_READ;
55 ao_spi_send(d, 1, AO_ADXL375_SPI_INDEX);
56 ao_spi_recv(d, 1, AO_ADXL375_SPI_INDEX);
59 PRINTD(DEBUG_LOW, "read %x = %x\n", addr, d[0]);
65 ao_adxl375_reg_write(uint8_t addr, uint8_t value)
69 PRINTD(DEBUG_LOW, "write %x %x\n", addr, value);
73 ao_spi_send(d, 2, AO_ADXL375_SPI_INDEX);
77 d[0] = addr | AO_ADXL375_READ;
79 ao_spi_send(d, 1, AO_ADXL375_SPI_INDEX);
80 ao_spi_recv(d, 1, AO_ADXL375_SPI_INDEX);
82 PRINTD(DEBUG_LOW, "readback %x\n", d[0]);
87 ao_adxl375_value(struct ao_adxl375_sample *value)
91 d[0] = AO_ADXL375_DATAX0 | AO_ADXL375_READ | AO_ADXL375_MULTI_BYTE;
93 ao_spi_send(d, 1, AO_ADXL375_SPI_INDEX);
94 ao_spi_recv(value, 6, AO_ADXL375_SPI_INDEX);
98 struct ao_adxl375_total {
104 #define AO_ADXL375_SELF_TEST_SAMPLES 10
105 #define AO_ADXL375_SELF_TEST_SETTLE 4
107 #define MIN_LSB_G 18.4
108 #define MAX_LSB_G 22.6
109 #define SELF_TEST_MIN_G 5.0
110 #define SELF_TEST_MAX_G 6.8
112 #define MIN_SELF_TEST ((int32_t) (MIN_LSB_G * SELF_TEST_MIN_G * AO_ADXL375_SELF_TEST_SAMPLES + 0.5))
113 #define MAX_SELF_TEST ((int32_t) (MAX_LSB_G * SELF_TEST_MAX_G * AO_ADXL375_SELF_TEST_SAMPLES + 0.5))
116 ao_adxl375_total_value(struct ao_adxl375_total *total, int samples)
118 struct ao_adxl375_sample value;
120 *total = (struct ao_adxl375_total) { 0, 0, 0 };
121 for (int i = 0; i < samples; i++) {
122 ao_adxl375_value(&value);
126 ao_delay(AO_MS_TO_TICKS(10));
130 #define AO_ADXL375_DATA_FORMAT_SETTINGS(self_test) ( \
131 AO_ADXL375_DATA_FORMAT_FIXED | \
132 (self_test << AO_ADXL375_DATA_FORMAT_SELF_TEST) | \
133 (AO_ADXL375_DATA_FORMAT_SPI_4_WIRE << AO_ADXL375_DATA_FORMAT_SPI_4_WIRE) | \
134 (0 << AO_ADXL375_DATA_FORMAT_INT_INVERT) | \
135 (0 << AO_ADXL375_DATA_FORMAT_JUSTIFY))
137 static int32_t self_test_value;
140 ao_adxl375_setup(void)
142 /* Get the device into 4-wire SPI mode before proceeding */
143 ao_adxl375_reg_write(AO_ADXL375_DATA_FORMAT,
144 AO_ADXL375_DATA_FORMAT_SETTINGS(0));
147 uint8_t devid = ao_adxl375_reg_read(AO_ADXL375_DEVID);
148 if (devid != AO_ADXL375_DEVID_ID)
149 AO_SENSOR_ERROR(AO_DATA_ADXL375);
151 /* Set the data rate */
152 ao_adxl375_reg_write(AO_ADXL375_BW_RATE,
153 (0 << AO_ADXL375_BW_RATE_LOW_POWER) |
154 (AO_ADXL375_BW_RATE_RATE_200 << AO_ADXL375_BW_RATE_RATE));
156 /* Set the offsets all to zero */
157 ao_adxl375_reg_write(AO_ADXL375_OFSX, 0);
158 ao_adxl375_reg_write(AO_ADXL375_OFSY, 0);
159 ao_adxl375_reg_write(AO_ADXL375_OFSZ, 0);
161 /* Clear interrupts */
162 ao_adxl375_reg_write(AO_ADXL375_INT_ENABLE, 0);
164 /* Configure FIFO (disable) */
165 ao_adxl375_reg_write(AO_ADXL375_FIFO_CTL,
166 (AO_ADXL375_FIFO_CTL_FIFO_MODE_BYPASS << AO_ADXL375_FIFO_CTL_FIFO_MODE) |
167 (0 << AO_ADXL375_FIFO_CTL_TRIGGER) |
168 (0 << AO_ADXL375_FIFO_CTL_SAMPLES));
170 /* Place part in measurement mode */
171 ao_adxl375_reg_write(AO_ADXL375_POWER_CTL,
172 (0 << AO_ADXL375_POWER_CTL_LINK) |
173 (0 << AO_ADXL375_POWER_CTL_AUTO_SLEEP) |
174 (1 << AO_ADXL375_POWER_CTL_MEASURE) |
175 (0 << AO_ADXL375_POWER_CTL_SLEEP) |
176 (AO_ADXL375_POWER_CTL_WAKEUP_8 << AO_ADXL375_POWER_CTL_WAKEUP));
178 /* Perform self-test */
180 struct ao_adxl375_total self_test_off, self_test_on;
182 /* Discard some samples to let it settle down */
183 ao_adxl375_total_value(&self_test_off, AO_ADXL375_SELF_TEST_SETTLE);
185 /* Get regular values */
186 ao_adxl375_total_value(&self_test_off, AO_ADXL375_SELF_TEST_SAMPLES);
188 /* Turn on self test */
189 ao_adxl375_reg_write(AO_ADXL375_DATA_FORMAT,
190 AO_ADXL375_DATA_FORMAT_SETTINGS(1));
192 /* Discard at least 4 samples to let the device settle */
193 ao_adxl375_total_value(&self_test_on, AO_ADXL375_SELF_TEST_SETTLE);
195 /* Read self test samples */
196 ao_adxl375_total_value(&self_test_on, AO_ADXL375_SELF_TEST_SAMPLES);
198 /* Reset back to normal mode */
200 ao_adxl375_reg_write(AO_ADXL375_DATA_FORMAT,
201 AO_ADXL375_DATA_FORMAT_SETTINGS(0));
203 /* Verify Z axis value is in range */
205 int32_t z_change = self_test_on.z - self_test_off.z;
207 self_test_value = z_change;
209 if (z_change < MIN_SELF_TEST)
210 AO_SENSOR_ERROR(AO_DATA_ADXL375);
212 /* This check is commented out as maximum self test is unreliable
214 if (z_change > MAX_SELF_TEST)
215 AO_SENSOR_ERROR(AO_DATA_ADXL375);
219 /* Discard some samples to let it settle down */
220 ao_adxl375_total_value(&self_test_off, AO_ADXL375_SELF_TEST_SETTLE);
228 ao_adxl375_value(&ao_adxl375_current);
230 AO_DATA_PRESENT(AO_DATA_ADXL375);
236 static struct ao_task ao_adxl375_task;
239 ao_adxl375_dump(void)
241 printf ("ADXL375 value %d %d %d self test %ld min %ld max %ld\n",
242 ao_adxl375_current.x,
243 ao_adxl375_current.y,
244 ao_adxl375_current.z,
245 (long) self_test_value,
246 (long) MIN_SELF_TEST,
247 (long) MAX_SELF_TEST);
250 const struct ao_cmds ao_adxl375_cmds[] = {
251 { ao_adxl375_dump, "A\0Display ADXL375 data" },
256 ao_adxl375_init(void)
258 ao_cmd_register(ao_adxl375_cmds);
259 ao_spi_init_cs(AO_ADXL375_CS_PORT, (1 << AO_ADXL375_CS_PIN));
261 ao_add_task(&ao_adxl375_task, ao_adxl375, "adxl375");