blob: 287caf3caf5975e05f92f9e97da04ae64c0ca701 [file] [log] [blame]
Sindy Tan9e89a882024-06-29 16:13:59 -07001// This file has the main for the Teensy on the button board.
2
3// ButtonBoard is the main outline of how we communicate with the teensy, along
4// with what we tell it to do
5
6// ButtonBoardBB1 and ButtonBoardBB2 only differ in what teensy pins manage what
7// on the pcb
8// teensy (3.5) schematic: https://www.pjrc.com/teensy/schematic.html
9// datasheets for the chip (MK64FX512) used in the teensy:
10// https://www.pjrc.com/teensy/datasheets.html
11// comments (especially on BB2) inform which pins are used
12
Sindy Tanfc771aa2024-07-19 22:38:43 -070013#include "motors/driver_station.h"
Sindy Tan9e89a882024-06-29 16:13:59 -070014
15#include <inttypes.h>
16#include <stdio.h>
17
18#include <atomic>
19#include <cmath>
20
21#include "motors/core/kinetis.h"
22#include "motors/core/time.h"
23#include "motors/peripheral/adc.h"
24#include "motors/peripheral/can.h"
25#include "motors/print/print.h"
26#include "motors/usb/cdc.h"
27#include "motors/usb/hid.h"
28#include "motors/usb/usb.h"
29#include "motors/util.h"
30
31namespace frc971 {
32namespace motors {
33namespace {
34
35// The HID report descriptor we use.
36constexpr char kReportDescriptor1[] = {
37 0x05, 0x01, // Usage Page (Generic Desktop),
38 0x09, 0x04, // Usage (Joystick),
39 0xA1, 0x01, // Collection (Application),
40 0x75, 0x08, // Report Size (8),
41 0x95, 0x05, // Report Count (5),
42 0x15, 0x00, // Logical Minimum (0),
43 0x26, 0xFF, 0x00, // Logical Maximum (255),
44 0x35, 0x00, // Physical Minimum (0),
45 0x46, 0xFF, 0x00, // Physical Maximum (255),
46 0x09, 0x30, // Usage (X),
47 0x09, 0x31, // Usage (Y),
48 0x09, 0x32, // Usage (Z),
49 0x09, 0x33, // Usage (Rx),
50 0x09, 0x34, // Usage (Ry),
51 0x81, 0x02, // Input (Variable),
52 0x75, 0x01, // Report Size (1),
53 0x95, 0x10, // Report Count (16),
54 0x25, 0x01, // Logical Maximum (1),
55 0x45, 0x01, // Physical Maximum (1),
56 0x05, 0x09, // Usage Page (Button),
57 0x19, 0x01, // Usage Minimum (01),
58 0x29, 0x10, // Usage Maximum (16),
59 0x81, 0x02, // Input (Variable),
60 0xC0 // End Collection
61};
62} // namespace
63
64bool IsMyProcessorId(uint32_t id[4]) {
65 uint32_t my_uuid[4] = {SIM_UIDH, SIM_UIDMH, SIM_UIDML, SIM_UIDL};
66
67 for (int byte_index = 0; byte_index < 4; byte_index++) {
68 if (id[byte_index] != my_uuid[byte_index]) {
69 return false;
70 }
71 }
72
73 return true;
74}
75
76uint8_t ProcessorIndex() {
77 static uint32_t kPistolgripProcessorIds[PROCESSOR_ID_COUNT][4] = {
78 {0x00000000, 0x00000000, 0x00000000, 0x00000000},
79 {0x0036FFFF, 0xFFFFFFFF, 0x4E457285,
80 0x60110022}, // One with cable tie labels
81 {0x0035FFFF, 0xFFFFFFFF, 0x4E457285, 0x60130022},
82 };
83
84 for (int i = 0; i < PROCESSOR_ID_COUNT; i++) {
85 if (IsMyProcessorId(kPistolgripProcessorIds[i])) {
86 return i;
87 }
88 }
89
90 return 0;
91}
92
93uint16_t TareEncoder(ENCODER_DATA_S *encoder_data) {
94 return static_cast<uint16_t>((static_cast<uint32_t>(encoder_data->angle) -
95 static_cast<uint32_t>(encoder_data->enc_trim) +
96 0x800) &
97 0xfff);
98}
99
100// Scale and center controller readings.
101//
102// The encoder has a larger range of motion in the + direction than the -
103// direction. We scale the readings so that min (-) maps to 0x0000, max (+) maps
104// to 0xFFFF and the center is at 0x8000.
105uint16_t ScaleEncoder(ENCODER_DATA_S *encoder_data, uint16_t adjusted_angle) {
106 uint16_t result = 0x8000;
107 if (adjusted_angle > 0x800) {
108 const float scaled_angle =
109 static_cast<float>(static_cast<int>(adjusted_angle) - 0x800) /
110 static_cast<float>(encoder_data->enc_max - 0x800);
111 result += std::min<int>(0xffff - 0x8000,
112 static_cast<int>(scaled_angle * (0xffff - 0x8000)));
113 } else {
114 const float scaled_angle =
115 static_cast<float>(static_cast<int>(adjusted_angle) - 0x800) /
116 static_cast<float>(0x800 - encoder_data->enc_min);
117 result -= std::min<int>(0x8000, static_cast<int>(-scaled_angle * 0x8000));
118 }
119
120 return result;
121}
122
123uint16_t filterIIR(uint32_t *filterValue, uint16_t currentValue,
124 uint16_t filterDepth, bool initFilter) {
125 uint32_t localValue = 0;
126
127 if (initFilter) {
128 *filterValue = currentValue << filterDepth;
129 return currentValue;
130 }
131
132 localValue = *filterValue - (*filterValue >> filterDepth);
133
134 localValue += currentValue;
135
136 *filterValue = localValue;
137
138 return localValue >> filterDepth;
139}
140
Sindy Tanfc771aa2024-07-19 22:38:43 -0700141int DriverStation::DetermineEncoderValues(ENCODER_DATA_S *enc,
142 ABS_POSITION_S *absAngle,
143 int encoderNum,
144 uint16_t resetTime_ms) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700145 uint16_t currentAngle = 0;
146
147 if (enc->angle > ENCODER_COUNTS_PER_REV) {
148 enc->angle = 0;
149 }
150
151 if (ReadQuadrature(encoderNum, &currentAngle)) {
152 return -1;
153 }
154
155 if (MeasureAbsPosition(encoderNum, absAngle)) {
156 return -1;
157 }
158
159 if (!absAngle->intialized) {
160 return 0;
161 }
162
163 enc->resetTimer_ms++;
164 if (abs((int)(((currentAngle + enc->offset) & ENCODER_MOD) - enc->angle)) >
165 0) {
166 enc->resetTimer_ms = 0;
167 (void)filterIIR(&(enc->angle_filter), absAngle->dutycycle,
168 ENCODER_FILTER_EXPONENT, true);
169 }
170
171 if (abs((int)(enc->angle - absAngle->dutycycle)) > MAX_FILTER_DELTA &&
172 enc->resetTimer_ms > 0) {
173 (void)filterIIR(&(enc->angle_filter), absAngle->dutycycle,
174 ENCODER_FILTER_EXPONENT, true);
175 }
176
177 if (enc->resetTimer_ms > resetTime_ms) {
178 enc->filtered_duty_cycle =
179 filterIIR(&(enc->angle_filter), absAngle->dutycycle,
180 ENCODER_FILTER_EXPONENT, false);
181 enc->offset =
182 enc->filtered_duty_cycle -
183 currentAngle; /* offset is calculated using filtered abs_position*/
184 enc->offset &= ENCODER_MOD;
185 enc->resetTimer_ms = resetTime_ms;
186 }
187
188 enc->angle = currentAngle + enc->offset;
189
190 enc->angle &= ENCODER_MOD;
191
192 return 0;
193}
194
Sindy Tanfc771aa2024-07-19 22:38:43 -0700195int DriverStation::MeasureAbsPosition(uint32_t encoder_id,
196 ABS_POSITION_S *abs_position) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700197 BigFTM *ftm = NULL;
198 volatile uint32_t *volatile stat_ctrl0 = NULL; // status and control
199 volatile uint32_t *volatile stat_ctrl1 = NULL;
200 volatile uint32_t *volatile channel_val0 = NULL; // channel value
201 volatile uint32_t *volatile channel_val1 = NULL;
202 uint32_t decap_mask = 0;
203 uint32_t decap_enable = 0;
204 uint32_t channel_filter = 0;
205
206 uint32_t initial = 0;
207 uint32_t final = 0;
208
209 switch (encoder_id) {
210 case 0:
211 ftm = FTM3;
212 stat_ctrl0 = &(FTM3_C0SC);
213 stat_ctrl1 = &(FTM3_C1SC);
214 channel_val0 = &(FTM3_C0V);
215 channel_val1 = &(FTM3_C1V);
216 decap_mask = FTM_COMBINE_DECAP0;
217 decap_enable = FTM_COMBINE_DECAPEN0;
218 channel_filter = FTM_FILTER_CH0FVAL(0);
219
220 break;
221 case 1:
222 ftm = FTM0;
223 stat_ctrl0 = &(FTM0_C6SC);
224 stat_ctrl1 = &(FTM0_C7SC);
225 channel_val0 = &(FTM0_C6V);
226 channel_val1 = &(FTM0_C7V);
227 decap_mask = FTM_COMBINE_DECAP3;
228 decap_enable = FTM_COMBINE_DECAPEN3;
229 channel_filter = FTM_FILTER_CH3FVAL(0);
230
231 break;
232
233 default:
234 return -1;
235 break;
236 }
237
238 switch (abs_position->state) {
239 case INIT_ABS:
240 ftm->MODE = FTM_MODE_WPDIS;
241 ftm->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
242
243 ftm->CNTIN = 0;
244 ftm->MOD = 0xFFFF;
245
246 // Disable filters
247 ftm->FILTER = channel_filter;
248
249 ftm->COMBINE = decap_enable;
250 ftm->COMBINE = decap_enable | decap_mask;
251
252 // Use PWM decoding rising and falling edges in CH0 and rising edges only
253 // in CH1.
254 *stat_ctrl0 = FTM_CSC_ELSA;
255 *stat_ctrl1 = FTM_CSC_ELSA;
256 *channel_val0 = 0;
257 *channel_val1 = 0;
258
259 ftm->SYNCONF =
260 FTM_SYNCONF_SWWRBUF /* Software trigger flushes MOD */ |
261 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
262 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
263
264 ftm->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
265
266 // Wait for the software synchronization to finish.
267 while (ftm->SYNC & FTM_SYNC_SWSYNC) {
268 }
269
270 ftm->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
271 FTM_SC_PS(4) /* Prescaler=16 */;
272
273 ftm->MODE &= ~FTM_MODE_WPDIS;
274 abs_position->state = START_PERIOD;
275 break;
276
277 case START_PERIOD:
278 if ((ftm->COMBINE & decap_mask) != decap_mask) {
279 ftm->COMBINE = decap_enable | decap_mask;
280 *stat_ctrl0 = FTM_CSC_ELSA;
281 *stat_ctrl1 = FTM_CSC_ELSA;
282 abs_position->state = WAIT_PERIOD_DONE;
283 }
284 break;
285
286 case WAIT_PERIOD_DONE:
287 initial = *channel_val0;
288 final = *channel_val1;
289 if ((*stat_ctrl0 & FTM_CSC_CHF) && (*stat_ctrl1 & FTM_CSC_CHF)) {
290 // Add 0x10000 to correct for rollover
291 abs_position->period = (final - initial) & 0xFFFF;
292
293 *stat_ctrl0 &= ~FTM_CSC_CHF;
294 *stat_ctrl1 &= ~FTM_CSC_CHF;
295
296 abs_position->state = START_WIDTH;
297 }
298 break;
299
300 case START_WIDTH:
301 if ((ftm->COMBINE & decap_mask) != decap_mask) {
302 ftm->COMBINE = decap_enable | decap_mask;
303 *stat_ctrl0 = FTM_CSC_ELSA;
304 *stat_ctrl1 = FTM_CSC_ELSB;
305 abs_position->state = WAIT_WIDTH_DONE;
306 }
307 break;
308
309 case WAIT_WIDTH_DONE:
310 initial = *channel_val0;
311 final = *channel_val1;
312 if ((*stat_ctrl0 & FTM_CSC_CHF) && (*stat_ctrl1 & FTM_CSC_CHF)) {
313 // Add 0x10000 to correct for rollover
314 abs_position->width = (final - initial) & 0xFFFF;
315
316 *stat_ctrl0 &= ~FTM_CSC_CHF;
317 *stat_ctrl1 &= ~FTM_CSC_CHF;
318
319 if (abs_position->period != 0) {
320 if (((abs_position->width * ENCODER_COUNTS_PER_REV) /
321 abs_position->period) > ENCODER_MOD) {
322 abs_position->state = START_PERIOD;
323 break;
324 }
325
326 // Handle duty cycle out of range. Reset at next reasonable
327 // measurement.
328 if (abs_position->last_erronious_dutycycle ==
329 (abs_position->width * ENCODER_COUNTS_PER_REV) /
330 abs_position->period) {
331 abs_position->dutycycle =
332 (abs_position->width * ENCODER_COUNTS_PER_REV) /
333 abs_position->period;
334
335 abs_position->state = START_PERIOD;
336 break;
337 }
338
339 if (abs((int)((abs_position->width * ENCODER_COUNTS_PER_REV) /
340 abs_position->period) -
341 (int)abs_position->dutycycle) > MAX_DUTY_CYCLE_DELTA) {
342 abs_position->last_erronious_dutycycle =
343 (abs_position->width * ENCODER_COUNTS_PER_REV) /
344 abs_position->period;
345
346 abs_position->state = START_PERIOD;
347 break;
348 }
349
350 abs_position->dutycycle =
351 (abs_position->width * ENCODER_COUNTS_PER_REV) /
352 abs_position->period;
353 abs_position->intialized = true;
354 } else {
355 abs_position->period = 0xFFFF;
356 }
357
358 abs_position->state = START_PERIOD;
359 }
360 break;
361
362 default:
363 return -1;
364 break;
365 }
366
367 return 0;
368}
369
370std::array<ENCODER_DATA_S, 2> MakeEncoderData(uint32_t processor_index) {
371 switch (processor_index) {
372 case 0:
373 default:
374 return {ENCODER_DATA_S{
375 .angle = 0,
376 .offset = 0,
377 .resetTimer_ms = 0,
378 .filtered_duty_cycle = 0,
379 .angle_filter = 0,
380 .enc_trim = 0,
381 .enc_min = 0,
382 .enc_max = 0,
383 },
384 ENCODER_DATA_S{
385 .angle = 0,
386 .offset = 0,
387 .resetTimer_ms = 0,
388 .filtered_duty_cycle = 0,
389 .angle_filter = 0,
390 .enc_trim = 0,
391 .enc_min = 0,
392 .enc_max = 0,
393 }};
394 case 1:
395 // Both enc_min and enc_max should come from the "trimmed" enc print
396 // enc_min should be < 0x7FF and enc_max > 0x800
397 // for encoder 0 they should be ~ +/- 0x050 and encoder 1 ~ +/- 0x700 from
398 // center
399 return {ENCODER_DATA_S{
400 .angle = 0,
401 .offset = 0,
402 .resetTimer_ms = 0,
403 .filtered_duty_cycle = 0,
404 .angle_filter = 0,
405 .enc_trim = 0x0568,
406 .enc_min = 0x0741,
407 .enc_max = 0x08EB,
408 },
409 ENCODER_DATA_S{
410 .angle = 0,
411 .offset = 0,
412 .resetTimer_ms = 0,
413 .filtered_duty_cycle = 0,
414 .angle_filter = 0,
415 .enc_trim = 0x0987,
416 .enc_min = 0x00EA,
417 .enc_max = 0x0FD5,
418 }};
419 case 2:
420 return {ENCODER_DATA_S{
421 .angle = 0,
422 .offset = 0,
423 .resetTimer_ms = 0,
424 .filtered_duty_cycle = 0,
425 .angle_filter = 0,
426 .enc_trim = 0x02CD,
427 .enc_min = 0x0746,
428 .enc_max = 0x0900,
429 },
430 ENCODER_DATA_S{
431 .angle = 0,
432 .offset = 0,
433 .resetTimer_ms = 0,
434 .filtered_duty_cycle = 0,
435 .angle_filter = 0,
436 .enc_trim = 0x0589,
437 .enc_min = 0x00FF,
438 .enc_max = 0x0FC0,
439 }};
440 }
441}
442
Sindy Tanfc771aa2024-07-19 22:38:43 -0700443void DriverStation::SendJoystickData(teensy::HidFunction *joystick0,
444 teensy::HidFunction *joystick1,
445 teensy::HidFunction *joystick2,
446 uint32_t processor_index) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700447 std::array<ENCODER_DATA_S, NUM_ENCODERS> encoder_data =
448 MakeEncoderData(processor_index);
449
450 static ABS_POSITION_S abs_position[NUM_ENCODERS];
451 memset(abs_position, 0, NUM_ENCODERS * sizeof(ABS_POSITION_S));
452
453 uint8_t can_data_out[8] = {0, 0, 0, 0, 0, 0, 0, 0};
454
455 uint8_t can_data_in[8] = {0, 0, 0, 0, 0, 0, 0, 0};
456 static int length = 0;
457
458 MEASUREMENT_DATA_S measurements[BUTTON_BOARD_COUNT];
459
460 uint32_t start = micros();
461 uint16_t can_timer_1 = 0;
462 uint16_t can_timer_2 = 0;
463 while (true) {
464 JoystickAdcReadings adc;
465 char report[3][kReportSize];
466 {
467 DisableInterrupts disable_interrupts;
468 adc = AdcReadJoystick(disable_interrupts);
469 }
470
471 uint16_t tared_encoders[NUM_ENCODERS];
472 for (int i = 0; i < NUM_ENCODERS; i++) {
473 (void)DetermineEncoderValues(&encoder_data[i], &abs_position[i], i,
474 ENCODER_RESET_TIME_MS);
475 tared_encoders[i] = TareEncoder(&encoder_data[i]);
476 }
477
478 measurements[board_config.board_id - 1].buttons = ReadButtons();
479 measurements[board_config.board_id - 1].abs0 = adc.analog0;
480 measurements[board_config.board_id - 1].abs1 = adc.analog1;
481 measurements[board_config.board_id - 1].abs2 = adc.analog2;
482 measurements[board_config.board_id - 1].abs3 = adc.analog3;
483 measurements[board_config.board_id - 1].enc0 =
484 ScaleEncoder(&encoder_data[0], tared_encoders[0]);
485 measurements[board_config.board_id - 1].enc1 =
486 ScaleEncoder(&encoder_data[1], tared_encoders[1]);
487
488#if PRINT_OFFSETS
489 static int counter = 0;
490 counter++;
491
492 if (counter % 100 == 0) {
493 printf(
494 "Processor_ID: 0x%08lX 0x%08lX 0x%08lX 0x%08lX, ENC0 Max: 0x%03X, "
495 "ENC0 Angle: 0x%03X, "
496 "ENC0 Tared: 0x%03X, ENC0 Result: 0x%04X, ENC1 Max: 0x%03X, ENC1 "
497 "Angle: 0x%03X, ENC1 "
498 "Tared: 0x%03X, ENC1 Result: 0x%04X\n\r",
499 SIM_UIDH, SIM_UIDMH, SIM_UIDML, SIM_UIDL, encoder_data[0].enc_max,
500 encoder_data[0].angle, tared_encoders[0], measurements[2].enc0,
501 encoder_data[1].enc_max, encoder_data[1].angle, tared_encoders[1],
502 measurements[2].enc1);
503 }
504#endif
505
506 can_receive(can_data_in, &length, 0);
507
508 if (length == -1) {
509 if (can_timer_1 < 2000) {
510 can_timer_1++;
511 }
512 }
513
514 if (can_timer_1 >= 2000) {
515 ZeroMeasurements(measurements, board_config.can_id0 - 1);
516 }
517
518 if (length == 8) {
519 UpdateMeasurementsFromCAN(measurements, can_data_in);
520 can_timer_1 = 0;
521 }
522
523 can_receive(can_data_in, &length, 1);
524
525 if (length == -1) {
526 if (can_timer_2 < 2000) {
527 can_timer_2++;
528 }
529 }
530
531 if (can_timer_2 >= 2000) {
532 ZeroMeasurements(measurements, board_config.can_id1 - 1);
533 }
534
535 if (length == 8) {
536 UpdateMeasurementsFromCAN(measurements, can_data_in);
537 can_timer_2 = 0;
538 }
539
540 static int counter = 0;
541 counter++;
542
543 if (counter % 100 == 0) {
544 printf("CAN Timer 1: %d, from BB%ld + CAN Timer 2: %d, from BB%ld\n\r",
545 can_timer_1, board_config.can_id0, can_timer_2,
546 board_config.can_id1);
547 printf("Report 1: 0x%04X + Report 2: 0x%04X + Report 3: 0x%04X\n\r",
548 report[0][4], report[1][4], report[2][4]);
549 }
550
551 PackMeasurementsToCAN(&measurements[board_config.board_id - 1],
552 can_data_out);
553
554 can_send(board_config.board_id, can_data_out, sizeof(can_data_out), 2);
555
556 ComposeReport(report, measurements, board_config.board_id,
557 (can_timer_1 >= 2000) ? -1 : board_config.can_id0 - 1,
558 (can_timer_2 >= 2000) ? -1 : board_config.can_id1 - 1);
559
560 {
561 DisableInterrupts disable_interrupts;
562 joystick0->UpdateReport(report[0], sizeof(report[0]), disable_interrupts);
563 joystick1->UpdateReport(report[1], sizeof(report[1]), disable_interrupts);
564 joystick2->UpdateReport(report[2], sizeof(report[2]), disable_interrupts);
565 }
566
567 start = delay_from(start, 1);
568 }
569}
570
Sindy Tanfc771aa2024-07-19 22:38:43 -0700571void DriverStation::ZeroMeasurements(MEASUREMENT_DATA_S *bbMeasurements,
572 uint32_t board) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700573 bbMeasurements[board].buttons = 0;
574 bbMeasurements[board].abs0 = 0;
575 bbMeasurements[board].abs1 = 0;
576 bbMeasurements[board].abs2 = 0;
577 bbMeasurements[board].abs3 = 0;
578 bbMeasurements[board].enc0 = 0;
579 bbMeasurements[board].enc1 = 0;
580}
581
582// clang-format off
583// CAN Packet Format
584// | Bit |
585// Byte 7 6 5 4 3 2 1 0
586// 0 BTN7 BTN6 BTN5 BTN4 BTN3 BTN2 BTN1 BTN0
587// 1 BTN15 BTN14 BTN13 BTN12 BTN11 BTN10 BTN9 BTN8
588// 2 - - - - BTN19 BTN18 BTN17 BTN16
589// 3 ENC0:7 ENC0:6 ENC0:5 ENC0:4 ENC0:3 ENC0_2 ENC0:1 ENC0:0
590// 4 ENC1:3 ENC1:2 ENC1:1 ENC1:0 ENC0:11 ENC0:10 ENC0:9 ENC0:8
591// 5 ENC1:11 ENC1:10 ENC1:9 ENC1:8 ENC1:7 ENC1:6 ENC1:5 ENC1:4
592// 6 ABS2:7 ABS2:6 ABS2:5 ABS2:4 ABS2:3 ABS2:2 ABS2:1 ABS2:0
593// 7 ABS3:7 ABS3:6 ABS3:5 ABS3:4 ABS3:3 ABS3:2 ABS3:1 ABS3:0
594// clang-format on
Sindy Tanfc771aa2024-07-19 22:38:43 -0700595int DriverStation::UpdateMeasurementsFromCAN(MEASUREMENT_DATA_S *bbMeasurements,
596 uint8_t *canRX_data) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700597 int bb_id = 0;
598 uint32_t buttons = 0;
599 uint16_t enc0 = 0;
600 uint16_t enc1 = 0;
601 uint16_t abs2 = 0;
602 uint16_t abs3 = 0;
603
604 // Extract BB_id
605 bb_id = (int)((canRX_data[2] >> 2) & 0x03);
606 bb_id--;
607
608 if (bb_id == -1) {
609 return -1;
610 }
611
612 buttons = (uint32_t)canRX_data[0];
613 buttons |= (uint32_t)canRX_data[1] << 8;
614 buttons |= ((uint32_t)canRX_data[2] & 0x0F) << 16;
615
616 bbMeasurements[bb_id].buttons = buttons;
617
618 enc0 = (uint16_t)canRX_data[3];
619 enc0 |= ((uint16_t)canRX_data[4] & 0x0F) << 8;
620
621 bbMeasurements[bb_id].enc0 = enc0 << 4;
622
623 enc1 = ((uint16_t)canRX_data[4] & 0xF0) >> 4;
624 enc1 |= ((uint16_t)canRX_data[5]) << 4;
625
626 bbMeasurements[bb_id].enc1 = enc1 << 4;
627
628 abs2 = ((uint16_t)canRX_data[6]) << 8;
629
630 bbMeasurements[bb_id].abs2 = abs2;
631
632 abs3 = ((uint16_t)canRX_data[7]) << 8;
633
634 bbMeasurements[bb_id].abs3 = abs3;
635
636 return bb_id;
637}
638
Sindy Tanfc771aa2024-07-19 22:38:43 -0700639void DriverStation::PackMeasurementsToCAN(MEASUREMENT_DATA_S *bbMeasurements,
640 uint8_t *canTX_data) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700641 uint16_t encoder_measurements_0 = bbMeasurements->enc0 >> 4;
642 uint16_t encoder_measurements_1 = bbMeasurements->enc1 >> 4;
643
644 // taking button data
645 canTX_data[2] = (uint8_t)((bbMeasurements->buttons >> 16) & 0x0F);
646 canTX_data[1] = (uint8_t)((bbMeasurements->buttons >> 8) & 0xFF);
647 canTX_data[0] = (uint8_t)(bbMeasurements->buttons & 0xFF);
648
649 // taking encdoer data
650 canTX_data[3] = (uint8_t)(encoder_measurements_0 & 0xFF);
651 canTX_data[4] = (uint8_t)((encoder_measurements_0 >> 8) & 0x0F);
652
653 canTX_data[4] |= (uint8_t)((encoder_measurements_1 & 0x0F) << 4);
654 canTX_data[5] = (uint8_t)((encoder_measurements_1 >> 4) & 0xFF);
655
656 // taking abs data
657 canTX_data[6] = (uint8_t)(bbMeasurements->abs2 >> 8);
658 canTX_data[7] = (uint8_t)(bbMeasurements->abs3 >> 8);
659}
660
661extern "C" {
662
663void *__stack_chk_guard = (void *)0x67111971;
664void __stack_chk_fail(void) {
665 while (true) {
666 GPIOC_PSOR = (1 << 5);
667 printf("Stack corruption detected\n");
668 delay(1000);
669 GPIOC_PCOR = (1 << 5);
670 delay(1000);
671 }
672}
673
674} // extern "C"
675
676// clang-format off
677
678// BB1/BB3 HID BB2 HID
679// HID Word JS0 JS1 JS2 JS3 JS4 JS5
680// 0 AXIS0 BB3:ENC0[15:8] BB3:ENC1[15:8] BB2:ADC0 BB3:ENC0[15:8] BB3:ENC1[15:8] BB2:ADC0
681// 1 AXIS1 0x7F 0x7F BB2:ADC1 0x7F 0x7F BB2:ADC1
682// 2 AXIS2 0x7F 0x7F BB2:ADC2 0x7F 0x7F BB2:ADC2
683// 3 AXIS3 BB3:ENC0[7:0] BB3:ENC1[7:0] BB2:ADC3 BB3:ENC0[7:0] BB3:ENC1[7:0] BB2:ADC3
684// 4 AXIS4[0] BB1 _OK BB1 _OK BB1 _OK BB1 _OK BB1 _OK BB1 _OK
685// 4 AXIS4[1] BB2 _OK BB2 _OK BB2 _OK BB2 _OK BB2 _OK BB2 _OK
686// 4 AXIS4[2] BB3_OK BB3_OK BB3_OK BB3_OK BB3_OK BB3_OK
687// 4 AXIS4[3:4] 0b01 0b10 0b11 0b01 0b10 0b11
688// 4 AXIS4[5] 0 0 0 1 1 1
689// 4 AXIS4[6:7] 0 0 0 0 0 0
690// 5 B0 BB3:B0 BB1:B8 BB2:B4 BB3:B0 BB1:B8 BB2:B4
691// 5 B1 BB3:B1 BB1:B9 BB2:B5 BB3:B1 BB1:B9 BB2:B5
692// 5 B2 BB3:B2 BB1:B10 BB2:B6 BB3:B2 BB1:B10 BB2:B6
693// 5 B3 BB3:B3 BB1:B11 BB2:B7 BB3:B3 BB1:B11 BB2:B7
694// 5 B4 BB3:B4 BB1:B12 BB2:B8 BB3:B4 BB1:B12 BB2:B8
695// 5 B5 BB1:B0 BB1:B13 BB2:B9 BB1:B0 BB1:B13 BB2:B9
696// 5 B6 BB1:B1 BB1:B14 BB2:B10 BB1:B1 BB1:B14 BB2:B10
697// 5 B7 BB1:B2 BB1:B15 BB2:B11 BB1:B2 BB1:B15 BB2:B11
698// 6 B8 BB1:B3 BB1:B16 BB2:B12 BB1:B3 BB1:B16 BB2:B12
699// 6 B9 BB1:B4 BB2:B0 BB2:B13 BB1:B4 BB2:B0 BB2:B13
700// 6 B10 BB1:B5 BB2:B1 BB2:B14 BB1:B5 BB2:B1 BB2:B14
701// 6 B11 BB1:B6 BB2:B2 BB2:B15 BB1:B6 BB2:B2 BB2:B15
702// 6 B12 BB1:B7 BB2:B3 BB2:B16 BB1:B7 BB2:B3 BB2:B16
703// 6 B[14:13] 0b01 0b10 0b11 0b01 0b10 0b11
704// 6 B15 0 0 0 1 1 1
705
706// clang-format on
Sindy Tanfc771aa2024-07-19 22:38:43 -0700707void DriverStation::ComposeReport(char report[][kReportSize],
708 MEASUREMENT_DATA_S *bbMeasurements,
709 uint8_t board_id, int can_1_board,
710 int can_2_board) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700711 memset(report, 0, 3 * sizeof(*report));
712
713 report[0][0] = (char)(bbMeasurements[2].enc0 >> 8 & 0xFF);
714 report[0][1] = (char)((0x7F) & 0xFF);
715 report[0][2] = (char)((0x7F) & 0xFF);
716 report[0][3] = (char)(bbMeasurements[2].enc0 & 0xFF);
717 report[0][4] |= (char)(1 << (board_id - 1));
718 if (can_1_board != -1) {
719 report[0][4] |= (char)(1 << (can_1_board));
720 }
721 if (can_2_board != -1) {
722 report[0][4] |= (char)(1 << (can_2_board));
723 }
724 report[0][4] |= (char)(1 << 3);
725 report[0][5] = (char)(bbMeasurements[2].buttons & 0x1F); // BB1 BTN[7:0]
726 report[0][5] |= (char)((bbMeasurements[0].buttons << 5) & 0xFF);
727 report[0][6] =
728 (char)((bbMeasurements[0].buttons >> 3) & 0x1F); // BB1 BTN[12:8]
729 report[0][6] |= (char)(1 << 5); // BB1 BTN[14:13]
730
731 report[1][0] = (char)(((bbMeasurements[2].enc1) >> 8) & 0xFF);
732 report[1][1] = (char)((0x7F) & 0xFF);
733 report[1][2] = (char)((0x7F) & 0xFF);
734 report[1][3] = (char)((bbMeasurements[2].enc1) & 0xFF);
735 report[1][4] |= (char)(1 << (board_id - 1));
736 if (can_1_board != -1) {
737 report[1][4] |= (char)(1 << (can_1_board));
738 }
739 if (can_2_board != -1) {
740 report[1][4] |= (char)(1 << (can_2_board));
741 }
742 report[1][4] |= (char)(2 << 3);
743 report[1][5] =
744 (char)((bbMeasurements[0].buttons >> 8) & 0xFF); // BB1 BTN[16:13]
745 report[1][6] = (char)((bbMeasurements[1].buttons) & 0x1F); // BB2 BTN[3:0]
746 report[1][6] |= (char)(2 << 5); // BB2 BTN[14:13]
747
748 report[2][0] = (char)((bbMeasurements[1].abs0 >> 8) & 0xFF);
749 report[2][1] = (char)((bbMeasurements[1].abs1 >> 8) & 0xFF);
750 report[2][2] = (char)((bbMeasurements[1].abs2 >> 8) & 0xFF);
751 report[2][3] = (char)((bbMeasurements[1].abs3 >> 8) & 0xFF);
752 report[2][4] |= (char)(1 << (board_id - 1));
753 if (can_1_board != -1) {
754 report[2][4] |= (char)(1 << (can_1_board));
755 }
756 if (can_2_board != -1) {
757 report[2][4] |= (char)(1 << (can_2_board));
758 }
759 report[2][4] |= (char)(3 << 3);
760 report[2][5] =
761 (char)((bbMeasurements[1].buttons >> 5) & 0xFF); // BB2 BTN[8:4]
762 report[2][6] =
763 (char)((bbMeasurements[1].buttons >> 13) & 0x1F); // BB2 BTN[16:9]
764 // report[2][5] = (char)(bbMeasurements[2].buttons & 0x1F); // BB3 BTN[4:0]
765 report[2][6] |= (char)(3 << 5); // BB3 BTN[14:13]
766
767 if (board_id == 2) {
768 report[0][4] |= (char)(1 << 5);
769 report[1][4] |= (char)(1 << 5);
770 report[2][4] |= (char)(1 << 5);
771
772 report[0][6] |= (char)(1 << 7); // BB1 BTN[15]
773 report[1][6] |= (char)(1 << 7); // BB2 BTN[15]
774 report[2][6] |= (char)(1 << 7); // BB3 BTN[15]
775 }
776
777 /*for ( int i = 0; i < 3; i++ ) {
778 printf("Report %d: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X ", i,
779 report[i][0], report[i][1], report[i][2], report[i][3], report[i][4],
780 report[i][5]);
781 }
782 printf("\n\r\n\r");*/
783}
784
Sindy Tanfc771aa2024-07-19 22:38:43 -0700785uint32_t DriverStation::ReadButtons() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700786 uint32_t buttons = 0;
787
788 buttons = ((PERIPHERAL_BITBAND(GPIOD_PDIR, 5) << 0) | // BTN0 PTD5
789 (PERIPHERAL_BITBAND(GPIOC_PDIR, 0) << 1) | // BTN1 PTC0
790 (PERIPHERAL_BITBAND(GPIOB_PDIR, 3) << 2) | // BTN2 PTB3
791 (PERIPHERAL_BITBAND(GPIOB_PDIR, 2) << 3) | // BTN3 PTB2
792 (PERIPHERAL_BITBAND(GPIOA_PDIR, 14) << 4) | // BTN4 PTA14
793 (PERIPHERAL_BITBAND(GPIOE_PDIR, 26) << 5) | // BTN5 PTE26
794 (PERIPHERAL_BITBAND(GPIOA_PDIR, 16) << 6) | // BTN6 PTA16
795 (PERIPHERAL_BITBAND(GPIOA_PDIR, 15) << 7) | // BTN7 PTA15
796 (PERIPHERAL_BITBAND(GPIOE_PDIR, 25) << 8) | // BTN8 PTE25
797 (PERIPHERAL_BITBAND(GPIOA_PDIR, 5) << 9) | // BTN9 PTA5
798 (PERIPHERAL_BITBAND(GPIOC_PDIR, 3) << 10) | // BTN10 PTC3
799 (PERIPHERAL_BITBAND(GPIOC_PDIR, 7) << 11) | // BTN11 PTC7
800 (PERIPHERAL_BITBAND(GPIOD_PDIR, 3) << 12) | // BTN12 PTD3
801 (PERIPHERAL_BITBAND(GPIOD_PDIR, 2) << 13) | // BTN13 PTD2
802 (PERIPHERAL_BITBAND(GPIOD_PDIR, 7) << 14) | // BTN14 PTD7
803 (PERIPHERAL_BITBAND(GPIOB_PDIR, 10) << 15) | // BTN15 PTB10
804 (PERIPHERAL_BITBAND(GPIOB_PDIR, 11) << 16) | // BTN16 PTB11
805 (PERIPHERAL_BITBAND(GPIOD_PDIR, 4) << 17) | // BTN17 PTD4
806 (PERIPHERAL_BITBAND(GPIOB_PDIR, 17) << 18) | // BTN18 PTB17
807 (PERIPHERAL_BITBAND(GPIOB_PDIR, 16) << 19)) ^ // BTN19 PTB16
808 0x000FFFFF;
809
810 return buttons;
811}
812
Sindy Tanfc771aa2024-07-19 22:38:43 -0700813JoystickAdcReadings DriverStation::AdcReadJoystick(const DisableInterrupts &) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700814 JoystickAdcReadings r;
815
816 // ENC1_ABS_ADC (PTE24) ADC0_SE17
817 ADC0_SC1A = 17;
818 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
819 }
820 // ABS2_ADC (PTC1) ADC0_SE15
821 ADC0_SC1A = 15;
822 r.analog1 = ADC0_RA << 4;
823 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
824 }
825 // ABS3_ADC (PTC2) ADC0_SE4b
826 ADC0_SC1A = 4;
827 r.analog2 = ADC0_RA << 4;
828 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
829 }
830 // ENC0_ABS_ADC (PTD1) ADC0_SE5b
831 ADC0_SC1A = 5;
832 r.analog3 = ADC0_RA << 4;
833 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
834 }
835 r.analog0 = ADC0_RA << 4;
836
837 return r;
838}
839
Sindy Tanfc771aa2024-07-19 22:38:43 -0700840void DriverStation::AdcInitJoystick() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700841 AdcInitCommon();
842 // ENC1_ABS_ADC (PTE24) ADC0_SE17
843 PORTE_PCR24 = PORT_PCR_MUX(0);
844 // ABS2_ADC (PTC1) ADC0_SE15
845 PORTC_PCR1 = PORT_PCR_MUX(0);
846 // ABS3_ADC (PTC2) ADC0_SE4b
847 PORTC_PCR2 = PORT_PCR_MUX(0);
848 // ENC0_ABS_ADC (PTD1) ADC0_SE5b
849 PORTD_PCR1 = PORT_PCR_MUX(0);
850}
851
Sindy Tanfc771aa2024-07-19 22:38:43 -0700852void DriverStation::EnableLeds() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700853 // Set all the LED pins to output, drive strength enable (high drive since its
854 // an output), slew rate enable (slow since output) LED (on board) PTC5
855 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 1;
856 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
857 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
858 // LED0R PTC6
859 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
860 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
861 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
862 // LED0Y PTA17
863 PERIPHERAL_BITBAND(GPIOA_PDOR, 17) = 1;
864 PORTA_PCR17 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
865 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 1;
866 // LED0G PTC11
867 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
868 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
869 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
870 // LED1R PTC10
871 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
872 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
873 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
874 // LED1Y PTC4
875 PERIPHERAL_BITBAND(GPIOC_PDOR, 4) = 1;
876 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
877 PERIPHERAL_BITBAND(GPIOC_PDDR, 4) = 1;
878 // LED1G PTC8
879 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
880 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
881 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
882}
883
Sindy Tanfc771aa2024-07-19 22:38:43 -0700884void DriverStation::EnableCan() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700885 // Set up the CAN pins.
886 // (PTA12) CAN0_TX
887 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
888 // (PTA13) CAN0_RX
889 PORTA_PCR13 = PORT_PCR_DSE | PORT_PCR_MUX(2);
890}
891
Sindy Tanfc771aa2024-07-19 22:38:43 -0700892void DriverStation::EnableEncoders() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700893 // Set up the encoder inputs
894 // ENC0_A (PTB18) FTM2_QD_PHA
895 PORTB_PCR18 = PORT_PCR_MUX(6) /*| PORT_PCR_PE | PORT_PCR_PS*/;
896
897 // ENC0_B (PTB19) FTM2_QD_PHB
898 PORTB_PCR19 = PORT_PCR_MUX(6) /*| PORT_PCR_PE | PORT_PCR_PS*/;
899
900 // ENC0_ABS (PTD0) FTM3_CH0
901 PORTD_PCR0 = PORT_PCR_MUX(4) /*| PORT_PCR_PE | PORT_PCR_PS*/;
902
903 // ENC1_A (PTB1) FTM1_QD_PHB
904 PORTB_PCR1 = PORT_PCR_MUX(6) /*| PORT_PCR_PE | PORT_PCR_PS*/;
905
906 // ENC1_B (PTB0) FTM1_QD_PHA
907 PORTB_PCR0 = PORT_PCR_MUX(6) /*| PORT_PCR_PE | PORT_PCR_PS*/;
908
909 // ENC1_ABS (PTD6) FTM0_CH6
910 PORTD_PCR6 = PORT_PCR_MUX(4) /*| PORT_PCR_PE | PORT_PCR_PS*/;
911}
912
913// Enable quadrature encoding.
Sindy Tanfc771aa2024-07-19 22:38:43 -0700914void DriverStation::EnableQD(LittleFTM *ftm, int encoder) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700915 ftm->MODE = FTM_MODE_WPDIS;
916 ftm->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
917
918 ftm->CNTIN = 0;
919 ftm->CNT = 0;
920 ftm->MOD = ENCODER_COUNTS_PER_REV;
921
922 if (encoder == 1) {
923 ftm->QDCTRL = FTM_QDCTRL_PHBPOL;
924 }
925
926 ftm->C0SC = FTM_CSC_ELSA;
927 ftm->C1SC = FTM_CSC_ELSA;
928
929 // Disable filters
930 ftm->FILTER = FTM_FILTER_CH0FVAL(0) | FTM_FILTER_CH1FVAL(0) |
931 FTM_FILTER_CH2FVAL(0) | FTM_FILTER_CH3FVAL(0);
932
933 // Use Quadrature Encoding.
934 ftm->QDCTRL |= FTM_QDCTRL_QUADEN;
935
936 ftm->SYNCONF = FTM_SYNCONF_SWWRBUF /* Software trigger flushes MOD */ |
937 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
938 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
939
940 ftm->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
941
942 // Wait for the software synchronization to finish.
943 while (ftm->SYNC & FTM_SYNC_SWSYNC) {
944 }
945
946 ftm->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
947 FTM_SC_PS(0) /* Prescaler=64 */;
948
949 ftm->MODE &= ~FTM_MODE_WPDIS;
950}
951
Sindy Tanfc771aa2024-07-19 22:38:43 -0700952int DriverStation::ReadQuadrature(int encoderNum, uint16_t *encoderAngle) {
Sindy Tan9e89a882024-06-29 16:13:59 -0700953 switch (encoderNum) {
954 case 0:
955 *encoderAngle = FTM2_CNT;
956 break;
957
958 case 1:
959 *encoderAngle = FTM1_CNT;
960 break;
961
962 default:
963 return -1;
964 break;
965 }
966 return 0;
967}
968
Sindy Tanfc771aa2024-07-19 22:38:43 -0700969void DriverStation::EnableGlitchFilter() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700970 // Enable 1KHz filter clock
971 PORTA_DFCR = 1;
972 PORTB_DFCR = 1;
973 PORTC_DFCR = 1;
974 PORTD_DFCR = 1;
975 PORTE_DFCR = 1;
976 // 10ms filter time
977 PORTA_DFWR = 10;
978 PORTB_DFWR = 10;
979 PORTC_DFWR = 10;
980 PORTD_DFWR = 10;
981 PORTE_DFWR = 10;
982 // TODO: validate the 10ms gitch filter, seems to work
983}
984
Sindy Tanfc771aa2024-07-19 22:38:43 -0700985void DriverStation::EnableButtons() {
Sindy Tan9e89a882024-06-29 16:13:59 -0700986 // Set up the buttons. The LEDs pull them up to 5V, so the Teensy needs to not
987 // be set to pull up.
988 // BTN0 PTD5
989 PORTD_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
990 PORTD_DFER |= 1 << 5;
991
992 // BTN1 PTC0
993 PORTC_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
994 PORTC_DFER |= 1 << 0;
995
996 // BTN2 PTB3
997 PORTB_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
998 PORTB_DFER |= 1 << 3;
999
1000 // BTN3 PTB2
1001 PORTB_PCR2 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1002 PORTB_DFER |= 1 << 2;
1003
1004 // BTN4 PTA14
1005 PORTA_PCR14 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1006 PORTA_DFER |= 1 << 14;
1007
1008 // BTN5 PTE26
1009 PORTE_PCR26 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1010 PORTE_DFER |= 1 << 26;
1011
1012 // BTN6 PTA16
1013 PORTA_PCR16 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1014 PORTA_DFER |= 1 << 16;
1015
1016 // BTN7 PTA15
1017 PORTA_PCR15 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1018 PORTA_DFER |= 1 << 15;
1019
1020 // BTN8 PTE25
1021 PORTE_PCR25 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1022 PORTE_DFER |= 1 << 25;
1023
1024 // BTN9 PTA5
1025 PORTA_PCR5 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1026 PORTA_DFER |= 1 << 5;
1027
1028 // BTN10 PTC3
1029 PORTC_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1030 PORTC_DFER |= 1 << 3;
1031
1032 // BTN11 PTC7
1033 PORTC_PCR7 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1034 PORTC_DFER |= 1 << 7;
1035
1036 // BTN12 PTD3
1037 PORTD_PCR3 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1038 PORTD_DFER |= 1 << 3;
1039
1040 // BTN13 PTD2
1041 PORTD_PCR2 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1042 PORTD_DFER |= 1 << 2;
1043
1044 // BTN14 PTD7
1045 PORTD_PCR7 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1046 PORTD_DFER |= 1 << 7;
1047
1048 // BTN15 PTB10
1049 PORTB_PCR10 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1050 PORTB_DFER |= 1 << 10;
1051
1052 // BTN16 PTB11
1053 PORTB_PCR11 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1054 PORTB_DFER |= 1 << 11;
1055
1056 // BTN17 PTD4
1057 PORTD_PCR4 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1058 PORTD_DFER |= 1 << 4;
1059 (PERIPHERAL_BITBAND(GPIOD_PDIR, 4) =
1060 1); // BTN17 PTD4 is being forced to be an input
1061
1062 // BTN18 PTB17
1063 PORTB_PCR17 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1064 PORTB_DFER |= 1 << 17;
1065
1066 // BTN19 PTB16
1067 PORTB_PCR16 = PORT_PCR_MUX(1) | PORT_PCR_PFE;
1068 PORTB_DFER |= 1 << 16;
1069}
1070
Sindy Tanfc771aa2024-07-19 22:38:43 -07001071void DriverStation::DisableLeds() {
Sindy Tan9e89a882024-06-29 16:13:59 -07001072 // LED (on board) PTC5
1073 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 0;
1074 // LED0R PTC6
1075 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
1076 // LED0Y PTA17
1077 PERIPHERAL_BITBAND(GPIOA_PDOR, 17) = 0;
1078 // LED0G PTC11
1079 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
1080 // LED1R PTC10
1081 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
1082 // LED1Y PTC4
1083 PERIPHERAL_BITBAND(GPIOC_PDOR, 4) = 0;
1084 // LED1G PTC8
1085 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
1086}
1087
Sindy Tanfc771aa2024-07-19 22:38:43 -07001088int DriverStation::Run() {
Sindy Tan9e89a882024-06-29 16:13:59 -07001089 // for background about this startup delay, please see these conversations
1090 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
1091 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
1092 delay(400);
1093
1094 // Set all interrupts to the second-lowest priority to start with.
1095 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
1096
1097 // Now set priorities for all the ones we care about. They only have meaning
1098 // relative to each other, which means centralizing them here makes it a lot
1099 // more manageable.
1100 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
1101
1102 EnableLeds();
1103
1104 EnableGlitchFilter();
1105
1106 EnableCan();
1107
1108 EnableEncoders();
1109
1110 EnableButtons();
1111
1112 delay(100);
1113
1114 teensy::UsbDevice usb_device(0, 0x16c0, 0x0492);
1115 usb_device.SetManufacturer("FRC 971 Spartan Robotics");
1116 usb_device.SetProduct("Spartan Joystick Board");
1117
1118 teensy::HidFunction joystick0(&usb_device, kReportSize);
1119 joystick0.set_report_descriptor(
1120 ::std::string(kReportDescriptor1, sizeof(kReportDescriptor1)));
1121
1122 teensy::HidFunction joystick1(&usb_device, kReportSize);
1123 joystick1.set_report_descriptor(
1124 ::std::string(kReportDescriptor1, sizeof(kReportDescriptor1)));
1125
1126 teensy::HidFunction joystick2(&usb_device, kReportSize);
1127 joystick2.set_report_descriptor(
1128 ::std::string(kReportDescriptor1, sizeof(kReportDescriptor1)));
1129
1130 teensy::AcmTty tty1(&usb_device);
1131 PrintingParameters printing_parameters;
1132 printing_parameters.stdout_tty = &tty1;
1133
1134 const ::std::unique_ptr<PrintingImplementation> printing =
1135 CreatePrinting(printing_parameters);
1136 usb_device.Initialize();
1137 printing->Initialize();
1138
1139 AdcInitJoystick();
1140
1141 EnableQD(FTM1, 1);
1142 EnableQD(FTM2, 0);
1143
1144 // Leave the LEDs on for a bit longer.
1145 delay(300);
1146 printf("Done starting up\n");
1147
1148 // Done starting up, now turn all the LEDs off.
1149 DisableLeds();
1150
1151 board_config.board_id = 0;
1152 board_config.processor_index = 0;
1153 board_config.can_id0 = 0;
1154 board_config.can_id1 = 0;
1155
1156 uint32_t button18 =
1157 PERIPHERAL_BITBAND(GPIOB_PDIR, 17) ^ 0x1; // BTN18 PTB17
1158 uint32_t button19 =
1159 PERIPHERAL_BITBAND(GPIOB_PDIR, 16) ^ 0x1; // BTN19 PTB16
1160
1161 board_config.board_id = (button19 << 1) | button18;
1162
1163 board_config.processor_index = ProcessorIndex();
1164
1165 switch (board_config.board_id) {
1166 case 1:
1167 board_config.can_id0 = 2;
1168 board_config.can_id1 = 3;
1169 break;
1170
1171 case 2:
1172 board_config.can_id0 = 1;
1173 board_config.can_id1 = 3;
1174 break;
1175
1176 case 3:
1177 board_config.can_id0 = 2;
1178 board_config.can_id1 = 1;
1179 break;
1180
1181 default:
1182 board_config.board_id = 0;
1183 break;
1184 }
1185
1186 can_init(board_config.can_id0, board_config.can_id1);
1187
1188 SendJoystickData(&joystick0, &joystick1, &joystick2,
1189 board_config.processor_index);
1190
1191 return 0;
1192}
1193
1194extern "C" int main(void) {
Sindy Tanfc771aa2024-07-19 22:38:43 -07001195 frc971::motors::DriverStation driverStation;
Sindy Tan9e89a882024-06-29 16:13:59 -07001196 return driverStation.Run();
1197}
1198
1199} // namespace motors
1200} // namespace frc971