blob: d95d4a2b60c8f856c4d184d866bce1d9e775bb39 [file] [log] [blame]
James Kuszmaul998d3032018-09-08 15:41:41 -07001#include "motors/core/kinetis.h"
2
3#include <inttypes.h>
4#include <stdio.h>
5
6#include <atomic>
7
8#include "motors/core/time.h"
9#include "motors/fet12/current_equalization.h"
10#include "motors/fet12/motor_controls.h"
11#include "motors/motor.h"
12#include "motors/peripheral/adc.h"
13#include "motors/peripheral/can.h"
14#include "motors/peripheral/uart.h"
15#include "motors/util.h"
16#include "third_party/GSL/include/gsl/gsl"
17
18namespace frc971 {
19namespace motors {
20namespace {
21
22constexpr double Kv = 22000.0 * 2.0 * M_PI / 60.0 / 30.0 * 3.6;
23constexpr double kVcc = 31.5;
24constexpr double kIcc = 125.0;
25constexpr double kR = 0.0084;
26
27struct Fet12AdcReadings {
28 int16_t motor_currents[3];
29 int16_t throttle, fuse_voltage;
30};
31
32void AdcInitFet12() {
33 AdcInitCommon(AdcChannels::kB, AdcChannels::kA);
34
35 // M_CH0V ADC0_SE5b
36 PORTD_PCR1 = PORT_PCR_MUX(0);
37
38 // M_CH1V ADC0_SE7b
39 PORTD_PCR6 = PORT_PCR_MUX(0);
40
41 // M_CH2V ADC0_SE14
42 PORTC_PCR0 = PORT_PCR_MUX(0);
43
44 // M_CH0F ADC1_SE5a
45 PORTE_PCR1 = PORT_PCR_MUX(0);
46
47 // M_CH1F ADC1_SE6a
48 PORTE_PCR2 = PORT_PCR_MUX(0);
49
50 // M_CH2F ADC1_SE7a
51 PORTE_PCR3 = PORT_PCR_MUX(0);
52
53 // SENSE0 ADC0_SE23
54 // dedicated
55
56 // SENSE1 ADC0_SE13
57 PORTB_PCR3 = PORT_PCR_MUX(0);
58}
59
60Fet12AdcReadings AdcReadFet12(const DisableInterrupts &) {
61 Fet12AdcReadings r;
62
63 ADC1_SC1A = 5;
64 ADC0_SC1A = 23;
65 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
66 }
67 ADC1_SC1A = 6;
68 r.motor_currents[0] = static_cast<int16_t>(ADC1_RA) - 2032;
69 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
70 }
71 ADC0_SC1A = 13;
72 r.throttle = static_cast<int16_t>(ADC0_RA);
73 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
74 }
75 ADC1_SC1A = 7;
76 r.motor_currents[1] = static_cast<int16_t>(ADC1_RA) - 2032;
77 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
78 }
79 r.fuse_voltage = static_cast<int16_t>(ADC0_RA);
80 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
81 }
82 r.motor_currents[2] = static_cast<int16_t>(ADC1_RA) - 2032;
83
84 return r;
85}
86
87::std::atomic<Motor *> global_motor{nullptr};
88::std::atomic<teensy::InterruptBufferedUart *> global_stdout{nullptr};
89
90extern "C" {
91
92void uart0_status_isr(void) {
93 teensy::InterruptBufferedUart *const tty =
94 global_stdout.load(::std::memory_order_relaxed);
95 DisableInterrupts disable_interrupts;
96 tty->HandleInterrupt(disable_interrupts);
97}
98
99void *__stack_chk_guard = (void *)0x67111971;
100void __stack_chk_fail(void) {
101 while (true) {
102 GPIOC_PSOR = (1 << 5);
103 printf("Stack corruption detected\n");
104 delay(1000);
105 GPIOC_PCOR = (1 << 5);
106 delay(1000);
107 }
108}
109
110int _write(int /*file*/, char *ptr, int len) {
111 teensy::InterruptBufferedUart *const tty =
112 global_stdout.load(::std::memory_order_acquire);
113 if (tty != nullptr) {
Brian Silverman12fec3f2018-09-09 16:09:50 -0700114 tty->Write(gsl::make_span(ptr, len));
James Kuszmaul998d3032018-09-08 15:41:41 -0700115 return len;
116 }
117 return 0;
118}
119
120void __stack_chk_fail(void);
121
122extern char *__brkval;
123extern uint32_t __bss_ram_start__[];
124extern uint32_t __heap_start__[];
125extern uint32_t __stack_end__[];
126
127struct DebugBuffer {
128 struct Sample {
129 ::std::array<int16_t, 3> currents;
130 ::std::array<int16_t, 3> commanded_currents;
131 ::std::array<uint16_t, 3> commands;
132 uint16_t position;
133 // Driver requested current.
134 float driver_request;
135 // Requested current.
136 int16_t total_command;
137
138 float est_omega;
139 float fuse_voltage;
140 int16_t fuse_current;
141
142 float fuse_badness;
143 uint32_t cycles_since_start;
144 };
145
146 // The amount of data in the buffer. This will never decrement. This will be
147 // transferred out the serial port after it fills up.
148 ::std::atomic<size_t> size{0};
149 ::std::atomic<uint32_t> count{0};
150 // The data.
151 ::std::array<Sample, 512> samples;
152};
153
154DebugBuffer global_debug_buffer;
155
156void ftm0_isr(void) {
157 const auto wrapped_encoder =
158 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
159 Fet12AdcReadings adc_readings;
160 {
161 DisableInterrupts disable_interrupts;
162 adc_readings = AdcReadFet12(disable_interrupts);
163 }
164 const ::std::array<float, 3> decoupled =
165 DecoupleCurrents(adc_readings.motor_currents);
166
167 const BalancedReadings balanced =
168 BalanceSimpleReadings(decoupled);
169
170 static int i = 0;
171 static float fuse_badness = 0;
172
173 static uint32_t cycles_since_start = 0u;
174 ++cycles_since_start;
175#if 0
176 static int count = 0;
177 ++count;
178 static float currents[3] = {0.0f, 0.0f, 0.0f};
179 for (int ii = 0; ii < 3; ++ii) {
180 currents[ii] += static_cast<float>(adc_readings.motor_currents[ii]);
181 }
182
183 if (i == 0) {
184 printf(
185 "foo %d.0, %d.0, %d.0, %.3d %.3d %.3d, switching %d %d %d enc %d\n",
186 static_cast<int>(currents[0] / static_cast<float>(count)),
187 static_cast<int>(currents[1] / static_cast<float>(count)),
188 static_cast<int>(currents[2] / static_cast<float>(count)),
189 static_cast<int>(decoupled[0] * 1.0f),
190 static_cast<int>(decoupled[1] * 1.0f),
191 static_cast<int>(decoupled[2] * 1.0f),
192 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0),
193 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1),
194 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2),
195 static_cast<int>(
196 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder()));
197 count = 0;
198 currents[0] = 0.0f;
199 currents[1] = 0.0f;
200 currents[2] = 0.0f;
201 }
202#endif
203#if 1
204 constexpr float kAlpha = 0.995f;
205 constexpr float kFuseAlpha = 0.95f;
206
207 // 3400 - 760
208 static float filtered_throttle = 0.0f;
209 constexpr int kMaxThrottle = 3400;
210 constexpr int kMinThrottle = 760;
211 const float throttle = ::std::max(
212 0.0f,
213 ::std::min(1.0f,
214 static_cast<float>(static_cast<int>(adc_readings.throttle) -
215 kMinThrottle) /
216 static_cast<float>(kMaxThrottle - kMinThrottle)));
217
218 // y(n) = x(n) + a * (y(n-1) - x(n))
219 filtered_throttle = throttle + kAlpha * (filtered_throttle - throttle);
220
221 const float fuse_voltage = static_cast<float>(adc_readings.fuse_voltage);
222 static float filtered_fuse_voltage = 0.0f;
223
224 filtered_fuse_voltage =
225 fuse_voltage + kFuseAlpha * (filtered_fuse_voltage - fuse_voltage);
226
227 const float velocity =
228 global_motor.load(::std::memory_order_relaxed)->estimated_velocity();
229 const float bemf = velocity / (static_cast<float>(Kv) / 1.5f);
230 const float abs_bemf = ::std::abs(bemf);
231 constexpr float kPeakCurrent = 300.0f;
232 constexpr float kLimitedCurrent = 75.0f;
233 const float max_bat_cur =
234 fuse_badness > (kLimitedCurrent * kLimitedCurrent * 0.95f)
235 ? kLimitedCurrent
236 : static_cast<float>(kIcc);
237 const float throttle_limit = ::std::min(
238 kPeakCurrent,
239 (-abs_bemf + ::std::sqrt(static_cast<float>(
240 bemf * bemf +
241 4.0f * static_cast<float>(kR) * 1.5f *
242 static_cast<float>(kVcc) * max_bat_cur))) /
243 (2.0f * 1.5f * static_cast<float>(kR)));
244
245 constexpr float kNegativeCurrent = 80.0f;
246 float goal_current = -::std::min(
247 filtered_throttle * (kPeakCurrent + kNegativeCurrent) - kNegativeCurrent,
248 throttle_limit);
249
250 if (velocity > -500) {
251 if (goal_current > 0.0f) {
252 goal_current = 0.0f;
253 }
254 }
255 //float goal_current =
256 //-::std::min(filtered_throttle * kPeakCurrent, throttle_limit);
257 const float fuse_current =
258 goal_current *
259 (bemf + goal_current * static_cast<float>(kR) * 1.5f) /
260 static_cast<float>(kVcc);
261 const int16_t fuse_current_10 = static_cast<int16_t>(10.0f * fuse_current);
262 fuse_badness += 0.00002f * (fuse_current * fuse_current - fuse_badness);
263
264 global_motor.load(::std::memory_order_relaxed)
265 ->SetGoalCurrent(goal_current);
266 global_motor.load(::std::memory_order_relaxed)
267 ->HandleInterrupt(balanced, wrapped_encoder);
268#else
269 (void)balanced;
270 FTM0->SC &= ~FTM_SC_TOF;
271 FTM0->C0V = 0;
272 FTM0->C1V = 0;
273 FTM0->C2V = 0;
274 FTM0->C3V = 0;
275 FTM0->C4V = 0;
276 FTM0->C5V = 60;
277 FTM0->PWMLOAD = FTM_PWMLOAD_LDOK;
278#endif
279
280 global_debug_buffer.count.fetch_add(1);
281
282 const bool trigger = false;
283 // global_debug_buffer.count.load(::std::memory_order_relaxed) >= 0;
284 size_t buffer_size =
285 global_debug_buffer.size.load(::std::memory_order_relaxed);
286 if ((buffer_size > 0 || trigger) &&
287 buffer_size != global_debug_buffer.samples.size()) {
288 global_debug_buffer.samples[buffer_size].currents[0] =
289 static_cast<int16_t>(balanced.readings[0] * 10.0f);
290 global_debug_buffer.samples[buffer_size].currents[1] =
291 static_cast<int16_t>(balanced.readings[1] * 10.0f);
292 global_debug_buffer.samples[buffer_size].currents[2] =
293 static_cast<int16_t>(balanced.readings[2] * 10.0f);
294 global_debug_buffer.samples[buffer_size].position =
295 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
296 global_debug_buffer.samples[buffer_size].est_omega =
297 global_motor.load(::std::memory_order_relaxed)->estimated_velocity();
298 global_debug_buffer.samples[buffer_size].commands[0] =
299 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0);
300 global_debug_buffer.samples[buffer_size].commands[1] =
301 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1);
302 global_debug_buffer.samples[buffer_size].commands[2] =
303 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2);
304 global_debug_buffer.samples[buffer_size].commanded_currents[0] =
305 global_motor.load(::std::memory_order_relaxed)->i_goal(0);
306 global_debug_buffer.samples[buffer_size].commanded_currents[1] =
307 global_motor.load(::std::memory_order_relaxed)->i_goal(1);
308 global_debug_buffer.samples[buffer_size].commanded_currents[2] =
309 global_motor.load(::std::memory_order_relaxed)->i_goal(2);
310 global_debug_buffer.samples[buffer_size].total_command =
311 global_motor.load(::std::memory_order_relaxed)->goal_current();
312 global_debug_buffer.samples[buffer_size].fuse_voltage =
313 filtered_fuse_voltage;
314 global_debug_buffer.samples[buffer_size].fuse_current = fuse_current_10;
315 global_debug_buffer.samples[buffer_size].driver_request =
316 ::std::max(filtered_throttle * (kPeakCurrent + kNegativeCurrent) -
317 kNegativeCurrent,
318 0.0f);
319 global_debug_buffer.samples[buffer_size].fuse_badness = fuse_badness;
320 global_debug_buffer.samples[buffer_size].cycles_since_start = cycles_since_start;
321
322 global_debug_buffer.size.fetch_add(1);
323 }
324
325 if (buffer_size == global_debug_buffer.samples.size()) {
326 GPIOC_PCOR = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
327 GPIOD_PCOR = (1 << 4) | (1 << 5);
328
329 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
330 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
331 PERIPHERAL_BITBAND(GPIOC_PDDR, 3) = 1;
332 PERIPHERAL_BITBAND(GPIOC_PDDR, 4) = 1;
333 PERIPHERAL_BITBAND(GPIOD_PDDR, 4) = 1;
334 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
335
336 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
337 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
338 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
339 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
340 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
341 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
342 }
343
344 ++i;
345 if (i > 1000) {
346 i = 0;
347 }
348}
349
350} // extern "C"
351
352void ConfigurePwmFtm(BigFTM *pwm_ftm) {
353 // Put them all into combine active-high mode, and all the low ones staying on
354 // all the time by default.
355 pwm_ftm->C0SC = FTM_CSC_ELSA;
356 pwm_ftm->C0V = 0;
357 pwm_ftm->C1SC = FTM_CSC_ELSA;
358 pwm_ftm->C1V = 0;
359 pwm_ftm->C2SC = FTM_CSC_ELSA;
360 pwm_ftm->C2V = 0;
361 pwm_ftm->C3SC = FTM_CSC_ELSA;
362 pwm_ftm->C3V = 0;
363 pwm_ftm->C4SC = FTM_CSC_ELSA;
364 pwm_ftm->C4V = 0;
365 pwm_ftm->C5SC = FTM_CSC_ELSA;
366 pwm_ftm->C5V = 0;
367 pwm_ftm->C6SC = FTM_CSC_ELSA;
368 pwm_ftm->C6V = 0;
369 pwm_ftm->C7SC = FTM_CSC_ELSA;
370 pwm_ftm->C7V = 0;
371
372 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
373 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
374 FTM_COMBINE_COMP3 /* Make them complementary */ |
375 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
376 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
377 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
378 FTM_COMBINE_COMP2 /* Make them complementary */ |
379 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
380 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
381 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
382 FTM_COMBINE_COMP1 /* Make them complementary */ |
383 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
384 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
385 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
386 FTM_COMBINE_COMP0 /* Make them complementary */ |
387 FTM_COMBINE_COMBINE0 /* Combine the channels */;
388 // Safe state for all channels is low.
389 pwm_ftm->POL = 0;
390
391 // Set the deadtime.
392 pwm_ftm->DEADTIME =
393 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
394
395 pwm_ftm->CONF =
396 FTM_CONF_BDMMOD(1) /* Set everything to POLn during debug halt */;
397}
398
399// Zeros the encoder. This involves blocking for an arbitrary length of time
400// with interrupts disabled.
401void ZeroMotor() {
402#if 0
403 while (true) {
404 if (PERIPHERAL_BITBAND(GPIOB_PDIR, 11)) {
405 encoder_ftm_->CNT = 0;
406 break;
407 }
408 }
409#else
410 uint32_t scratch;
411 __disable_irq();
412 // Stuff all of this in an inline assembly statement so we can make sure the
413 // compiler doesn't decide sticking constant loads etc in the middle of
414 // the loop is a good idea, because that increases the latency of recognizing
415 // the index pulse edge which makes velocity affect the zeroing accuracy.
416 __asm__ __volatile__(
417 // A label to restart the loop.
418 "0:\n"
419 // Load the current PDIR value for the pin we care about.
420 "ldr %[scratch], [%[pdir_word]]\n"
421 // Terminate the loop if it's non-0.
422 "cbnz %[scratch], 1f\n"
423 // Go back around again.
424 "b 0b\n"
425 // A label to finish the loop.
426 "1:\n"
427 // Reset the count once we're down here. It doesn't actually matter what
428 // value we store because writing anything resets it to CNTIN (ie 0).
429 "str %[scratch], [%[cnt]]\n"
430 : [scratch] "=&l"(scratch)
431 : [pdir_word] "l"(&PERIPHERAL_BITBAND(GPIOB_PDIR, 11)),
432 [cnt] "l"(&FTM1->CNT));
433 __enable_irq();
434#endif
435}
436
437} // namespace
438
439extern "C" int main(void) {
440 // for background about this startup delay, please see these conversations
441 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
442 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
443 delay(400);
444
445 // Set all interrupts to the second-lowest priority to start with.
446 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
447
448 // Now set priorities for all the ones we care about. They only have meaning
449 // relative to each other, which means centralizing them here makes it a lot
450 // more manageable.
451 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
452 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0xE);
453
454 // Set the LED's pin to output mode.
455 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
456 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
457
458#if 0
459 PERIPHERAL_BITBAND(GPIOA_PDDR, 15) = 1;
460 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
461#endif
462
463 // Set up the CAN pins.
464 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
465 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
466
467 DMA.CR = M_DMA_EMLM;
468
469 PORTB_PCR16 = PORT_PCR_DSE | PORT_PCR_MUX(3);
470 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(3);
471 SIM_SCGC4 |= SIM_SCGC4_UART0;
472 teensy::InterruptBufferedUart debug_uart(&UART0, F_CPU);
473 debug_uart.Initialize(115200);
474 global_stdout.store(&debug_uart, ::std::memory_order_release);
475 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
476
477 AdcInitFet12();
478 MathInit();
479 delay(100);
480 can_init(0, 1);
481
482 MotorControlsImplementation controls;
483
484 delay(100);
485
486 // Index pin
487 PORTB_PCR11 = PORT_PCR_MUX(1);
488 // FTM1_QD_PH{A,B}
489 PORTB_PCR0 = PORT_PCR_MUX(6);
490 PORTB_PCR1 = PORT_PCR_MUX(6);
491
492 // FTM0_CH[0-5]
493 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
494 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
495 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
496 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
497 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
498 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
499
500 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
501 motor.set_encoder_offset(810);
502 motor.set_deadtime_compensation(9);
503 ConfigurePwmFtm(FTM0);
504 motor.Init();
505 global_motor.store(&motor, ::std::memory_order_relaxed);
506 // Output triggers to things like the PDBs on initialization.
507 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
508 // Don't let any memory accesses sneak past here, because we actually
509 // need everything to be starting up.
510 __asm__("" :: : "memory");
511
512 // Give everything a chance to get going.
513 delay(100);
514
515 printf("Ram start: %p\n", __bss_ram_start__);
516 printf("Heap start: %p\n", __heap_start__);
517 printf("Heap end: %p\n", __brkval);
518 printf("Stack start: %p\n", __stack_end__);
519
520 printf("Going silent to zero motors...\n");
521 // Give the print a chance to make it out.
522 delay(100);
523 ZeroMotor();
524
525 motor.set_encoder_multiplier(-1);
526 motor.set_encoder_calibration_offset(
527 558 + 1034 + 39 /*big data bemf comp*/ - 14 /*just backwardsbackwards comp*/);
528
529 printf("Zeroed motor!\n");
530 // Give stuff a chance to recover from interrupts-disabled.
531 delay(100);
532 motor.Start();
533 NVIC_ENABLE_IRQ(IRQ_FTM0);
534 GPIOC_PSOR = 1 << 5;
535
536 constexpr bool dump_full_sample = false;
537 while (true) {
538 if (dump_full_sample) {
539 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
540 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
541 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
542 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
543 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
544 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
545 motor.Reset();
546 }
547 global_debug_buffer.size.store(0);
548 global_debug_buffer.count.store(0);
549 while (global_debug_buffer.size.load(::std::memory_order_relaxed) <
550 global_debug_buffer.samples.size()) {
551 }
552 if (dump_full_sample) {
553 printf("Dumping data\n");
554 for (size_t i = 0; i < global_debug_buffer.samples.size(); ++i) {
555 const auto &sample = global_debug_buffer.samples[i];
556
557 printf("%u, %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d\n", i,
558 sample.currents[0], sample.currents[1], sample.currents[2],
559 sample.commands[0], sample.commands[1], sample.commands[2],
560 sample.position, static_cast<int>(sample.est_omega),
561 sample.commanded_currents[0], sample.commanded_currents[1],
562 sample.commanded_currents[2]);
563 }
564 printf("Done dumping data\n");
565 } else {
566 //const auto &sample = global_debug_buffer.samples.back();
567 const DebugBuffer::Sample sample = global_debug_buffer.samples[0];
568#if 1
569 printf("%" PRIu32
570 ", %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d, %d, %d, %d\n",
571 sample.cycles_since_start, sample.currents[0], sample.currents[1],
572 sample.currents[2], sample.commands[0], sample.commands[1],
573 sample.commands[2], sample.position,
574 static_cast<int>(sample.est_omega), sample.commanded_currents[0],
575 sample.commanded_currents[1], sample.commanded_currents[2],
576 sample.total_command, static_cast<int>(sample.driver_request),
577 static_cast<int>(sample.fuse_badness));
578#else
579 printf("%d, %d\n", static_cast<int>(sample.fuse_voltage),
580 sample.fuse_current);
581#endif
582 }
583 }
584
585 return 0;
586}
587
588} // namespace motors
589} // namespace frc971