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