blob: c52f72a473c5f54fb7c61ddc8c0205c801baa9cc [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;
Brian Silverman37a95d62018-11-09 16:08:32 -080090 ::std::array<int16_t, 3> readings;
James Kuszmaul998d3032018-09-08 15:41:41 -070091 uint16_t position;
92 // Driver requested current.
93 float driver_request;
94 // Requested current.
95 int16_t total_command;
96
97 float est_omega;
98 float fuse_voltage;
99 int16_t fuse_current;
100
101 float fuse_badness;
102 uint32_t cycles_since_start;
103 };
104
105 // The amount of data in the buffer. This will never decrement. This will be
106 // transferred out the serial port after it fills up.
107 ::std::atomic<size_t> size{0};
108 ::std::atomic<uint32_t> count{0};
109 // The data.
110 ::std::array<Sample, 512> samples;
111};
112
113DebugBuffer global_debug_buffer;
114
115void ftm0_isr(void) {
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700116 static uint32_t i = 0;
117 teensy::AdcDmaSampler *const adc_dma =
118 global_adc_dma.load(::std::memory_order_relaxed);
119
James Kuszmaul998d3032018-09-08 15:41:41 -0700120 Fet12AdcReadings adc_readings;
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700121 // TODO(Brian): Switch to the DMA interrupt instead of spinning.
122 while (!adc_dma->CheckDone()) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700123 }
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700124
125 adc_readings.motor_currents[0] =
126 (adc_dma->adc_result(0, 0) + adc_dma->adc_result(0, 1)) / 2;
127 adc_readings.motor_currents[1] =
128 (adc_dma->adc_result(0, 2) + adc_dma->adc_result(1, 1)) / 2;
129 adc_readings.motor_currents[2] =
130 (adc_dma->adc_result(1, 0) + adc_dma->adc_result(1, 2)) / 2;
131 adc_readings.throttle = adc_dma->adc_result(0, 3);
James Kuszmaul998d3032018-09-08 15:41:41 -0700132 const ::std::array<float, 3> decoupled =
133 DecoupleCurrents(adc_readings.motor_currents);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700134 adc_dma->Reset();
135 const uint32_t wrapped_encoder =
136 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
James Kuszmaul998d3032018-09-08 15:41:41 -0700137 const BalancedReadings balanced =
138 BalanceSimpleReadings(decoupled);
139
James Kuszmaul521eb652018-10-17 19:09:33 -0700140#if 1
141
James Kuszmaul998d3032018-09-08 15:41:41 -0700142 static float fuse_badness = 0;
143
144 static uint32_t cycles_since_start = 0u;
145 ++cycles_since_start;
146#if 0
147 static int count = 0;
148 ++count;
149 static float currents[3] = {0.0f, 0.0f, 0.0f};
150 for (int ii = 0; ii < 3; ++ii) {
151 currents[ii] += static_cast<float>(adc_readings.motor_currents[ii]);
152 }
153
154 if (i == 0) {
155 printf(
156 "foo %d.0, %d.0, %d.0, %.3d %.3d %.3d, switching %d %d %d enc %d\n",
157 static_cast<int>(currents[0] / static_cast<float>(count)),
158 static_cast<int>(currents[1] / static_cast<float>(count)),
159 static_cast<int>(currents[2] / static_cast<float>(count)),
160 static_cast<int>(decoupled[0] * 1.0f),
161 static_cast<int>(decoupled[1] * 1.0f),
162 static_cast<int>(decoupled[2] * 1.0f),
163 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0),
164 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1),
165 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2),
166 static_cast<int>(
167 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder()));
168 count = 0;
169 currents[0] = 0.0f;
170 currents[1] = 0.0f;
171 currents[2] = 0.0f;
172 }
173#endif
174#if 1
175 constexpr float kAlpha = 0.995f;
176 constexpr float kFuseAlpha = 0.95f;
177
178 // 3400 - 760
James Kuszmaulb7707432018-10-07 14:48:11 -0700179 // Start the throttle filter at 1.0f--once it converges to near zero, we set
180 // throttle_zeroed to true and only then do we start listening to throttle
181 // commands.
182 static float filtered_throttle = 1.0f;
183 static bool throttle_zeroed = false;
James Kuszmaul998d3032018-09-08 15:41:41 -0700184 constexpr int kMaxThrottle = 3400;
185 constexpr int kMinThrottle = 760;
186 const float throttle = ::std::max(
187 0.0f,
188 ::std::min(1.0f,
189 static_cast<float>(static_cast<int>(adc_readings.throttle) -
190 kMinThrottle) /
191 static_cast<float>(kMaxThrottle - kMinThrottle)));
192
193 // y(n) = x(n) + a * (y(n-1) - x(n))
194 filtered_throttle = throttle + kAlpha * (filtered_throttle - throttle);
James Kuszmaulb7707432018-10-07 14:48:11 -0700195 if (::std::abs(filtered_throttle) < 1e-2f) {
196 // Once the filter gets near zero once, we start paying attention to it;
197 // once it gets near zero once, never ignore it again.
198 throttle_zeroed = true;
199 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700200
201 const float fuse_voltage = static_cast<float>(adc_readings.fuse_voltage);
202 static float filtered_fuse_voltage = 0.0f;
203
204 filtered_fuse_voltage =
205 fuse_voltage + kFuseAlpha * (filtered_fuse_voltage - fuse_voltage);
206
207 const float velocity =
208 global_motor.load(::std::memory_order_relaxed)->estimated_velocity();
209 const float bemf = velocity / (static_cast<float>(Kv) / 1.5f);
210 const float abs_bemf = ::std::abs(bemf);
211 constexpr float kPeakCurrent = 300.0f;
Brian Silverman37a95d62018-11-09 16:08:32 -0800212 constexpr float kLimitedCurrent = 70.0f;
James Kuszmaul998d3032018-09-08 15:41:41 -0700213 const float max_bat_cur =
214 fuse_badness > (kLimitedCurrent * kLimitedCurrent * 0.95f)
215 ? kLimitedCurrent
216 : static_cast<float>(kIcc);
217 const float throttle_limit = ::std::min(
218 kPeakCurrent,
219 (-abs_bemf + ::std::sqrt(static_cast<float>(
220 bemf * bemf +
221 4.0f * static_cast<float>(kR) * 1.5f *
222 static_cast<float>(kVcc) * max_bat_cur))) /
223 (2.0f * 1.5f * static_cast<float>(kR)));
224
James Kuszmaul521eb652018-10-17 19:09:33 -0700225 constexpr float kNegativeCurrent = 100.0f;
James Kuszmaula1d94c82018-10-10 20:00:09 -0700226 float goal_current =
227 -::std::min(
228 ::std::max(filtered_throttle * (kPeakCurrent + kNegativeCurrent) -
229 kNegativeCurrent,
230 -throttle_limit),
231 throttle_limit);
James Kuszmaul998d3032018-09-08 15:41:41 -0700232
James Kuszmaulb7707432018-10-07 14:48:11 -0700233 if (!throttle_zeroed) {
234 goal_current = 0.0f;
235 }
James Kuszmaula1d94c82018-10-10 20:00:09 -0700236 // Note: current reduction is 12/70 belt, 15 / 54 on chain, and 10 inch
237 // diameter wheels, so cutoff of 500 electrical rad/sec * 1 mechanical rad / 2
238 // erad * 12 / 70 * 15 / 54 * 0.127 m = 1.5m/s = 3.4 mph
James Kuszmaul998d3032018-09-08 15:41:41 -0700239 if (velocity > -500) {
240 if (goal_current > 0.0f) {
241 goal_current = 0.0f;
242 }
243 }
James Kuszmaul521eb652018-10-17 19:09:33 -0700244
James Kuszmaul998d3032018-09-08 15:41:41 -0700245 //float goal_current =
246 //-::std::min(filtered_throttle * kPeakCurrent, throttle_limit);
James Kuszmaul521eb652018-10-17 19:09:33 -0700247 const float overall_measured_current =
248 global_motor.load(::std::memory_order_relaxed)
249 ->overall_measured_current();
James Kuszmaul998d3032018-09-08 15:41:41 -0700250 const float fuse_current =
James Kuszmaul521eb652018-10-17 19:09:33 -0700251 overall_measured_current *
252 (bemf + overall_measured_current * static_cast<float>(kR) * 1.5f) /
James Kuszmaul998d3032018-09-08 15:41:41 -0700253 static_cast<float>(kVcc);
254 const int16_t fuse_current_10 = static_cast<int16_t>(10.0f * fuse_current);
255 fuse_badness += 0.00002f * (fuse_current * fuse_current - fuse_badness);
256
257 global_motor.load(::std::memory_order_relaxed)
258 ->SetGoalCurrent(goal_current);
259 global_motor.load(::std::memory_order_relaxed)
260 ->HandleInterrupt(balanced, wrapped_encoder);
James Kuszmaul998d3032018-09-08 15:41:41 -0700261
262 global_debug_buffer.count.fetch_add(1);
263
James Kuszmaul521eb652018-10-17 19:09:33 -0700264 const bool trigger = false && i > 10000;
James Kuszmaul998d3032018-09-08 15:41:41 -0700265 // global_debug_buffer.count.load(::std::memory_order_relaxed) >= 0;
266 size_t buffer_size =
267 global_debug_buffer.size.load(::std::memory_order_relaxed);
268 if ((buffer_size > 0 || trigger) &&
269 buffer_size != global_debug_buffer.samples.size()) {
270 global_debug_buffer.samples[buffer_size].currents[0] =
271 static_cast<int16_t>(balanced.readings[0] * 10.0f);
272 global_debug_buffer.samples[buffer_size].currents[1] =
273 static_cast<int16_t>(balanced.readings[1] * 10.0f);
274 global_debug_buffer.samples[buffer_size].currents[2] =
275 static_cast<int16_t>(balanced.readings[2] * 10.0f);
276 global_debug_buffer.samples[buffer_size].position =
277 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
278 global_debug_buffer.samples[buffer_size].est_omega =
279 global_motor.load(::std::memory_order_relaxed)->estimated_velocity();
280 global_debug_buffer.samples[buffer_size].commands[0] =
281 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(0);
282 global_debug_buffer.samples[buffer_size].commands[1] =
283 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(1);
284 global_debug_buffer.samples[buffer_size].commands[2] =
285 global_motor.load(::std::memory_order_relaxed)->get_switching_points_cycles(2);
286 global_debug_buffer.samples[buffer_size].commanded_currents[0] =
287 global_motor.load(::std::memory_order_relaxed)->i_goal(0);
288 global_debug_buffer.samples[buffer_size].commanded_currents[1] =
289 global_motor.load(::std::memory_order_relaxed)->i_goal(1);
290 global_debug_buffer.samples[buffer_size].commanded_currents[2] =
291 global_motor.load(::std::memory_order_relaxed)->i_goal(2);
292 global_debug_buffer.samples[buffer_size].total_command =
293 global_motor.load(::std::memory_order_relaxed)->goal_current();
294 global_debug_buffer.samples[buffer_size].fuse_voltage =
295 filtered_fuse_voltage;
296 global_debug_buffer.samples[buffer_size].fuse_current = fuse_current_10;
297 global_debug_buffer.samples[buffer_size].driver_request =
298 ::std::max(filtered_throttle * (kPeakCurrent + kNegativeCurrent) -
299 kNegativeCurrent,
300 0.0f);
301 global_debug_buffer.samples[buffer_size].fuse_badness = fuse_badness;
302 global_debug_buffer.samples[buffer_size].cycles_since_start = cycles_since_start;
303
304 global_debug_buffer.size.fetch_add(1);
305 }
306
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700307 ++i;
James Kuszmaul998d3032018-09-08 15:41:41 -0700308 if (buffer_size == global_debug_buffer.samples.size()) {
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700309 i = 0;
James Kuszmaul998d3032018-09-08 15:41:41 -0700310 GPIOC_PCOR = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
311 GPIOD_PCOR = (1 << 4) | (1 << 5);
312
313 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
314 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
315 PERIPHERAL_BITBAND(GPIOC_PDDR, 3) = 1;
316 PERIPHERAL_BITBAND(GPIOC_PDDR, 4) = 1;
317 PERIPHERAL_BITBAND(GPIOD_PDDR, 4) = 1;
318 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
319
320 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
321 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
322 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
323 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
324 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
325 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
326 }
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700327#endif
328#else
James Kuszmaul521eb652018-10-17 19:09:33 -0700329 // Useful code when calculating resistance/inductance of motor
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700330 FTM0->SC &= ~FTM_SC_TOF;
331 FTM0->C0V = 0;
332 FTM0->C1V = 0;
333 FTM0->C2V = 0;
Brian Silverman37a95d62018-11-09 16:08:32 -0800334 FTM0->C3V = 20;
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700335 FTM0->C4V = 0;
Brian Silverman37a95d62018-11-09 16:08:32 -0800336 FTM0->C5V = 0;
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700337 FTM0->PWMLOAD = FTM_PWMLOAD_LDOK;
James Kuszmaul521eb652018-10-17 19:09:33 -0700338 (void)wrapped_encoder;
James Kuszmaul521eb652018-10-17 19:09:33 -0700339 size_t buffer_size =
340 global_debug_buffer.size.load(::std::memory_order_relaxed);
Brian Silverman37a95d62018-11-09 16:08:32 -0800341 // Setting this to true is helpful for calibrating inductance, and false is
342 // good for calibrating resistance.
343 constexpr bool start_immediately = true;
344 bool trigger = start_immediately || i > 20000;
James Kuszmaul521eb652018-10-17 19:09:33 -0700345 if ((trigger || buffer_size > 0) &&
346 buffer_size != global_debug_buffer.samples.size()) {
347 global_debug_buffer.samples[buffer_size].currents[0] =
348 static_cast<int16_t>(balanced.readings[0] * 10.0f);
349 global_debug_buffer.samples[buffer_size].currents[1] =
350 static_cast<int16_t>(balanced.readings[1] * 10.0f);
351 global_debug_buffer.samples[buffer_size].currents[2] =
352 static_cast<int16_t>(balanced.readings[2] * 10.0f);
353 global_debug_buffer.samples[buffer_size].commands[0] = FTM0->C1V;
354 global_debug_buffer.samples[buffer_size].commands[1] = FTM0->C3V;
355 global_debug_buffer.samples[buffer_size].commands[2] = FTM0->C5V;
Brian Silverman37a95d62018-11-09 16:08:32 -0800356 global_debug_buffer.samples[buffer_size].readings[0] =
357 adc_readings.motor_currents[0];
358 global_debug_buffer.samples[buffer_size].readings[1] =
359 adc_readings.motor_currents[1];
360 global_debug_buffer.samples[buffer_size].readings[2] =
361 adc_readings.motor_currents[2];
James Kuszmaul521eb652018-10-17 19:09:33 -0700362 global_debug_buffer.samples[buffer_size].position =
363 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder();
364 global_debug_buffer.size.fetch_add(1);
365 }
366 if (buffer_size == global_debug_buffer.samples.size()) {
367 GPIOC_PCOR = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
368 GPIOD_PCOR = (1 << 4) | (1 << 5);
369
370 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
371 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
372 PERIPHERAL_BITBAND(GPIOC_PDDR, 3) = 1;
373 PERIPHERAL_BITBAND(GPIOC_PDDR, 4) = 1;
374 PERIPHERAL_BITBAND(GPIOD_PDDR, 4) = 1;
375 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
376
377 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
378 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
379 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
380 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
381 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(1);
382 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
383 i = 0;
384 }
385 ++i;
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700386#endif
James Kuszmaul998d3032018-09-08 15:41:41 -0700387
James Kuszmaul998d3032018-09-08 15:41:41 -0700388}
389
390} // extern "C"
391
392void ConfigurePwmFtm(BigFTM *pwm_ftm) {
393 // Put them all into combine active-high mode, and all the low ones staying on
394 // all the time by default.
395 pwm_ftm->C0SC = FTM_CSC_ELSA;
396 pwm_ftm->C0V = 0;
397 pwm_ftm->C1SC = FTM_CSC_ELSA;
398 pwm_ftm->C1V = 0;
399 pwm_ftm->C2SC = FTM_CSC_ELSA;
400 pwm_ftm->C2V = 0;
401 pwm_ftm->C3SC = FTM_CSC_ELSA;
402 pwm_ftm->C3V = 0;
403 pwm_ftm->C4SC = FTM_CSC_ELSA;
404 pwm_ftm->C4V = 0;
405 pwm_ftm->C5SC = FTM_CSC_ELSA;
406 pwm_ftm->C5V = 0;
407 pwm_ftm->C6SC = FTM_CSC_ELSA;
408 pwm_ftm->C6V = 0;
409 pwm_ftm->C7SC = FTM_CSC_ELSA;
410 pwm_ftm->C7V = 0;
411
412 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
413 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
414 FTM_COMBINE_COMP3 /* Make them complementary */ |
415 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
416 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
417 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
418 FTM_COMBINE_COMP2 /* Make them complementary */ |
419 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
420 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
421 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
422 FTM_COMBINE_COMP1 /* Make them complementary */ |
423 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
424 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
425 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
426 FTM_COMBINE_COMP0 /* Make them complementary */ |
427 FTM_COMBINE_COMBINE0 /* Combine the channels */;
428 // Safe state for all channels is low.
429 pwm_ftm->POL = 0;
430
431 // Set the deadtime.
432 pwm_ftm->DEADTIME =
433 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
434
435 pwm_ftm->CONF =
436 FTM_CONF_BDMMOD(1) /* Set everything to POLn during debug halt */;
437}
438
439// Zeros the encoder. This involves blocking for an arbitrary length of time
440// with interrupts disabled.
441void ZeroMotor() {
442#if 0
443 while (true) {
444 if (PERIPHERAL_BITBAND(GPIOB_PDIR, 11)) {
445 encoder_ftm_->CNT = 0;
446 break;
447 }
448 }
449#else
450 uint32_t scratch;
451 __disable_irq();
452 // Stuff all of this in an inline assembly statement so we can make sure the
453 // compiler doesn't decide sticking constant loads etc in the middle of
454 // the loop is a good idea, because that increases the latency of recognizing
455 // the index pulse edge which makes velocity affect the zeroing accuracy.
456 __asm__ __volatile__(
457 // A label to restart the loop.
458 "0:\n"
459 // Load the current PDIR value for the pin we care about.
460 "ldr %[scratch], [%[pdir_word]]\n"
461 // Terminate the loop if it's non-0.
462 "cbnz %[scratch], 1f\n"
463 // Go back around again.
464 "b 0b\n"
465 // A label to finish the loop.
466 "1:\n"
467 // Reset the count once we're down here. It doesn't actually matter what
468 // value we store because writing anything resets it to CNTIN (ie 0).
469 "str %[scratch], [%[cnt]]\n"
470 : [scratch] "=&l"(scratch)
471 : [pdir_word] "l"(&PERIPHERAL_BITBAND(GPIOB_PDIR, 11)),
472 [cnt] "l"(&FTM1->CNT));
473 __enable_irq();
474#endif
475}
476
477} // namespace
478
479extern "C" int main(void) {
480 // for background about this startup delay, please see these conversations
481 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
482 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
483 delay(400);
484
485 // Set all interrupts to the second-lowest priority to start with.
486 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
487
488 // Now set priorities for all the ones we care about. They only have meaning
489 // relative to each other, which means centralizing them here makes it a lot
490 // more manageable.
491 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
492 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0xE);
493
494 // Set the LED's pin to output mode.
495 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
496 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
497
498#if 0
499 PERIPHERAL_BITBAND(GPIOA_PDDR, 15) = 1;
500 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
501#endif
502
503 // Set up the CAN pins.
504 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
505 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
506
507 DMA.CR = M_DMA_EMLM;
508
509 PORTB_PCR16 = PORT_PCR_DSE | PORT_PCR_MUX(3);
510 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(3);
511 SIM_SCGC4 |= SIM_SCGC4_UART0;
Brian Silverman4787a6e2018-10-06 16:00:54 -0700512
513 PrintingParameters printing_parameters;
514 printing_parameters.stdout_uart_module = &UART0;
515 printing_parameters.stdout_uart_module_clock_frequency = F_CPU;
516 printing_parameters.stdout_uart_status_interrupt = IRQ_UART0_STATUS;
517 printing_parameters.dedicated_usb = true;
518 const ::std::unique_ptr<PrintingImplementation> printing =
519 CreatePrinting(printing_parameters);
520 printing->Initialize();
James Kuszmaul998d3032018-09-08 15:41:41 -0700521
522 AdcInitFet12();
523 MathInit();
524 delay(100);
525 can_init(0, 1);
526
527 MotorControlsImplementation controls;
528
529 delay(100);
530
531 // Index pin
532 PORTB_PCR11 = PORT_PCR_MUX(1);
533 // FTM1_QD_PH{A,B}
534 PORTB_PCR0 = PORT_PCR_MUX(6);
535 PORTB_PCR1 = PORT_PCR_MUX(6);
536
537 // FTM0_CH[0-5]
538 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
539 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
540 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
541 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
542 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
543 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
544
545 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
546 motor.set_encoder_offset(810);
547 motor.set_deadtime_compensation(9);
548 ConfigurePwmFtm(FTM0);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700549
Brian Silvermana1d84822018-09-15 17:18:49 -0700550 // TODO(Brian): Figure out how to avoid duplicating this code to slave one FTM
551 // to another.
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700552 FTM2->CONF = FTM_CONF_GTBEEN;
553 FTM2->MODE = FTM_MODE_WPDIS;
554 FTM2->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
555 FTM2->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
556 FTM2->CNTIN = 0;
557 FTM2->CNT = 0;
558 // TODO(Brian): Don't duplicate this.
559 FTM2->MOD = BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY;
560 FTM2->OUTINIT = 0;
561 // All of the channels are active high.
562 FTM2->POL = 0;
563 FTM2->SYNCONF = FTM_SYNCONF_HWWRBUF | FTM_SYNCONF_SWWRBUF |
564 FTM_SYNCONF_SWRSTCNT | FTM_SYNCONF_SYNCMODE;
565 // Don't want any intermediate loading points.
566 FTM2->PWMLOAD = 0;
567
568 // Need to set them to some kind of output mode so we can actually change
569 // them.
570 FTM2->C0SC = FTM_CSC_MSA;
571 FTM2->C1SC = FTM_CSC_MSA;
572
573 // This has to happen after messing with SYNCONF, and should happen after
574 // messing with various other things so the values can get flushed out of the
575 // buffers.
576 FTM2->SYNC =
577 FTM_SYNC_SWSYNC /* Flush everything out right now */ |
578 FTM_SYNC_CNTMAX /* Load new values at the end of the cycle */;
579 // Wait for the software synchronization to finish.
580 while (FTM2->SYNC & FTM_SYNC_SWSYNC) {
581 }
582 FTM2->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
583 FTM_SC_PS(0) /* Don't prescale the clock */;
584 // TODO:
585 //FTM2->MODE &= ~FTM_MODE_WPDIS;
586
587 FTM2->EXTTRIG = FTM_EXTTRIG_CH0TRIG | FTM_EXTTRIG_CH1TRIG;
588
Brian Silvermana1d84822018-09-15 17:18:49 -0700589 // TODO(Brian): Don't duplicate the timer's MOD value.
590 teensy::AdcDmaSampler adc_dma{BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY};
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700591 // ADC0_Dx0 is 1-0
592 // ADC0_Dx2 is 1-2
593 // ADC0_Dx3 is 2-0
594 // ADC1_Dx0 is 2-0
595 // ADC1_Dx3 is 1-0
596 // Sample 0: 1-2,2-0
597 // Sample 1: 1-2,1-0
598 // Sample 2: 1-0,2-0
599 // Sample 3: 23(SENSE0),18(VIN)
600 adc_dma.set_adc0_samples({V_ADC_ADCH(2) | M_ADC_DIFF,
601 V_ADC_ADCH(2) | M_ADC_DIFF,
602 V_ADC_ADCH(0) | M_ADC_DIFF, V_ADC_ADCH(23)});
603 adc_dma.set_adc1_samples({V_ADC_ADCH(0) | M_ADC_DIFF,
604 V_ADC_ADCH(3) | M_ADC_DIFF,
605 V_ADC_ADCH(0) | M_ADC_DIFF, V_ADC_ADCH(18)});
606 adc_dma.set_ftm_delays({&FTM2->C0V, &FTM2->C1V});
607 adc_dma.set_pdb_input(PDB_IN_FTM2);
608
609 adc_dma.Initialize();
610 FTM0->CONF = FTM_CONF_GTBEEN;
James Kuszmaul998d3032018-09-08 15:41:41 -0700611 motor.Init();
612 global_motor.store(&motor, ::std::memory_order_relaxed);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700613 global_adc_dma.store(&adc_dma, ::std::memory_order_relaxed);
614
James Kuszmaul998d3032018-09-08 15:41:41 -0700615 // Output triggers to things like the PDBs on initialization.
616 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
617 // Don't let any memory accesses sneak past here, because we actually
618 // need everything to be starting up.
619 __asm__("" :: : "memory");
620
621 // Give everything a chance to get going.
622 delay(100);
623
624 printf("Ram start: %p\n", __bss_ram_start__);
625 printf("Heap start: %p\n", __heap_start__);
626 printf("Heap end: %p\n", __brkval);
627 printf("Stack start: %p\n", __stack_end__);
628
629 printf("Going silent to zero motors...\n");
630 // Give the print a chance to make it out.
631 delay(100);
632 ZeroMotor();
633
634 motor.set_encoder_multiplier(-1);
635 motor.set_encoder_calibration_offset(
James Kuszmaul521eb652018-10-17 19:09:33 -0700636 364 /*from running constant phases*/ - 26 /*average offset from lstsq*/ -
637 14 /* compensation for going backwards */);
James Kuszmaul998d3032018-09-08 15:41:41 -0700638
639 printf("Zeroed motor!\n");
640 // Give stuff a chance to recover from interrupts-disabled.
641 delay(100);
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700642 adc_dma.Reset();
James Kuszmaul998d3032018-09-08 15:41:41 -0700643 motor.Start();
James Kuszmaul7c8aad62018-09-08 18:16:18 -0700644 // Now poke the GTB to actually start both timers.
645 FTM0->CONF = FTM_CONF_GTBEEN | FTM_CONF_GTBEOUT;
646
James Kuszmaul998d3032018-09-08 15:41:41 -0700647 NVIC_ENABLE_IRQ(IRQ_FTM0);
648 GPIOC_PSOR = 1 << 5;
649
Brian Silverman37a95d62018-11-09 16:08:32 -0800650 constexpr bool dump_full_sample = false;
James Kuszmaul521eb652018-10-17 19:09:33 -0700651 constexpr bool dump_resist_calib = false;
Brian Silverman37a95d62018-11-09 16:08:32 -0800652 constexpr bool repeat_calib = true;
James Kuszmaul998d3032018-09-08 15:41:41 -0700653 while (true) {
James Kuszmaul521eb652018-10-17 19:09:33 -0700654 if (dump_resist_calib || dump_full_sample) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700655 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
656 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
657 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
658 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
659 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
660 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
661 motor.Reset();
662 }
663 global_debug_buffer.size.store(0);
664 global_debug_buffer.count.store(0);
665 while (global_debug_buffer.size.load(::std::memory_order_relaxed) <
666 global_debug_buffer.samples.size()) {
667 }
James Kuszmaul521eb652018-10-17 19:09:33 -0700668 if (dump_resist_calib) {
669 // Useful prints for when calibrating resistance/inductance of motor
670 for (size_t i = 0; i < global_debug_buffer.samples.size(); ++i) {
671 const auto &sample = global_debug_buffer.samples[i];
Brian Silverman37a95d62018-11-09 16:08:32 -0800672#if 1
James Kuszmaul521eb652018-10-17 19:09:33 -0700673 printf("%u, %d, %d, %d, %u, %u, %u, %u\n", i,
674 sample.currents[0], sample.currents[1], sample.currents[2],
675 sample.commands[0], sample.commands[1], sample.commands[2],
676 sample.position);
Brian Silverman37a95d62018-11-09 16:08:32 -0800677#else
678 printf("%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRId16 ",%" PRId16
679 ",%" PRId16 "\n",
680 sample.commands[0], sample.commands[1], sample.commands[2],
681 sample.readings[0], sample.readings[1], sample.readings[2]);
682#endif
James Kuszmaul521eb652018-10-17 19:09:33 -0700683 }
684 } else if (dump_full_sample) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700685 printf("Dumping data\n");
686 for (size_t i = 0; i < global_debug_buffer.samples.size(); ++i) {
687 const auto &sample = global_debug_buffer.samples[i];
688
689 printf("%u, %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d\n", i,
690 sample.currents[0], sample.currents[1], sample.currents[2],
691 sample.commands[0], sample.commands[1], sample.commands[2],
692 sample.position, static_cast<int>(sample.est_omega),
693 sample.commanded_currents[0], sample.commanded_currents[1],
694 sample.commanded_currents[2]);
695 }
696 printf("Done dumping data\n");
697 } else {
698 //const auto &sample = global_debug_buffer.samples.back();
699 const DebugBuffer::Sample sample = global_debug_buffer.samples[0];
700#if 1
701 printf("%" PRIu32
702 ", %d, %d, %d, %u, %u, %u, %u, %d, %d, %d, %d, %d, %d, %d\n",
703 sample.cycles_since_start, sample.currents[0], sample.currents[1],
704 sample.currents[2], sample.commands[0], sample.commands[1],
705 sample.commands[2], sample.position,
706 static_cast<int>(sample.est_omega), sample.commanded_currents[0],
707 sample.commanded_currents[1], sample.commanded_currents[2],
708 sample.total_command, static_cast<int>(sample.driver_request),
709 static_cast<int>(sample.fuse_badness));
710#else
711 printf("%d, %d\n", static_cast<int>(sample.fuse_voltage),
712 sample.fuse_current);
713#endif
714 }
Brian Silverman37a95d62018-11-09 16:08:32 -0800715 if (!repeat_calib) {
716 while (true) {
717 }
718 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700719 }
720
721 return 0;
722}
723
724} // namespace motors
725} // namespace frc971