blob: 0e241012c90950eb5b9d1d3831f0950b1cd86cf8 [file] [log] [blame]
Ravago Jonesb83957c2021-12-29 19:57:34 -08001/**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdio.h>
8
9#include <algorithm>
10#include <cstring>
11
12#include "hardware/dma.h"
13#include "hardware/gpio.h"
14#include "hardware/irq.h"
15#include "hardware/pio.h"
16#include "hardware/pwm.h"
17#include "hardware/spi.h"
18#include "hardware/timer.h"
19#include "pico/binary_info.h"
20#include "pico/bootrom.h"
21#include "pico/double.h"
22#include "pico/stdlib.h"
23#include "quadrature_encoder.pio.h"
24
Adam Snaider13d48d92023-08-03 12:20:15 -070025#pragma GCC diagnostic ignored "-Wformat"
26#pragma GCC diagnostic ignored "-Wformat-extra-args"
27
Ravago Jonesb83957c2021-12-29 19:57:34 -080028// Pinout definitions for the imu
29#define RST_IMU 22
30#define DR_IMU 20
31#define SYNC_IMU 21
32#define DIN_IMU 19
33#define DOUT_IMU 16
34#define SCLK_IMU 18
35#define CS_IMU 17
36
37// Pinout definitions for spi to the pi through the differential drivers
38#define DR_PI 14
39#define MOSI_PI 12
40#define MISO_PI 11
41#define SCK_PI 10
42#define CS_PI 13
43
44// The two drivetrain encoders
45#define ENC1_A 6
46#define ENC1_B 7
47#define ENC2_A 0
48#define ENC2_B 1
49
50// Backup outputs to the roborio
51#define RATE_PWM 2
52#define HEADING_PWM 4
53
54#define PWM_FREQ_HZ 200
55// PWM counts to this before wrapping
56#define PWM_TOP 62499
57
58#define SPI_IMU spi0
59#define SPI_PI spi1
60#define WRITE_BIT 0x8000
61
62// length in half-words of the buffer for communicating with the IMU
63// includes 2 non-data fields
64// the first element is used for recieving zeros while the initial request is
65// made the last element is the checksum
66#define IMU_NUM_ITEMS 17
67
68// length in bytes of the packet to the pi
69#define PI_NUM_ITEMS 42
70
71// number of samples for zeroing the z-gyro axis
72#define YAW_BUF_LEN 5000
73
74#define EXPECTED_PROD_ID 0x4079
75
76// Registers on the ADIS16505
77#define GLOB_CMD 0x68
78#define DIAG_STAT 0x02
79#define FIRM_REV 0x6C
80#define FIRM_DM 0x6E
81#define FIRM_Y 0x70
82#define PROD_ID 0x72
83#define SERIAL_NUM 0x74
84#define FILT_CTRL 0x5C
85#define MSC_CTRL 0x60
86#define DEC_RATE 0x64
87
88// TODO: replace with aos/events/logging/crc32.h
89const uint32_t kCrc32Table[256] = {
90 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
91 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
92 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
93 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
94 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
95 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
96 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
97 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
98 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
99 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
100 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
101 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
102 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
103 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
104 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
105 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
106 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
107 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
108 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
109 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
110 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
111 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
112 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
113 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
114 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
115 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
116 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
117 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
118 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
119 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
120 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
121 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
122 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
123 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
124 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
125 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
126 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
127 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
128 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
129 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
130 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
131 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
132 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
133
134// Buffer to start a burst read and recive 15 items + checksum
135static uint16_t imu_write_buf[IMU_NUM_ITEMS] = {0x6800, 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0};
137// recieves a byte of zeros followed by 15 items + checksum
138static uint16_t imu_data_buffer[IMU_NUM_ITEMS];
139
140static dma_channel_config imu_tx_config;
141static dma_channel_config imu_rx_config;
142static uint imu_dma_tx;
143static uint imu_dma_rx;
144
145// The packet to the pi contains the whole burst read from the IMU (30 bytes)
146// followed by a timestamp, encoder values, and checksum
147// DIAG_STAT, X_GYRO_LOW, X_GYRO_OUT, Y_GYRO_LOW, Y_GYRO_OUT, Z_GYRO_LOW,
148// Z_GYRO_OUT, X_ACCL_LOW, X_ACCL_OUT, Y_ACCL_LOW, Y_ACCL_OUT, Z_ACCL_LOW,
149// Z_ACCL_OUT, TEMP_OUT, DATA_CNTR, TIMESTAMP (32 bit), ENC1_POS, ENC2_POS,
150// CHECKSUM (32-bit)
151
152// the staging buffer gets updated everytime new data is received
153static uint8_t pi_staging_buffer[PI_NUM_ITEMS];
154// the data from the staging buffer is latched into the sending buffer while the
155// pi is reading
156static uint8_t pi_sending_buffer[PI_NUM_ITEMS];
157
158// for now just recieves zeros
159// but is useful because directing the dma to a nullptr messes up the transfer
160// finished interrupt
161static uint8_t pi_recieve_buffer[PI_NUM_ITEMS];
162
163static dma_channel_config pi_tx_config;
164static dma_channel_config pi_rx_config;
165static uint pi_dma_tx;
166static uint pi_dma_rx;
167
Ravago Jones8f9ed852023-03-04 21:36:37 -0800168// yaw velocity from the latest message from the imu
Ravago Jonesb83957c2021-12-29 19:57:34 -0800169static double yaw_rate = 0;
170
Ravago Jonesb83957c2021-12-29 19:57:34 -0800171static int16_t encoder1_count = 0;
172static int16_t encoder2_count = 0;
173
174static uint32_t data_collect_timestamp = 0;
175
Ravago Jones23109002022-02-04 15:50:50 -0800176// if we need to reset the imu
177static bool reset_imu = false;
178// number of consectuive checksums that are mismatched or zero
179static uint suspicious_checksums = 0;
180
Ravago Jonesb83957c2021-12-29 19:57:34 -0800181// useful debug counters
Ravago Jones23109002022-02-04 15:50:50 -0800182static uint imu_reset_count = 0;
183static uint checksum_mismatch_count = 0;
184static uint message_recieved_count = 0;
185static uint message_sent_count = 0;
Ravago Jonesb83957c2021-12-29 19:57:34 -0800186// the number of times we had to defer sending new data because another
187// transfer was still in progress
Ravago Jones23109002022-02-04 15:50:50 -0800188static uint timing_overrun_count = 0;
Ravago Jonesb83957c2021-12-29 19:57:34 -0800189
190// the time it takes from servicing DR_IMU to finishing the transfer to the pi
191static int send_time = 0;
192
193void data_ready();
194void maybe_send_pi_packet();
195
196void gpio_irq_handler(uint gpio, uint32_t events) {
James Kuszmaulc1741012022-02-19 17:49:27 -0800197 if (gpio == SYNC_IMU && (events & GPIO_IRQ_EDGE_RISE)) {
198 // Grab a timestamp for when the data sample was actually collected.
199 data_collect_timestamp = time_us_32();
200 }
Ravago Jonesb83957c2021-12-29 19:57:34 -0800201 if (gpio == DR_IMU && (events & GPIO_IRQ_EDGE_RISE)) {
202 data_ready();
203 }
204}
205
206static inline void cs_select() {
207 gpio_put(CS_IMU, 0); // Active low
208 sleep_us(1);
209}
210
211static inline void cs_deselect() { gpio_put(CS_IMU, 1); }
212
213static uint16_t read_register(uint8_t reg_low) {
214 // For this particular device, we send the device the register we want to read
215 // first, then subsequently read from the device.
216 uint16_t output;
217
218 // The low byte of the register is first in the IMU's memory
219 uint16_t reg = ((uint16_t)reg_low) << 8;
220
221 cs_select();
222 spi_write16_blocking(SPI_IMU, &reg, 1);
223 cs_deselect();
224 sleep_us(20); // wait the stall period
225 cs_select();
226 spi_read16_blocking(SPI_IMU, 0x0000, &output, 1);
227 cs_deselect();
228
229 return output;
230}
231
232static void write_register(uint8_t reg, uint16_t value) {
233 uint16_t low_byte = ((uint16_t)value) & 0xFF;
234 uint16_t high_byte = ((uint16_t)value) >> 8;
235
236 uint16_t command = (((uint16_t)reg) << 8) | low_byte | WRITE_BIT;
237
238 cs_select();
239 spi_write16_blocking(SPI_IMU, &command, 1);
240 cs_deselect();
241
242 sleep_us(20); // wait the stall period
243
244 command = ((((uint16_t)reg) + 1) << 8) | high_byte | WRITE_BIT;
245
246 cs_select();
247 spi_write16_blocking(SPI_IMU, &command, 1);
248 cs_deselect();
249}
250
251static void adis16505_reset() {
252 gpio_put(RST_IMU, 0); // Active low
253 sleep_ms(10);
254 gpio_put(RST_IMU, 1); // Active low
255 sleep_ms(310);
256}
257
258static uint32_t calculate_crc32(uint8_t *data, size_t len) {
259 uint32_t crc = 0xFFFFFFFF;
260 for (size_t i = 0; i < len; i++) {
261 crc = kCrc32Table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
262 }
263 return crc;
264}
265
Ravago Jones23109002022-02-04 15:50:50 -0800266static uint16_t check_checksum(uint16_t *buf) {
Ravago Jonesb83957c2021-12-29 19:57:34 -0800267 uint16_t sum = 0;
268 for (int i = 1; i < IMU_NUM_ITEMS - 1; i++) {
269 uint16_t low = buf[i] & 0xff;
270 uint16_t high = (buf[i] >> 8) & 0xff;
271
272 sum += high + low;
273 }
274
Ravago Jones23109002022-02-04 15:50:50 -0800275 return sum;
Ravago Jonesb83957c2021-12-29 19:57:34 -0800276}
277
Ravago Jonesb83957c2021-12-29 19:57:34 -0800278void pack_pi_packet() {
279 // zero the buffer
280 for (int i = 0; i < PI_NUM_ITEMS; i++) {
281 pi_staging_buffer[i] = 0;
282 }
283
284 // skip empty item
285 uint8_t *imu_packet = (uint8_t *)(imu_data_buffer + 1);
286 // skip empty item and checksum and convert to bytes
287 const size_t imu_packet_len = (IMU_NUM_ITEMS - 2) * sizeof(uint16_t);
288
289 memcpy(pi_staging_buffer, imu_packet, imu_packet_len);
290 memcpy(pi_staging_buffer + imu_packet_len, &data_collect_timestamp, 4);
291 memcpy(pi_staging_buffer + imu_packet_len + 4, &encoder1_count, 2);
292 memcpy(pi_staging_buffer + imu_packet_len + 6, &encoder2_count, 2);
293
294 // exclude the part of the buffer that will be the checksum
295 uint32_t crc = calculate_crc32(pi_staging_buffer, PI_NUM_ITEMS - 4);
296 memcpy(pi_staging_buffer + imu_packet_len + 8, &crc, 4);
297
298 static_assert(PI_NUM_ITEMS == imu_packet_len +
299 sizeof(data_collect_timestamp) +
300 sizeof(encoder1_count) +
301 sizeof(encoder2_count) + sizeof(crc),
302 "PI_NUM_ITEMS needs to be able to hold the imu message + the "
303 "timestamp + the encoders + the checksum");
304}
305
306void data_ready() {
Ravago Jonesb83957c2021-12-29 19:57:34 -0800307 // read encoders
308 quadrature_encoder_request_count(pio0, 0);
309 quadrature_encoder_request_count(pio0, 1);
310
311 cs_select();
312 dma_channel_configure(imu_dma_tx, &imu_tx_config,
313 &spi_get_hw(SPI_IMU)->dr, // write address
314 &imu_write_buf, // read address
315 IMU_NUM_ITEMS, // element count (each element is of
316 // size transfer_data_size)
317 false); // don't start yet
318 dma_channel_configure(imu_dma_rx, &imu_rx_config,
319 &imu_data_buffer, // write address
320 &spi_get_hw(SPI_IMU)->dr, // read address
321 IMU_NUM_ITEMS, // element count (each element is of
322 // size transfer_data_size)
323 false); // don't start yet
324 dma_start_channel_mask((1u << imu_dma_tx) | (1u << imu_dma_rx));
325
326 encoder1_count = quadrature_encoder_fetch_count(pio0, 0);
327 encoder2_count = quadrature_encoder_fetch_count(pio0, 1);
328}
329
330void imu_read_finished() {
331 cs_deselect();
332
333 // TODO: check status and if necessary set flag to reset in main loop
334
335 message_recieved_count++;
Ravago Jones23109002022-02-04 15:50:50 -0800336 uint16_t computed_checksum = check_checksum(imu_data_buffer);
337 uint16_t given_checksum = imu_data_buffer[IMU_NUM_ITEMS - 1];
338
339 if (computed_checksum != given_checksum) {
Ravago Jonesb83957c2021-12-29 19:57:34 -0800340 checksum_mismatch_count++;
Ravago Jones23109002022-02-04 15:50:50 -0800341 for (size_t i = 0; i < IMU_NUM_ITEMS; i++) {
342 // make it clear that this data is bad
343 imu_data_buffer[i] = 0;
344 }
345 // and set an unused bit of DIAG_STAT
346 imu_data_buffer[1] = 1u << 0;
Ravago Jonesb83957c2021-12-29 19:57:34 -0800347 } else {
Ravago Jonesb83957c2021-12-29 19:57:34 -0800348 int32_t z_gyro_out;
349 memcpy(&z_gyro_out, imu_data_buffer + 6, 4);
Ravago Jones8f9ed852023-03-04 21:36:37 -0800350 yaw_rate = (double)z_gyro_out / 655360.0; // degrees
Ravago Jonesb83957c2021-12-29 19:57:34 -0800351
352 // 50% is 0; -2000 deg/sec to 2000 deg/sec
Ravago Jones0e86e242022-02-12 18:38:14 -0800353 double scaled_rate = (std::clamp(yaw_rate, -2000.0, 2000.0) / 4000.0 + 0.5);
Ravago Jonesb83957c2021-12-29 19:57:34 -0800354
Ravago Jones0e86e242022-02-12 18:38:14 -0800355 constexpr double kScaledRangeLow = 0.1;
356 constexpr double kScaledRangeHigh = 0.9;
357
Ravago Jones0e86e242022-02-12 18:38:14 -0800358 uint16_t rate_level =
359 (scaled_rate * (kScaledRangeHigh - kScaledRangeLow) + kScaledRangeLow) *
360 PWM_TOP;
Ravago Jones0e86e242022-02-12 18:38:14 -0800361 pwm_set_gpio_level(RATE_PWM, rate_level);
Ravago Jonesb83957c2021-12-29 19:57:34 -0800362 }
363
Ravago Jones23109002022-02-04 15:50:50 -0800364 // if 5 or more consecutive checksums are zero, then something weird is going
365 // on with the imu
366 if (computed_checksum != given_checksum || computed_checksum == 0 ||
367 given_checksum == 0) {
368 suspicious_checksums++;
369 } else {
370 suspicious_checksums = 0;
371 }
372
373 if (suspicious_checksums >= 5) {
374 reset_imu = true;
375 }
376
377 // fill out message and add it to the queue
378 pack_pi_packet();
379
Ravago Jonesb83957c2021-12-29 19:57:34 -0800380 // TODO: this has a sleep in it
381 // stay in sync with the pi by resetting the spi fifos each transfer
382 spi_init(SPI_PI, 2000 * 1000);
383 spi_set_slave(SPI_PI, true);
384 // these settings were the most stable even though the PI is using
385 // polarity 1 and phase 1
386 spi_set_format(SPI_PI, 8, SPI_CPOL_0, SPI_CPHA_1, SPI_MSB_FIRST);
387
388 maybe_send_pi_packet();
389
390 // clear the interrupt
391 dma_hw->ints0 = 1u << imu_dma_rx;
392}
393
394void maybe_send_pi_packet() {
395 // active low; if the pi isn't connected/booted, this will
396 // also look active
397 bool cs_asserted_or_unplugged = !gpio_get(CS_PI);
398
399 if (cs_asserted_or_unplugged) {
400 // the pi is still recieving something else from us
401 timing_overrun_count++;
402 return;
403 }
404
Ravago Jonesb83957c2021-12-29 19:57:34 -0800405 memcpy(pi_sending_buffer, pi_staging_buffer, PI_NUM_ITEMS);
406
407 dma_channel_configure(pi_dma_tx, &pi_tx_config,
408 &spi_get_hw(SPI_PI)->dr, // write address
409 &pi_sending_buffer, // read address
410 PI_NUM_ITEMS, // element count (each element is
411 // of size transfer_data_size)
412 false); // don't start yet
413 dma_channel_configure(pi_dma_rx, &pi_rx_config,
414 &pi_recieve_buffer, // write address
415 &spi_get_hw(SPI_PI)->dr, // read address
416 PI_NUM_ITEMS, // element count (each element is of
417 // size transfer_data_size)
418 false); // don't start yet
419
420 // start hardware calculation of the CRC-32; currently calculated in software
421 dma_sniffer_enable(pi_dma_tx, 0x0, true);
422 dma_hw->sniff_data = 0;
423
424 // start both at exactly the same time
425 dma_start_channel_mask((1u << pi_dma_tx) | (1u << pi_dma_rx));
Ravago Jones23109002022-02-04 15:50:50 -0800426 gpio_put(DR_PI, 1);
Ravago Jonesb83957c2021-12-29 19:57:34 -0800427}
428
429void pi_transfer_finished() {
430 message_sent_count++;
431 gpio_put(DR_PI, 0);
432
433 send_time = time_us_32() - data_collect_timestamp;
434
435 dma_hw->ints1 = 1u << pi_dma_rx;
436}
437
Ravago Jones23109002022-02-04 15:50:50 -0800438void setup_adis16505() {
James Kuszmaulc1741012022-02-19 17:49:27 -0800439 // Disable the interrupts from the data-ready/sync pins to avoid interrupts
440 // while attempting to reset the IMU.
Ravago Jones23109002022-02-04 15:50:50 -0800441 gpio_set_irq_enabled(DR_IMU, GPIO_IRQ_EDGE_RISE, false);
James Kuszmaulc1741012022-02-19 17:49:27 -0800442 gpio_set_irq_enabled(SYNC_IMU, GPIO_IRQ_EDGE_RISE, false);
Ravago Jones23109002022-02-04 15:50:50 -0800443
444 while (true) {
445 adis16505_reset();
446 // See if SPI is working - interrogate the device for its product ID
447 // number, should be 0x4079
448 uint16_t id = read_register(PROD_ID);
449 if (id == EXPECTED_PROD_ID) {
450 printf("Product id: 0x%04x == expected 0x%04x\n", id, EXPECTED_PROD_ID);
451 break;
452 } else {
453 printf("Got 0x%04x for prod id, expected 0x%04x\ntrying again\n", id,
454 EXPECTED_PROD_ID);
455 }
456 }
457
458 uint16_t firmware_revision = read_register(FIRM_REV);
459 uint16_t firmware_day_month = read_register(FIRM_DM);
460 uint16_t firmware_year = read_register(FIRM_Y);
461 uint16_t serial_number = read_register(SERIAL_NUM);
462
463 printf(
464 "Firmware revision: 0x%04x, \nFirmware day month: 0x%04x, \nFirmware "
465 "year: "
466 "0x%04x, \nSerial number: 0x%04x, \n",
467 firmware_revision, firmware_day_month, firmware_year, serial_number);
468
469 // run self test
470 int num_failures = 0;
471 while (true) {
472 write_register(GLOB_CMD, 1u << 2);
473 sleep_ms(24);
474 uint16_t diag_stat = read_register(DIAG_STAT);
475
476 // check the sensor failure bit
477 bool sensor_failure = diag_stat & (1u << 5);
478 printf("Diag stat: 0b%016b, \n", diag_stat);
479
480 if (sensor_failure) {
481 num_failures++;
482 printf("%d failures, trying again\n", num_failures);
483 } else {
484 break;
485 }
486 }
487
488 write_register(FILT_CTRL, 0 /* no filtering */);
489 write_register(
490 MSC_CTRL,
491 (1u << 9) /* enable 32-bit mode for burst reads */ |
492 (0u << 8) /* send gyro and accelerometer data in burst mode */ |
493 (1u << 7) /* enable gyro linear g compensation */ |
494 (1u << 6) /* enable point of percussion alignment */ |
James Kuszmaulc1741012022-02-19 17:49:27 -0800495 (11u << 2) /* output sync mode (uses internal 2kHz clock) */ |
496 (1u << 1) /* sync polarity, active high */ |
Ravago Jones23109002022-02-04 15:50:50 -0800497 (1u << 0) /* data ready is active high */);
498 // Rate of the output will be 2000 / (DEC_RATE + 1) Hz.
499 write_register(DEC_RATE, 0 /* no decimation */);
500
501 sleep_us(200);
502
503 imu_reset_count++;
504
James Kuszmaulc1741012022-02-19 17:49:27 -0800505 gpio_set_irq_enabled(SYNC_IMU, GPIO_IRQ_EDGE_RISE, true);
Ravago Jones23109002022-02-04 15:50:50 -0800506 gpio_set_irq_enabled_with_callback(DR_IMU, GPIO_IRQ_EDGE_RISE, true,
507 &gpio_irq_handler);
508}
509
Ravago Jonesb83957c2021-12-29 19:57:34 -0800510int main() {
511 stdio_init_all();
512
513 // Use 1MHz with the IMU as that is the limit for burst mode.
514 spi_init(SPI_IMU, 1000 * 1000);
515 spi_set_format(SPI_IMU, 16, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
516 gpio_set_function(DOUT_IMU, GPIO_FUNC_SPI);
517 gpio_set_function(SCLK_IMU, GPIO_FUNC_SPI);
518 gpio_set_function(DIN_IMU, GPIO_FUNC_SPI);
519 // Make the SPI pins available to picotool
520 bi_decl(bi_3pins_with_func(DOUT_IMU, DIN_IMU, SCLK_IMU, GPIO_FUNC_SPI));
521
522 // Chip select is active-low, so we'll initialise it to a driven-high state
523 gpio_init(CS_IMU);
524 gpio_set_dir(CS_IMU, GPIO_OUT);
525 gpio_put(CS_IMU, 1);
526 // Make the CS pin available to picotool
527 bi_decl(bi_1pin_with_name(CS_IMU, "IMU CS"));
528
529 // Reset is active-low, so we'll initialise it to a driven-high state
530 gpio_init(RST_IMU);
531 gpio_set_dir(RST_IMU, GPIO_OUT);
532 gpio_put(RST_IMU, 1);
533 // Make the RST pin available to picotool
534 bi_decl(bi_1pin_with_name(RST_IMU, "IMU RESET"));
535
536 imu_dma_tx = dma_claim_unused_channel(true);
537 imu_dma_rx = dma_claim_unused_channel(true);
538
539 // We set the outbound DMA to transfer from a memory buffer to the SPI
540 // transmit FIFO paced by the SPI TX FIFO DREQ The default is for the read
541 // address to increment every element (in this case 2 bytes - DMA_SIZE_16) and
542 // for the write address to remain unchanged.
543
544 imu_tx_config = dma_channel_get_default_config(imu_dma_tx);
545 channel_config_set_transfer_data_size(&imu_tx_config, DMA_SIZE_16);
546 channel_config_set_dreq(&imu_tx_config, spi_get_dreq(SPI_IMU, true));
547 channel_config_set_read_increment(&imu_tx_config, true);
548 channel_config_set_write_increment(&imu_tx_config, false);
549
550 // We set the inbound DMA to transfer from the SPI receive FIFO to a memory
551 // buffer paced by the SPI RX FIFO DREQ We configure the read address to
552 // remain unchanged for each element, but the write address to increment (so
553 // data is written throughout the buffer)
554 imu_rx_config = dma_channel_get_default_config(imu_dma_rx);
555 channel_config_set_transfer_data_size(&imu_rx_config, DMA_SIZE_16);
556 channel_config_set_dreq(&imu_rx_config, spi_get_dreq(SPI_IMU, false));
557 channel_config_set_read_increment(&imu_rx_config, false);
558 channel_config_set_write_increment(&imu_rx_config, true);
559
560 // Tell the DMA to raise IRQ line 0 when the channel finishes a block
561 dma_channel_set_irq0_enabled(imu_dma_rx, true);
562
563 // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
564 irq_set_exclusive_handler(DMA_IRQ_0, imu_read_finished);
565 irq_set_enabled(DMA_IRQ_0, true);
566
567 // Use 2MHz with the PI as that is the maximum speed for the pico
568 gpio_set_function(MISO_PI, GPIO_FUNC_SPI);
569 gpio_set_function(MOSI_PI, GPIO_FUNC_SPI);
570 gpio_set_function(SCK_PI, GPIO_FUNC_SPI);
571 gpio_set_function(CS_PI, GPIO_FUNC_SPI);
572 // Make the SPI pins available to picotool
573 bi_decl(bi_3pins_with_func(DOUT_IMU, DIN_IMU, SCLK_IMU, GPIO_FUNC_SPI));
574
575 gpio_init(DR_PI);
576 gpio_set_dir(DR_PI, GPIO_OUT);
577 gpio_put(DR_PI, 0);
578 // Make the CS pin available to picotool
579 bi_decl(bi_1pin_with_name(DR_PI, "DATA READY PI"));
580
581 pi_dma_tx = dma_claim_unused_channel(true);
582 pi_dma_rx = dma_claim_unused_channel(true);
583
584 // We set the outbound DMA to transfer from a memory buffer to the SPI
585 // transmit FIFO paced by the SPI TX FIFO DREQ The default is for the read
586 // address to increment every element (in this case 2 bytes - DMA_SIZE_16) and
587 // for the write address to remain unchanged.
588
589 pi_tx_config = dma_channel_get_default_config(pi_dma_tx);
590 channel_config_set_transfer_data_size(&pi_tx_config, DMA_SIZE_8);
591 channel_config_set_dreq(&pi_tx_config, spi_get_dreq(SPI_PI, true));
592 channel_config_set_read_increment(&pi_tx_config, true);
593 channel_config_set_write_increment(&pi_tx_config, false);
594
595 // We set the inbound DMA to transfer from the SPI receive FIFO to a memory
596 // buffer paced by the SPI RX FIFO DREQ We configure the read address to
597 // remain unchanged for each element, but the write address to increment (so
598 // data is written throughout the buffer)
599 pi_rx_config = dma_channel_get_default_config(pi_dma_rx);
600 channel_config_set_transfer_data_size(&pi_rx_config, DMA_SIZE_8);
601 channel_config_set_dreq(&pi_rx_config, spi_get_dreq(SPI_PI, false));
602 channel_config_set_read_increment(&pi_rx_config, false);
603 channel_config_set_write_increment(&pi_rx_config, true);
604
605 // Tell the DMA to raise IRQ line 1 when the channel finishes a block
606 dma_channel_set_irq1_enabled(pi_dma_rx, true);
607
608 // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
609 irq_set_exclusive_handler(DMA_IRQ_1, pi_transfer_finished);
610 irq_set_enabled(DMA_IRQ_1, true);
611
612 /* All IRQ priorities are initialized to PICO_DEFAULT_IRQ_PRIORITY by the pico
James Kuszmaulc1741012022-02-19 17:49:27 -0800613 * runtime at startup. As such, their priorities will correspond to their
614 * IRQ numbers (See Table 80 in the rp2040 datasheet). The interrupts are
615 * listed highest priority to lowest below--i.e., the sync/data ready
616 * interrupts are currently at the lowest priority.
617 * TODO(james): In the nominal case, the GPIO interrupts should never
618 * interfere with the SPI data transfer, but we may still want to up the
619 * GPIO priority using irq_set_priority() so that we are guaranteed good
620 * timestamps.
Ravago Jonesb83957c2021-12-29 19:57:34 -0800621 *
622 * Handler | Interrupt | Cause of interrupt
623 * --------------------|--------------|---------------------------------------
624 * imu_read_finished | DMA_IRQ_0 | When the dma read from the imu is done
625 * pi_transfer_finished| DMA_IRQ_1 | When the dma read to the pi is
626 * done data_ready | IO_IRQ_BANK0 | On the rising edge of DR_IMU
James Kuszmaulc1741012022-02-19 17:49:27 -0800627 * sync pin high | IO_IRQ_BANK0 | On the rising edge of SYNC_IMU
Ravago Jonesb83957c2021-12-29 19:57:34 -0800628 */
629
630 // Tell the GPIOs they are allocated to PWM
631 gpio_set_function(HEADING_PWM, GPIO_FUNC_PWM);
632 gpio_set_function(RATE_PWM, GPIO_FUNC_PWM);
633
634 // Find out which PWM slice is connected to each gpio pin
635 uint heading_slice = pwm_gpio_to_slice_num(HEADING_PWM);
636 uint rate_slice = pwm_gpio_to_slice_num(RATE_PWM);
637
638 /* frequency_pwm = f_sys / ((TOP + 1) * (CSR_PHASE_CORRECT + 1) * (DIV_INT +
639 * DIV_FRAC / 16))
640 *
641 * f_sys = 125 mhz
642 * CSR_PHASE_CORRECT = 0; no phase correct
643 * TARGET_FREQ = 200 hz
644 *
645 * 125 mhz / x = 200 hz * 62500
646 *
647 * TOP = 62499
648 * DIV_INT = 10
649 */
650
651 float divisor = clock_get_hz(clk_sys) / (PWM_TOP + 1) / PWM_FREQ_HZ;
652
653 pwm_config cfg = pwm_get_default_config();
654 pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_FREE_RUNNING);
655 pwm_config_set_clkdiv(&cfg, divisor);
656 pwm_config_set_wrap(&cfg, PWM_TOP);
657
658 pwm_init(heading_slice, &cfg, true);
659 pwm_init(rate_slice, &cfg, true);
660
661 // the two state machine instances use the same program memory from pio0
662 uint offset = pio_add_program(pio0, &quadrature_encoder_program);
663 quadrature_encoder_program_init(pio0, 0, offset, ENC1_A, 0);
664 quadrature_encoder_program_init(pio0, 1, offset, ENC2_A, 0);
665
666 sleep_ms(3 * 1000);
667
668 printf("Hello ADIS16505\n");
669
670 printf(
671 "System clock: %d hz\n"
672 "PWM target frequency: %d hz, PWM clock divisor: "
673 "%f, PWM TOP: %d\n",
674 clock_get_hz(clk_sys), PWM_FREQ_HZ, divisor, PWM_TOP);
675
Ravago Jones23109002022-02-04 15:50:50 -0800676 setup_adis16505();
Ravago Jonesb83957c2021-12-29 19:57:34 -0800677
Ravago Jonesb83957c2021-12-29 19:57:34 -0800678 printf("Press q to enter bootloader\n");
679
680 while (1) {
681 dma_channel_wait_for_finish_blocking(imu_dma_rx);
682 // we want the interrupts to happen before or during the sleep so that we
683 // can get a good picture of what's going on without things moving around
684 sleep_us(100);
685
Ravago Jones23109002022-02-04 15:50:50 -0800686 if (reset_imu) {
687 printf("Triggered IMU reset, resetting\n");
688 setup_adis16505();
689 reset_imu = false;
690 }
691
Ravago Jonesb83957c2021-12-29 19:57:34 -0800692 // debug
693 // one printf is faster than many printfs
694 printf(
Ravago Jones8f9ed852023-03-04 21:36:37 -0800695 "z vel: %f, encoder: %d %d\n"
Ravago Jonesb83957c2021-12-29 19:57:34 -0800696 "Num failed checksums: %d, Total messages recieved: %d,\n"
697 "Num messages to pi: %d, Timing overrun count: %d,\n"
Ravago Jones23109002022-02-04 15:50:50 -0800698 "Send time: %d us, suspicious checksum count: %u,\n"
699 "IMU reset count: %d, checksum: %u,\n",
Ravago Jones8f9ed852023-03-04 21:36:37 -0800700 yaw_rate, encoder1_count, encoder2_count, checksum_mismatch_count,
Ravago Jonesb83957c2021-12-29 19:57:34 -0800701 message_recieved_count, message_sent_count, timing_overrun_count,
Ravago Jones23109002022-02-04 15:50:50 -0800702 send_time, suspicious_checksums, imu_reset_count,
703 imu_data_buffer[IMU_NUM_ITEMS - 1]);
Ravago Jonesb83957c2021-12-29 19:57:34 -0800704
705 // allow the user to enter the bootloader without removing power or having
706 // to install a reset button
707 char user_input = getchar_timeout_us(0);
708 if (user_input == 'q') {
709 printf("Going down! entering bootloader\n");
710 reset_usb_boot(0, 0);
711 }
712
713 sleep_ms(50);
714 }
715
716 printf("All good\n");
717 dma_channel_unclaim(imu_dma_rx);
718 dma_channel_unclaim(imu_dma_tx);
719 dma_channel_unclaim(pi_dma_rx);
720 dma_channel_unclaim(pi_dma_tx);
721 return 0;
722}