PX4 Firmware
PX4 Autopilot Software http://px4.io
ADIS16497.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #include "ADIS16497.hpp"
35 
36 #define DIR_READ 0x00
37 #define DIR_WRITE 0x80
38 
39 // ADIS16497 registers
40 static constexpr uint8_t PAGE_ID = 0x0; // Page identifier
41 
42 // Page 0x00
43 static constexpr uint8_t SYS_E_FLAG = 0x08; // Output, system error flags
44 static constexpr uint8_t DIAG_STS = 0x0A; // Output, self test error flags
45 static constexpr uint8_t BURST_CMD = 0x7C; // Burst-read command
46 static constexpr uint8_t PROD_ID = 0x7E; // Output, product identification
47 
48 // Page 0x03
49 static constexpr uint8_t GLOB_CMD = 0x02; // Control, global commands
50 static constexpr uint8_t FNCTIO_CTRL = 0x06; // Control, I/O pins, functional definitions
51 static constexpr uint8_t GPIO_CTRL = 0x08; // Control, I/O pins, general-purpose
52 static constexpr uint8_t CONFIG = 0x0A; // Control, clock and miscellaneous corrections
53 static constexpr uint8_t DEC_RATE = 0x0C; // Control, output sample rate decimation
54 static constexpr uint8_t NULL_CNFG = 0x0E; // Control, automatic bias correction configuration
55 static constexpr uint8_t SYNC_SCALE = 0x10; // Control, automatic bias correction configuration
56 static constexpr uint8_t RANG_MDL = 0x12; // Measurement range (model-specific) Identifier TODO use this
57 static constexpr uint8_t FILTR_BNK_0 = 0x16; // Filter selection
58 static constexpr uint8_t FILTR_BNK_1 = 0x18; // Filter selection
59 
60 static constexpr uint16_t PROD_ID_ADIS16497 = 0x4071; // ADIS16497 Identification, device number
61 
62 // Stall time between SPI transfers
63 static constexpr uint8_t T_STALL = 2;
64 
65 static constexpr uint32_t ADIS16497_DEFAULT_RATE = 1000;
66 
67 using namespace time_literals;
68 
69 ADIS16497::ADIS16497(int bus, uint32_t device, enum Rotation rotation) :
70  SPI("ADIS16497", nullptr, bus, device, SPIDEV_MODE3, 5000000),
71  ScheduledWorkItem(MODULE_NAME, px4::device_bus_to_wq(get_device_id())),
72  _px4_accel(get_device_id(), ORB_PRIO_MAX, rotation),
73  _px4_gyro(get_device_id(), ORB_PRIO_MAX, rotation),
74  _sample_perf(perf_alloc(PC_ELAPSED, "adis16497: read")),
75  _bad_transfers(perf_alloc(PC_COUNT, "adis16497: bad transfers"))
76 {
77 #ifdef GPIO_SPI1_RESET_ADIS16497
78  // Configure hardware reset line
79  px4_arch_configgpio(GPIO_SPI1_RESET_ADIS16497);
80 #endif // GPIO_SPI1_RESET_ADIS16497
81 
84  _px4_accel.set_scale(1.25f * CONSTANTS_ONE_G / 1000.0f); // accel 1.25 mg/LSB
85 
88  _px4_gyro.set_scale(math::radians(0.025f)); // gyro 0.025 °/sec/LSB
89 }
90 
92 {
93  // make sure we are truly inactive
94  stop();
95 
96  // delete the perf counters
99 }
100 
101 int
103 {
104  // do SPI init (and probe) first
105  if (SPI::init() != OK) {
106  // if probe/setup failed, bail now
107  PX4_DEBUG("SPI setup failed");
108  return PX4_ERROR;
109  }
110 
111  start();
112 
113  return PX4_OK;
114 }
115 
117 {
118 #ifdef GPIO_SPI1_RESET_ADIS16497
119  // Hardware reset
120  px4_arch_gpiowrite(GPIO_SPI1_RESET_ADIS16497, 0);
121 
122  // The RST line must be in a low state for at least 10 μs to ensure a proper reset initiation and recovery.
123  usleep(10_us);
124 
125  px4_arch_gpiowrite(GPIO_SPI1_RESET_ADIS16497, 1);
126 #else
127  // Software reset (global command bit 7)
128  uint8_t value[2] {};
129  value[0] = (1 << 7);
130  write_reg16(PAGE_ID, 0x03);
131  write_reg16(GLOB_CMD, (uint16_t)value[0]);
132 #endif // GPIO_SPI1_RESET_ADIS16497
133 
134  // Reset recovery time
135  usleep(210_ms);
136 
137  // Switch to configuration page
138  write_reg16(PAGE_ID, 0x03);
139 
140  // Functional IO control
141  static constexpr uint16_t FNCTIO_CTRL_DEFAULT = 0x000D;
142 
143  write_reg16(FNCTIO_CTRL, FNCTIO_CTRL_DEFAULT);
144 
145  usleep(340_us);
146 
147  const uint16_t fnctio_ctrl = read_reg16(FNCTIO_CTRL);
148 
149  if (fnctio_ctrl != FNCTIO_CTRL_DEFAULT) {
150  PX4_ERR("Invalid setup, FNCTIO_CTRL=%#X", fnctio_ctrl);
151  return PX4_ERROR;
152  }
153 
154  // Miscellaneous configuration
155  static constexpr uint16_t CONFIG_DEFAULT = 0x00C0;
156 
157  write_reg16(CONFIG, CONFIG_DEFAULT);
158 
159  usleep(45_us);
160 
161  const uint16_t config = read_reg16(CONFIG);
162 
163  if (config != CONFIG_DEFAULT) {
164  PX4_ERR("Invalid setup, CONFIG=%#X", config);
165  return PX4_ERROR;
166  }
167 
168  // Decimation Filter
169  static constexpr uint16_t DEC_RATE_DEFAULT = 0x0003; // 4250/4 = 1062 samples per second
170 
171  write_reg16(DEC_RATE, DEC_RATE_DEFAULT);
172 
173  usleep(340_us);
174 
175  const uint16_t dec_rate = read_reg16(DEC_RATE);
176 
177  if (dec_rate != DEC_RATE_DEFAULT) {
178  PX4_ERR("Invalid setup, DEC_RATE=%#X", dec_rate);
179  return PX4_ERROR;
180  }
181 
182  // Continious bias estimation
183  static constexpr uint16_t NULL_CNFG_DEFAULT = 0x0000; // Disable continious bias estimation
184 
185  write_reg16(NULL_CNFG, NULL_CNFG_DEFAULT);
186 
187  usleep(71_us);
188 
189  const uint16_t null_cnfg = read_reg16(NULL_CNFG);
190 
191  if (null_cnfg != NULL_CNFG_DEFAULT) {
192  PX4_ERR("Invalid setup, NULL_CNFG=%#X", null_cnfg);
193  return PX4_ERROR;
194  }
195 
196  // Bartlett Window FIR Filter
197  static constexpr uint16_t FILTR_BNK_0_SETUP = 0x0000; // Disable FIR filter
198  static constexpr uint16_t FILTR_BNK_1_SETUP = 0x0000; // Disable FIR filter
199 
200  write_reg16(FILTR_BNK_0, FILTR_BNK_0_SETUP);
201  write_reg16(FILTR_BNK_1, FILTR_BNK_1_SETUP);
202 
203  usleep(65_us);
204 
205  const uint16_t filtr_bnk_0 = read_reg16(FILTR_BNK_0);
206 
207  if (filtr_bnk_0 != FILTR_BNK_0_SETUP) {
208  PX4_ERR("Invalid setup, FILTR_BNK_0=%#X", filtr_bnk_0);
209  return PX4_ERROR;
210  }
211 
212  const uint16_t filtr_bnk_1 = read_reg16(FILTR_BNK_1);
213 
214  if (filtr_bnk_1 != FILTR_BNK_1_SETUP) {
215  PX4_ERR("Invalid setup, FILTR_BNK_1=%#X", filtr_bnk_1);
216  return PX4_ERROR;
217  }
218 
219  /*
220  // Save to flash memory (NOTE : Limited cycles!)
221  uint8_t value[2] = {};
222  value[0] = (1 << 3);
223  write_reg16(PAGE_ID, 0x03);
224  write_reg16(GLOB_CMD, (uint16_t)value[0]);
225 
226  // save Recovery Time
227  usleep(1125_ms);
228  */
229 
230  return OK;
231 }
232 
233 int
235 {
236  reset();
237 
238  // read product id (5 attempts)
239  for (int i = 0; i < 5; i++) {
240 
241  // Switch to output page
242  write_reg16(PAGE_ID, 0x00);
243 
244  uint16_t product_id = read_reg16(PROD_ID);
245 
246  if (product_id == PROD_ID_ADIS16497) {
247  PX4_DEBUG("PRODUCT: %X", product_id);
248 
249  if (self_test()) {
250  return PX4_OK;
251 
252  } else {
253  PX4_ERR("probe attempt %d: self test failed, resetting", i);
254  reset();
255  }
256 
257  } else {
258  PX4_ERR("probe attempt %d: read product id failed, resetting", i);
259  reset();
260  }
261  }
262 
263  return -EIO;
264 }
265 
266 bool
268 {
269  // Switch to configuration page
270  write_reg16(PAGE_ID, 0x03);
271 
272  // Self test (globa l command bit 1)
273  uint8_t value[2] {};
274  value[0] = (1 << 1);
275  write_reg16(GLOB_CMD, (uint16_t)value[0]);
276 
277  usleep(20_ms); // Self test time
278 
279  // Switch to output page
280  write_reg16(PAGE_ID, 0x0);
281 
282  // Read SYS_E_FLAG to check overall result
283  uint16_t sys_e_flag = read_reg16(SYS_E_FLAG);
284 
285  if (sys_e_flag != 0) {
286  PX4_ERR("SYS_E_FLAG: %#X", sys_e_flag);
287 
288  // Read DIAG_STS to check per-sensor results
289  uint16_t diag_sts_flag = read_reg16(DIAG_STS);
290 
291  if (diag_sts_flag != 0) {
292  PX4_ERR("DIAG_STS: %#X", diag_sts_flag);
293  }
294 
295  return false;
296  }
297 
298  return true;
299 }
300 
301 uint16_t
303 {
304  uint16_t cmd[1] {};
305 
306  cmd[0] = ((reg | DIR_READ) << 8) & 0xff00;
307  transferhword(cmd, nullptr, 1);
308  up_udelay(T_STALL);
309  transferhword(nullptr, cmd, 1);
310  up_udelay(T_STALL);
311 
312  return cmd[0];
313 }
314 
315 void
316 ADIS16497::write_reg(uint8_t reg, uint8_t val)
317 {
318  uint8_t cmd[2] {};
319  cmd[0] = reg | 0x8;
320  cmd[1] = val;
321  transfer(cmd, cmd, sizeof(cmd));
322 }
323 
324 void
325 ADIS16497::write_reg16(uint8_t reg, uint16_t value)
326 {
327  uint16_t cmd[2] {};
328 
329  cmd[0] = ((reg | DIR_WRITE) << 8) | (0x00ff & value);
330  cmd[1] = (((reg + 0x1) | DIR_WRITE) << 8) | ((0xff00 & value) >> 8);
331 
332  transferhword(cmd, nullptr, 1);
333  up_udelay(T_STALL);
334  transferhword(cmd + 1, nullptr, 1);
335  up_udelay(T_STALL);
336 }
337 
338 void
340 {
341 #ifdef GPIO_SPI1_DRDY1_ADIS16497
342  // Setup data ready on rising edge
343  px4_arch_gpiosetevent(GPIO_SPI1_DRDY1_ADIS16497, true, false, true, &ADIS16497::data_ready_interrupt, this);
344 #else
345  // Make sure we are stopped first
346  stop();
347 
348  // start polling at the specified rate
349  ScheduleOnInterval((1_s / ADIS16497_DEFAULT_RATE), 10000);
350 #endif
351 }
352 
353 void
355 {
356 #ifdef GPIO_SPI1_DRDY1_ADIS16497
357  // Disable data ready callback
358  px4_arch_gpiosetevent(GPIO_SPI1_DRDY1_ADIS16497, false, false, false, nullptr, nullptr);
359 #else
360  ScheduleClear();
361 #endif
362 }
363 
364 int
365 ADIS16497::data_ready_interrupt(int irq, void *context, void *arg)
366 {
367  ADIS16497 *dev = static_cast<ADIS16497 *>(arg);
368 
369  // make another measurement
370  dev->ScheduleNow();
371 
372  return PX4_OK;
373 }
374 
375 void
377 {
378  // make another measurement
379  measure();
380 }
381 
382 int
384 {
386 
387  // Fetch the full set of measurements from the ADIS16497 in one pass (burst read).
388  ADISReport adis_report{};
389  adis_report.cmd = ((BURST_CMD | DIR_READ) << 8) & 0xff00;
390 
391  // ADIS16497 burst report should be 320 bits
392  static_assert(sizeof(adis_report) == (320 / 8), "ADIS16497 report not 320 bits");
393 
394  const hrt_abstime timestamp_sample = hrt_absolute_time();
395 
396  if (OK != transferhword((uint16_t *)&adis_report, ((uint16_t *)&adis_report), sizeof(adis_report) / sizeof(uint16_t))) {
399  return -EIO;
400  }
401 
402  // Check burst ID to make sure the correct SPI speed is being used.
403  // The sensor uses a different burst report format at slower speeds
404  static constexpr uint16_t BURST_ID_DEFAULT = 0xA5A5;
405 
406  if (adis_report.BURST_ID != BURST_ID_DEFAULT) {
407  PX4_DEBUG("BURST_ID: %#X", adis_report.BURST_ID);
408 
411 
412  return -EIO;
413  }
414 
415  // Check all Status/Error Flag Indicators
416  if (adis_report.SYS_E_FLAG != 0) {
417  PX4_DEBUG("SYS_E_FLAG: %#X", adis_report.SYS_E_FLAG);
418 
421 
422  return -EIO;
423  }
424 
425  uint32_t checksum = uint32_t(adis_report.CRC_UPR) << 16 | adis_report.CRC_LWR;
426  uint32_t checksum_calc = crc32((uint16_t *)&adis_report.SYS_E_FLAG, 15);
427 
428  if (checksum != checksum_calc) {
429  PX4_DEBUG("CHECKSUM: %#X vs. calculated: %#X", checksum, checksum_calc);
430 
433 
434  return -EIO;
435  }
436 
437  const uint64_t error_count = perf_event_count(_bad_transfers);
438  _px4_accel.set_error_count(error_count);
439  _px4_gyro.set_error_count(error_count);
440 
441  const float temperature = (int16_t(adis_report.TEMP_OUT) * 0.0125f) + 25.0f; // 1 LSB = 0.0125°C, 0x0000 at 25°C
442  _px4_accel.set_temperature(temperature);
443  _px4_gyro.set_temperature(temperature);
444 
445  // TODO check data counter here to see if we're missing samples/getting repeated samples
446  {
447  float xraw_f = (int32_t(adis_report.X_ACCEL_OUT) << 16 | adis_report.X_ACCEL_LOW) / 65536.0f;
448  float yraw_f = (int32_t(adis_report.Y_ACCEL_OUT) << 16 | adis_report.Y_ACCEL_LOW) / 65536.0f;
449  float zraw_f = (int32_t(adis_report.Z_ACCEL_OUT) << 16 | adis_report.Z_ACCEL_LOW) / 65536.0f;
450  _px4_accel.update(timestamp_sample, xraw_f, yraw_f, zraw_f);
451  }
452 
453  {
454  float xraw_f = (int32_t(adis_report.X_GYRO_OUT) << 16 | adis_report.X_GYRO_LOW) / 65536.0f;
455  float yraw_f = (int32_t(adis_report.Y_GYRO_OUT) << 16 | adis_report.Y_GYRO_LOW) / 65536.0f;
456  float zraw_f = (int32_t(adis_report.Z_GYRO_OUT) << 16 | adis_report.Z_GYRO_LOW) / 65536.0f;
457  _px4_gyro.update(timestamp_sample, xraw_f, yraw_f, zraw_f);
458  }
459 
461 
462  return OK;
463 }
464 
465 void
467 {
470 
473 }
#define DRV_GYR_DEVTYPE_ADIS16497
Definition: drv_sensor.h:115
virtual ~ADIS16497()
Definition: ADIS16497.cpp:91
measure the time elapsed performing an event
Definition: perf_counter.h:56
void set_sample_rate(unsigned rate)
#define DRV_ACC_DEVTYPE_ADIS16497
Definition: drv_sensor.h:114
void print_status()
void update(hrt_abstime timestamp, float x, float y, float z)
#define DIR_READ
Definition: ADIS16497.cpp:36
static constexpr uint8_t SYS_E_FLAG
Definition: ADIS16497.cpp:43
virtual int init()
Definition: ADIS16497.cpp:102
static constexpr uint8_t FNCTIO_CTRL
Definition: ADIS16497.cpp:50
static constexpr uint8_t RANG_MDL
Definition: ADIS16497.cpp:56
Namespace encapsulating all device framework classes, functions and data.
Definition: CDev.cpp:47
count the number of times an event occurs
Definition: perf_counter.h:55
void set_device_type(uint8_t devtype)
static constexpr float CONSTANTS_ONE_G
Definition: geo.h:51
void set_error_count(uint64_t error_count)
static constexpr uint8_t DEC_RATE
Definition: ADIS16497.cpp:53
int reset()
Reset chip.
Definition: ADIS16497.cpp:116
void write_reg(uint8_t reg, uint8_t value)
Definition: ADIS16497.cpp:316
static constexpr uint8_t PROD_ID
Definition: ADIS16497.cpp:46
void update(hrt_abstime timestamp, float x, float y, float z)
static constexpr uint8_t GLOB_CMD
Definition: ADIS16497.cpp:49
uint32_t crc32(const uint16_t *data, size_t len) const
Definition: ADIS16497.hpp:167
void perf_count(perf_counter_t handle)
Count a performance event.
static constexpr uint16_t PROD_ID_ADIS16497
Definition: ADIS16497.cpp:60
void perf_free(perf_counter_t handle)
Free a counter.
void init()
Activates/configures the hardware registers.
void set_temperature(float temperature)
static constexpr uint8_t CONFIG
Definition: ADIS16497.cpp:52
void Run() override
Definition: ADIS16497.cpp:376
void set_sample_rate(unsigned rate)
#define perf_alloc(a, b)
Definition: px4io.h:59
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
constexpr T radians(T degrees)
Definition: Limits.hpp:85
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
perf_counter_t _bad_transfers
Definition: ADIS16497.hpp:105
static constexpr uint8_t FILTR_BNK_0
Definition: ADIS16497.cpp:57
void set_error_count(uint64_t error_count)
void perf_end(perf_counter_t handle)
End a performance event.
static constexpr uint8_t GPIO_CTRL
Definition: ADIS16497.cpp:51
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
Definition: drv_hrt.h:58
static int data_ready_interrupt(int irq, void *context, void *arg)
Definition: ADIS16497.cpp:365
void stop()
Stop automatic measurement.
Definition: ADIS16497.cpp:354
void set_scale(float scale)
#define DIR_WRITE
Definition: ADIS16497.cpp:37
virtual int probe()
Definition: ADIS16497.cpp:234
static constexpr uint8_t NULL_CNFG
Definition: ADIS16497.cpp:54
void set_temperature(float temperature)
int measure()
Fetch measurements from the sensor and update the report buffers.
Definition: ADIS16497.cpp:383
bool self_test()
Definition: ADIS16497.cpp:267
static constexpr uint8_t BURST_CMD
Definition: ADIS16497.cpp:45
static constexpr uint8_t DIAG_STS
Definition: ADIS16497.cpp:44
perf_counter_t _sample_perf
Definition: ADIS16497.hpp:104
void perf_print_counter(perf_counter_t handle)
Print one performance counter to stdout.
uint64_t perf_event_count(perf_counter_t handle)
Return current event_count.
Definition: bst.cpp:62
static constexpr uint8_t PAGE_ID
Definition: ADIS16497.cpp:40
PX4Gyroscope _px4_gyro
Definition: ADIS16497.hpp:102
void print_info()
Definition: ADIS16497.cpp:466
void write_reg16(uint8_t reg, uint16_t value)
Definition: ADIS16497.cpp:325
#define OK
Definition: uavcan_main.cpp:71
static constexpr uint8_t FILTR_BNK_1
Definition: ADIS16497.cpp:58
static constexpr uint8_t SYNC_SCALE
Definition: ADIS16497.cpp:55
void set_scale(float scale)
void set_device_type(uint8_t devtype)
PX4Accelerometer _px4_accel
Definition: ADIS16497.hpp:101
ADIS16497(int bus, uint32_t device, enum Rotation rotation=ROTATION_NONE)
Definition: ADIS16497.cpp:69
static constexpr uint8_t T_STALL
Definition: ADIS16497.cpp:63
void perf_begin(perf_counter_t handle)
Begin a performance event.
static constexpr uint32_t ADIS16497_DEFAULT_RATE
Definition: ADIS16497.cpp:65
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint16_t read_reg16(uint8_t reg)
Definition: ADIS16497.cpp:302
void start()
Start automatic measurement.
Definition: ADIS16497.cpp:339