blob: 7d18f469db0d537d18c6ed399390d095cb35b4db [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"
James Kuszmaul7c8aad62018-09-08 18:16:18 -070013#include "motors/peripheral/adc_dma.h"
James Kuszmaul998d3032018-09-08 15:41:41 -070014#include "motors/peripheral/can.h"
15#include "motors/peripheral/uart.h"
16#include "motors/util.h"
17#include "third_party/GSL/include/gsl/gsl"
18
19namespace frc971 {
20namespace motors {
21namespace {
22
23constexpr double Kv = 22000.0 * 2.0 * M_PI / 60.0 / 30.0 * 3.6;
24constexpr double kVcc = 31.5;
25constexpr double kIcc = 125.0;
26constexpr double kR = 0.0084;
27
28struct Fet12AdcReadings {
James Kuszmaul7c8aad62018-09-08 18:16:18 -070029 // Averages of the pairs of ADC DMA channels corresponding with each channel
30 // pair. Individual values in motor_currents correspond to current sensor
31 // values, rather than the actual currents themselves (and so they still need
32 // to be decoupled).
James Kuszmaul998d3032018-09-08 15:41:41 -070033 int16_t motor_currents[3];
34 int16_t throttle, fuse_voltage;
35};
36
37void AdcInitFet12() {
38 AdcInitCommon(AdcChannels::kB, AdcChannels::kA);
39
40 // M_CH0V ADC0_SE5b
41 PORTD_PCR1 = PORT_PCR_MUX(0);
42
43 // M_CH1V ADC0_SE7b
44 PORTD_PCR6 = PORT_PCR_MUX(0);
45
46 // M_CH2V ADC0_SE14
47 PORTC_PCR0 = PORT_PCR_MUX(0);
48
49 // M_CH0F ADC1_SE5a
50 PORTE_PCR1 = PORT_PCR_MUX(0);
51
52 // M_CH1F ADC1_SE6a
53 PORTE_PCR2 = PORT_PCR_MUX(0);
54
55 // M_CH2F ADC1_SE7a
56 PORTE_PCR3 = PORT_PCR_MUX(0);
57
58 // SENSE0 ADC0_SE23
59 // dedicated
60
61 // SENSE1 ADC0_SE13
62 PORTB_PCR3 = PORT_PCR_MUX(0);
63}
64
James Kuszmaul998d3032018-09-08 15:41:41 -070065::std::atomic<Motor *> global_motor{nullptr};
James Kuszmaul7c8aad62018-09-08 18:16:18 -070066::std::atomic<teensy::AdcDmaSampler *> global_adc_dma{nullptr};
67
James Kuszmaul998d3032018-09-08 15:41:41 -070068::std::atomic<teensy::InterruptBufferedUart *> global_stdout{nullptr};
69
70extern "C" {
71
72void uart0_status_isr(void) {
73 teensy::InterruptBufferedUart *const tty =
74 global_stdout.load(::std::memory_order_relaxed);
75 DisableInterrupts disable_interrupts;
76 tty->HandleInterrupt(disable_interrupts);
77}
78
79void *__stack_chk_guard = (void *)0x67111971;
80void __stack_chk_fail(void) {
81 while (true) {
82 GPIOC_PSOR = (1 << 5);
83 printf("Stack corruption detected\n");
84 delay(1000);
85 GPIOC_PCOR = (1 << 5);
86 delay(1000);
87 }
88}
89
90int _write(int /*file*/, char *ptr, int len) {
91 teensy::InterruptBufferedUart *const tty =
92 global_stdout.load(::std::memory_order_acquire);
93 if (tty != nullptr) {
Brian Silverman12fec3f2018-09-09 16:09:50 -070094 tty->Write(gsl::make_span(ptr, len));
James Kuszmaul998d3032018-09-08 15:41:41 -070095 return len;
96 }
97 return 0;
98}
99
100void __stack_chk_fail(void);
101
102extern char *__brkval;
103extern uint32_t __bss_ram_start__[];
104extern uint32_t __heap_start__[];
105extern uint32_t __stack_end__[];
106
107struct DebugBuffer {
108 struct Sample {
109 ::std::array<int16_t, 3> currents;
110 ::std::array<int16_t, 3> commanded_currents;
111 ::std::array<uint16_t, 3> commands;
112 uint16_t position;
113 // Driver requested current.
114 float driver_request;
115 // Requested current.
116 int16_t total_command;
117
118 float est_omega;
119 float fuse_voltage;
120 int16_t fuse_current;
121
122 float fuse_badness;
123 uint32_t cycles_since_start;
124 };
125
126 // The amount of data in the buffer. This will never decrement. This will be
127 // transferred out the serial port after it fills up.
128 ::std::atomic<size_t> size{0};
129 ::std::atomic<uint32_t> count{0};
130 // The data.
131 ::std::array<Sample, 512> samples;
132};
133
134DebugBuffer global_debug_buffer;
135
136void ftm0_isr(void) {
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700137 static uint32_t i = 0;
138 teensy::AdcDmaSampler *const adc_dma =
139 global_adc_dma.load(::std::memory_order_relaxed);
140
James Kuszmaul998d3032018-09-08 15:41:41 -0700141 Fet12AdcReadings adc_readings;
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700142 // TODO(Brian): Switch to the DMA interrupt instead of spinning.
143 while (!adc_dma->CheckDone()) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700144 }
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700145
146 adc_readings.motor_currents[0] =
147 (adc_dma->adc_result(0, 0) + adc_dma->adc_result(0, 1)) / 2;
148 adc_readings.motor_currents[1] =
149 (adc_dma->adc_result(0, 2) + adc_dma->adc_result(1, 1)) / 2;
150 adc_readings.motor_currents[2] =
151 (adc_dma->adc_result(1, 0) + adc_dma->adc_result(1, 2)) / 2;
152 adc_readings.throttle = adc_dma->adc_result(0, 3);
James Kuszmaul998d3032018-09-08 15:41:41 -0700153 const ::std::array<float, 3> decoupled =
154 DecoupleCurrents(adc_readings.motor_currents);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700155 adc_dma->Reset();
156 const uint32_t wrapped_encoder =
157 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
158#if 1
James Kuszmaul998d3032018-09-08 15:41:41 -0700159 const BalancedReadings balanced =
160 BalanceSimpleReadings(decoupled);
161
James Kuszmaul998d3032018-09-08 15:41:41 -0700162 static float fuse_badness = 0;
163
164 static uint32_t cycles_since_start = 0u;
165 ++cycles_since_start;
166#if 0
167 static int count = 0;
168 ++count;
169 static float currents[3] = {0.0f, 0.0f, 0.0f};
170 for (int ii = 0; ii < 3; ++ii) {
171 currents[ii] += static_cast<float>(adc_readings.motor_currents[ii]);
172 }
173
174 if (i == 0) {
175 printf(
176 "foo %d.0, %d.0, %d.0, %.3d %.3d %.3d, switching %d %d %d enc %d\n",
177 static_cast<int>(currents[0] / static_cast<float>(count)),
178 static_cast<int>(currents[1] / static_cast<float>(count)),
179 static_cast<int>(currents[2] / static_cast<float>(count)),
180 static_cast<int>(decoupled[0] * 1.0f),
181 static_cast<int>(decoupled[1] * 1.0f),
182 static_cast<int>(decoupled[2] * 1.0f),
183 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0),
184 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1),
185 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2),
186 static_cast<int>(
187 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder()));
188 count = 0;
189 currents[0] = 0.0f;
190 currents[1] = 0.0f;
191 currents[2] = 0.0f;
192 }
193#endif
194#if 1
195 constexpr float kAlpha = 0.995f;
196 constexpr float kFuseAlpha = 0.95f;
197
198 // 3400 - 760
James Kuszmaulb7707432018-10-07 14:48:11 -0700199 // Start the throttle filter at 1.0f--once it converges to near zero, we set
200 // throttle_zeroed to true and only then do we start listening to throttle
201 // commands.
202 static float filtered_throttle = 1.0f;
203 static bool throttle_zeroed = false;
James Kuszmaul998d3032018-09-08 15:41:41 -0700204 constexpr int kMaxThrottle = 3400;
205 constexpr int kMinThrottle = 760;
206 const float throttle = ::std::max(
207 0.0f,
208 ::std::min(1.0f,
209 static_cast<float>(static_cast<int>(adc_readings.throttle) -
210 kMinThrottle) /
211 static_cast<float>(kMaxThrottle - kMinThrottle)));
212
213 // y(n) = x(n) + a * (y(n-1) - x(n))
214 filtered_throttle = throttle + kAlpha * (filtered_throttle - throttle);
James Kuszmaulb7707432018-10-07 14:48:11 -0700215 if (::std::abs(filtered_throttle) < 1e-2f) {
216 // Once the filter gets near zero once, we start paying attention to it;
217 // once it gets near zero once, never ignore it again.
218 throttle_zeroed = true;
219 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700220
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;
James Kuszmaula1d94c82018-10-10 20:00:09 -0700246 float goal_current =
247 -::std::min(
248 ::std::max(filtered_throttle * (kPeakCurrent + kNegativeCurrent) -
249 kNegativeCurrent,
250 -throttle_limit),
251 throttle_limit);
James Kuszmaul998d3032018-09-08 15:41:41 -0700252
James Kuszmaulb7707432018-10-07 14:48:11 -0700253 if (!throttle_zeroed) {
254 goal_current = 0.0f;
255 }
256
James Kuszmaula1d94c82018-10-10 20:00:09 -0700257 // Note: current reduction is 12/70 belt, 15 / 54 on chain, and 10 inch
258 // diameter wheels, so cutoff of 500 electrical rad/sec * 1 mechanical rad / 2
259 // erad * 12 / 70 * 15 / 54 * 0.127 m = 1.5m/s = 3.4 mph
James Kuszmaul998d3032018-09-08 15:41:41 -0700260 if (velocity > -500) {
261 if (goal_current > 0.0f) {
262 goal_current = 0.0f;
263 }
264 }
265 //float goal_current =
266 //-::std::min(filtered_throttle * kPeakCurrent, throttle_limit);
267 const float fuse_current =
268 goal_current *
269 (bemf + goal_current * static_cast<float>(kR) * 1.5f) /
270 static_cast<float>(kVcc);
271 const int16_t fuse_current_10 = static_cast<int16_t>(10.0f * fuse_current);
272 fuse_badness += 0.00002f * (fuse_current * fuse_current - fuse_badness);
273
274 global_motor.load(::std::memory_order_relaxed)
275 ->SetGoalCurrent(goal_current);
276 global_motor.load(::std::memory_order_relaxed)
277 ->HandleInterrupt(balanced, wrapped_encoder);
James Kuszmaul998d3032018-09-08 15:41:41 -0700278
279 global_debug_buffer.count.fetch_add(1);
280
281 const bool trigger = false;
282 // global_debug_buffer.count.load(::std::memory_order_relaxed) >= 0;
283 size_t buffer_size =
284 global_debug_buffer.size.load(::std::memory_order_relaxed);
285 if ((buffer_size > 0 || trigger) &&
286 buffer_size != global_debug_buffer.samples.size()) {
287 global_debug_buffer.samples[buffer_size].currents[0] =
288 static_cast<int16_t>(balanced.readings[0] * 10.0f);
289 global_debug_buffer.samples[buffer_size].currents[1] =
290 static_cast<int16_t>(balanced.readings[1] * 10.0f);
291 global_debug_buffer.samples[buffer_size].currents[2] =
292 static_cast<int16_t>(balanced.readings[2] * 10.0f);
293 global_debug_buffer.samples[buffer_size].position =
294 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
295 global_debug_buffer.samples[buffer_size].est_omega =
296 global_motor.load(::std::memory_order_relaxed)->estimated_velocity();
297 global_debug_buffer.samples[buffer_size].commands[0] =
298 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0);
299 global_debug_buffer.samples[buffer_size].commands[1] =
300 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1);
301 global_debug_buffer.samples[buffer_size].commands[2] =
302 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2);
303 global_debug_buffer.samples[buffer_size].commanded_currents[0] =
304 global_motor.load(::std::memory_order_relaxed)->i_goal(0);
305 global_debug_buffer.samples[buffer_size].commanded_currents[1] =
306 global_motor.load(::std::memory_order_relaxed)->i_goal(1);
307 global_debug_buffer.samples[buffer_size].commanded_currents[2] =
308 global_motor.load(::std::memory_order_relaxed)->i_goal(2);
309 global_debug_buffer.samples[buffer_size].total_command =
310 global_motor.load(::std::memory_order_relaxed)->goal_current();
311 global_debug_buffer.samples[buffer_size].fuse_voltage =
312 filtered_fuse_voltage;
313 global_debug_buffer.samples[buffer_size].fuse_current = fuse_current_10;
314 global_debug_buffer.samples[buffer_size].driver_request =
315 ::std::max(filtered_throttle * (kPeakCurrent + kNegativeCurrent) -
316 kNegativeCurrent,
317 0.0f);
318 global_debug_buffer.samples[buffer_size].fuse_badness = fuse_badness;
319 global_debug_buffer.samples[buffer_size].cycles_since_start = cycles_since_start;
320
321 global_debug_buffer.size.fetch_add(1);
322 }
323
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700324 ++i;
James Kuszmaul998d3032018-09-08 15:41:41 -0700325 if (buffer_size == global_debug_buffer.samples.size()) {
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700326 i = 0;
James Kuszmaul998d3032018-09-08 15:41:41 -0700327 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 }
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700344#else
345#endif
346#else
347 FTM0->SC &= ~FTM_SC_TOF;
348 FTM0->C0V = 0;
349 FTM0->C1V = 0;
350 FTM0->C2V = 0;
351 FTM0->C3V = 0;
352 FTM0->C4V = 0;
353 FTM0->C5V = 0;
354 FTM0->PWMLOAD = FTM_PWMLOAD_LDOK;
355#endif
James Kuszmaul998d3032018-09-08 15:41:41 -0700356
James Kuszmaul998d3032018-09-08 15:41:41 -0700357}
358
359} // extern "C"
360
361void ConfigurePwmFtm(BigFTM *pwm_ftm) {
362 // Put them all into combine active-high mode, and all the low ones staying on
363 // all the time by default.
364 pwm_ftm->C0SC = FTM_CSC_ELSA;
365 pwm_ftm->C0V = 0;
366 pwm_ftm->C1SC = FTM_CSC_ELSA;
367 pwm_ftm->C1V = 0;
368 pwm_ftm->C2SC = FTM_CSC_ELSA;
369 pwm_ftm->C2V = 0;
370 pwm_ftm->C3SC = FTM_CSC_ELSA;
371 pwm_ftm->C3V = 0;
372 pwm_ftm->C4SC = FTM_CSC_ELSA;
373 pwm_ftm->C4V = 0;
374 pwm_ftm->C5SC = FTM_CSC_ELSA;
375 pwm_ftm->C5V = 0;
376 pwm_ftm->C6SC = FTM_CSC_ELSA;
377 pwm_ftm->C6V = 0;
378 pwm_ftm->C7SC = FTM_CSC_ELSA;
379 pwm_ftm->C7V = 0;
380
381 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
382 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
383 FTM_COMBINE_COMP3 /* Make them complementary */ |
384 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
385 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
386 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
387 FTM_COMBINE_COMP2 /* Make them complementary */ |
388 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
389 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
390 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
391 FTM_COMBINE_COMP1 /* Make them complementary */ |
392 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
393 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
394 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
395 FTM_COMBINE_COMP0 /* Make them complementary */ |
396 FTM_COMBINE_COMBINE0 /* Combine the channels */;
397 // Safe state for all channels is low.
398 pwm_ftm->POL = 0;
399
400 // Set the deadtime.
401 pwm_ftm->DEADTIME =
402 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
403
404 pwm_ftm->CONF =
405 FTM_CONF_BDMMOD(1) /* Set everything to POLn during debug halt */;
406}
407
408// Zeros the encoder. This involves blocking for an arbitrary length of time
409// with interrupts disabled.
410void ZeroMotor() {
411#if 0
412 while (true) {
413 if (PERIPHERAL_BITBAND(GPIOB_PDIR, 11)) {
414 encoder_ftm_->CNT = 0;
415 break;
416 }
417 }
418#else
419 uint32_t scratch;
420 __disable_irq();
421 // Stuff all of this in an inline assembly statement so we can make sure the
422 // compiler doesn't decide sticking constant loads etc in the middle of
423 // the loop is a good idea, because that increases the latency of recognizing
424 // the index pulse edge which makes velocity affect the zeroing accuracy.
425 __asm__ __volatile__(
426 // A label to restart the loop.
427 "0:\n"
428 // Load the current PDIR value for the pin we care about.
429 "ldr %[scratch], [%[pdir_word]]\n"
430 // Terminate the loop if it's non-0.
431 "cbnz %[scratch], 1f\n"
432 // Go back around again.
433 "b 0b\n"
434 // A label to finish the loop.
435 "1:\n"
436 // Reset the count once we're down here. It doesn't actually matter what
437 // value we store because writing anything resets it to CNTIN (ie 0).
438 "str %[scratch], [%[cnt]]\n"
439 : [scratch] "=&l"(scratch)
440 : [pdir_word] "l"(&PERIPHERAL_BITBAND(GPIOB_PDIR, 11)),
441 [cnt] "l"(&FTM1->CNT));
442 __enable_irq();
443#endif
444}
445
446} // namespace
447
448extern "C" int main(void) {
449 // for background about this startup delay, please see these conversations
450 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
451 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
452 delay(400);
453
454 // Set all interrupts to the second-lowest priority to start with.
455 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
456
457 // Now set priorities for all the ones we care about. They only have meaning
458 // relative to each other, which means centralizing them here makes it a lot
459 // more manageable.
460 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
461 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0xE);
462
463 // Set the LED's pin to output mode.
464 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
465 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
466
467#if 0
468 PERIPHERAL_BITBAND(GPIOA_PDDR, 15) = 1;
469 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
470#endif
471
472 // Set up the CAN pins.
473 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
474 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
475
476 DMA.CR = M_DMA_EMLM;
477
478 PORTB_PCR16 = PORT_PCR_DSE | PORT_PCR_MUX(3);
479 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(3);
480 SIM_SCGC4 |= SIM_SCGC4_UART0;
481 teensy::InterruptBufferedUart debug_uart(&UART0, F_CPU);
482 debug_uart.Initialize(115200);
483 global_stdout.store(&debug_uart, ::std::memory_order_release);
484 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
485
486 AdcInitFet12();
487 MathInit();
488 delay(100);
489 can_init(0, 1);
490
491 MotorControlsImplementation controls;
492
493 delay(100);
494
495 // Index pin
496 PORTB_PCR11 = PORT_PCR_MUX(1);
497 // FTM1_QD_PH{A,B}
498 PORTB_PCR0 = PORT_PCR_MUX(6);
499 PORTB_PCR1 = PORT_PCR_MUX(6);
500
501 // FTM0_CH[0-5]
502 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
503 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
504 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
505 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
506 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
507 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
508
509 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
510 motor.set_encoder_offset(810);
511 motor.set_deadtime_compensation(9);
512 ConfigurePwmFtm(FTM0);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700513
Brian Silvermana1d84822018-09-15 17:18:49 -0700514 // TODO(Brian): Figure out how to avoid duplicating this code to slave one FTM
515 // to another.
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700516 FTM2->CONF = FTM_CONF_GTBEEN;
517 FTM2->MODE = FTM_MODE_WPDIS;
518 FTM2->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
519 FTM2->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
520 FTM2->CNTIN = 0;
521 FTM2->CNT = 0;
522 // TODO(Brian): Don't duplicate this.
523 FTM2->MOD = BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY;
524 FTM2->OUTINIT = 0;
525 // All of the channels are active high.
526 FTM2->POL = 0;
527 FTM2->SYNCONF = FTM_SYNCONF_HWWRBUF | FTM_SYNCONF_SWWRBUF |
528 FTM_SYNCONF_SWRSTCNT | FTM_SYNCONF_SYNCMODE;
529 // Don't want any intermediate loading points.
530 FTM2->PWMLOAD = 0;
531
532 // Need to set them to some kind of output mode so we can actually change
533 // them.
534 FTM2->C0SC = FTM_CSC_MSA;
535 FTM2->C1SC = FTM_CSC_MSA;
536
537 // This has to happen after messing with SYNCONF, and should happen after
538 // messing with various other things so the values can get flushed out of the
539 // buffers.
540 FTM2->SYNC =
541 FTM_SYNC_SWSYNC /* Flush everything out right now */ |
542 FTM_SYNC_CNTMAX /* Load new values at the end of the cycle */;
543 // Wait for the software synchronization to finish.
544 while (FTM2->SYNC & FTM_SYNC_SWSYNC) {
545 }
546 FTM2->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
547 FTM_SC_PS(0) /* Don't prescale the clock */;
548 // TODO:
549 //FTM2->MODE &= ~FTM_MODE_WPDIS;
550
551 FTM2->EXTTRIG = FTM_EXTTRIG_CH0TRIG | FTM_EXTTRIG_CH1TRIG;
552
Brian Silvermana1d84822018-09-15 17:18:49 -0700553 // TODO(Brian): Don't duplicate the timer's MOD value.
554 teensy::AdcDmaSampler adc_dma{BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY};
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700555 // ADC0_Dx0 is 1-0
556 // ADC0_Dx2 is 1-2
557 // ADC0_Dx3 is 2-0
558 // ADC1_Dx0 is 2-0
559 // ADC1_Dx3 is 1-0
560 // Sample 0: 1-2,2-0
561 // Sample 1: 1-2,1-0
562 // Sample 2: 1-0,2-0
563 // Sample 3: 23(SENSE0),18(VIN)
564 adc_dma.set_adc0_samples({V_ADC_ADCH(2) | M_ADC_DIFF,
565 V_ADC_ADCH(2) | M_ADC_DIFF,
566 V_ADC_ADCH(0) | M_ADC_DIFF, V_ADC_ADCH(23)});
567 adc_dma.set_adc1_samples({V_ADC_ADCH(0) | M_ADC_DIFF,
568 V_ADC_ADCH(3) | M_ADC_DIFF,
569 V_ADC_ADCH(0) | M_ADC_DIFF, V_ADC_ADCH(18)});
570 adc_dma.set_ftm_delays({&FTM2->C0V, &FTM2->C1V});
571 adc_dma.set_pdb_input(PDB_IN_FTM2);
572
573 adc_dma.Initialize();
574 FTM0->CONF = FTM_CONF_GTBEEN;
James Kuszmaul998d3032018-09-08 15:41:41 -0700575 motor.Init();
576 global_motor.store(&motor, ::std::memory_order_relaxed);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700577 global_adc_dma.store(&adc_dma, ::std::memory_order_relaxed);
578
James Kuszmaul998d3032018-09-08 15:41:41 -0700579 // Output triggers to things like the PDBs on initialization.
580 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
581 // Don't let any memory accesses sneak past here, because we actually
582 // need everything to be starting up.
583 __asm__("" :: : "memory");
584
585 // Give everything a chance to get going.
586 delay(100);
587
588 printf("Ram start: %p\n", __bss_ram_start__);
589 printf("Heap start: %p\n", __heap_start__);
590 printf("Heap end: %p\n", __brkval);
591 printf("Stack start: %p\n", __stack_end__);
592
593 printf("Going silent to zero motors...\n");
594 // Give the print a chance to make it out.
595 delay(100);
596 ZeroMotor();
597
598 motor.set_encoder_multiplier(-1);
599 motor.set_encoder_calibration_offset(
600 558 + 1034 + 39 /*big data bemf comp*/ - 14 /*just backwardsbackwards comp*/);
601
602 printf("Zeroed motor!\n");
603 // Give stuff a chance to recover from interrupts-disabled.
604 delay(100);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700605 adc_dma.Reset();
James Kuszmaul998d3032018-09-08 15:41:41 -0700606 motor.Start();
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700607 // Now poke the GTB to actually start both timers.
608 FTM0->CONF = FTM_CONF_GTBEEN | FTM_CONF_GTBEOUT;
609
James Kuszmaul998d3032018-09-08 15:41:41 -0700610 NVIC_ENABLE_IRQ(IRQ_FTM0);
611 GPIOC_PSOR = 1 << 5;
612
613 constexpr bool dump_full_sample = false;
614 while (true) {
615 if (dump_full_sample) {
616 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
617 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
618 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
619 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
620 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
621 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
622 motor.Reset();
623 }
624 global_debug_buffer.size.store(0);
625 global_debug_buffer.count.store(0);
626 while (global_debug_buffer.size.load(::std::memory_order_relaxed) <
627 global_debug_buffer.samples.size()) {
628 }
629 if (dump_full_sample) {
630 printf("Dumping data\n");
631 for (size_t i = 0; i < global_debug_buffer.samples.size(); ++i) {
632 const auto &sample = global_debug_buffer.samples[i];
633
634 printf("%u, %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d\n", i,
635 sample.currents[0], sample.currents[1], sample.currents[2],
636 sample.commands[0], sample.commands[1], sample.commands[2],
637 sample.position, static_cast<int>(sample.est_omega),
638 sample.commanded_currents[0], sample.commanded_currents[1],
639 sample.commanded_currents[2]);
640 }
641 printf("Done dumping data\n");
642 } else {
643 //const auto &sample = global_debug_buffer.samples.back();
644 const DebugBuffer::Sample sample = global_debug_buffer.samples[0];
645#if 1
646 printf("%" PRIu32
647 ", %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d, %d, %d, %d\n",
648 sample.cycles_since_start, sample.currents[0], sample.currents[1],
649 sample.currents[2], sample.commands[0], sample.commands[1],
650 sample.commands[2], sample.position,
651 static_cast<int>(sample.est_omega), sample.commanded_currents[0],
652 sample.commanded_currents[1], sample.commanded_currents[2],
653 sample.total_command, static_cast<int>(sample.driver_request),
654 static_cast<int>(sample.fuse_badness));
655#else
656 printf("%d, %d\n", static_cast<int>(sample.fuse_voltage),
657 sample.fuse_current);
658#endif
659 }
660 }
661
662 return 0;
663}
664
665} // namespace motors
666} // namespace frc971