Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 1 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 13 | #include "motors/driver_station.h" |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 14 | |
| 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 | |
| 31 | namespace frc971 { |
| 32 | namespace motors { |
| 33 | namespace { |
| 34 | |
| 35 | // The HID report descriptor we use. |
| 36 | constexpr 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 | |
| 64 | bool 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 | |
| 76 | uint8_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 | |
| 93 | uint16_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. |
| 105 | uint16_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 | |
| 123 | uint16_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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 141 | int DriverStation::DetermineEncoderValues(ENCODER_DATA_S *enc, |
| 142 | ABS_POSITION_S *absAngle, |
| 143 | int encoderNum, |
| 144 | uint16_t resetTime_ms) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 145 | uint16_t currentAngle = 0; |
| 146 | |
| 147 | if (enc->angle > ENCODER_COUNTS_PER_REV) { |
| 148 | enc->angle = 0; |
| 149 | } |
| 150 | |
| 151 | if (ReadQuadrature(encoderNum, ¤tAngle)) { |
| 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 195 | int DriverStation::MeasureAbsPosition(uint32_t encoder_id, |
| 196 | ABS_POSITION_S *abs_position) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 197 | 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 | |
| 370 | std::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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 443 | void DriverStation::SendJoystickData(teensy::HidFunction *joystick0, |
| 444 | teensy::HidFunction *joystick1, |
| 445 | teensy::HidFunction *joystick2, |
| 446 | uint32_t processor_index) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 447 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 571 | void DriverStation::ZeroMeasurements(MEASUREMENT_DATA_S *bbMeasurements, |
| 572 | uint32_t board) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 573 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 595 | int DriverStation::UpdateMeasurementsFromCAN(MEASUREMENT_DATA_S *bbMeasurements, |
| 596 | uint8_t *canRX_data) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 597 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 639 | void DriverStation::PackMeasurementsToCAN(MEASUREMENT_DATA_S *bbMeasurements, |
| 640 | uint8_t *canTX_data) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 641 | 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 | |
| 661 | extern "C" { |
| 662 | |
| 663 | void *__stack_chk_guard = (void *)0x67111971; |
| 664 | void __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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 707 | void 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 Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 711 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 785 | uint32_t DriverStation::ReadButtons() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 786 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 813 | JoystickAdcReadings DriverStation::AdcReadJoystick(const DisableInterrupts &) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 814 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 840 | void DriverStation::AdcInitJoystick() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 841 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 852 | void DriverStation::EnableLeds() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 853 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 884 | void DriverStation::EnableCan() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 885 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 892 | void DriverStation::EnableEncoders() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 893 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 914 | void DriverStation::EnableQD(LittleFTM *ftm, int encoder) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 915 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 952 | int DriverStation::ReadQuadrature(int encoderNum, uint16_t *encoderAngle) { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 953 | 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 969 | void DriverStation::EnableGlitchFilter() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 970 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 985 | void DriverStation::EnableButtons() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 986 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 1071 | void DriverStation::DisableLeds() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 1072 | // 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 Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 1088 | int DriverStation::Run() { |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 1089 | // 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 | |
| 1194 | extern "C" int main(void) { |
Sindy Tan | fc771aa | 2024-07-19 22:38:43 -0700 | [diff] [blame] | 1195 | frc971::motors::DriverStation driverStation; |
Sindy Tan | 9e89a88 | 2024-06-29 16:13:59 -0700 | [diff] [blame] | 1196 | return driverStation.Run(); |
| 1197 | } |
| 1198 | |
| 1199 | } // namespace motors |
| 1200 | } // namespace frc971 |