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