blob: 1b9f2e54a2f113b9a48d9f43cb3d35cda19bcf19 [file] [log] [blame]
Brian Silverman8d3816a2017-07-03 18:52:15 -07001#include "motors/motor.h"
2
3#include <limits.h>
Brian Silverman19ea60f2018-01-03 21:43:15 -08004#include <stdio.h>
5#include <inttypes.h>
Brian Silverman8d3816a2017-07-03 18:52:15 -07006
7#include <array>
8
9#include "motors/peripheral/configuration.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -070010#include "motors/peripheral/can.h"
11
Brian Silverman19ea60f2018-01-03 21:43:15 -080012extern "C" float analog_ratio(uint16_t reading);
Brian Silverman6260c092018-01-14 15:21:36 -080013extern "C" float absolute_wheel(uint16_t reading);
Brian Silverman19ea60f2018-01-03 21:43:15 -080014
Brian Silverman8d3816a2017-07-03 18:52:15 -070015namespace frc971 {
Brian Silvermana96c1a42018-05-12 12:11:31 -070016namespace motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -070017
Brian Silverman19ea60f2018-01-03 21:43:15 -080018Motor::Motor(BigFTM *pwm_ftm, LittleFTM *encoder_ftm, MotorControls *controls,
19 const ::std::array<volatile uint32_t *, 3> &output_registers)
20 : pwm_ftm_(pwm_ftm),
21 encoder_ftm_(encoder_ftm),
22 controls_(controls),
23 output_registers_(output_registers) {
Brian Silverman8d3816a2017-07-03 18:52:15 -070024 // PWMSYNC doesn't matter because we set SYNCMODE down below.
25 pwm_ftm_->MODE = FTM_MODE_WPDIS;
26 pwm_ftm_->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
27 encoder_ftm_->MODE = FTM_MODE_WPDIS;
28 encoder_ftm_->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
29
30 pwm_ftm_->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
31 encoder_ftm_->SC =
32 FTM_SC_CLKS(1) /* Use the system clock (not sure it matters) */ |
33 FTM_SC_PS(0) /* Don't prescale the clock (not sure it matters) */;
Brian Silverman19ea60f2018-01-03 21:43:15 -080034}
Brian Silverman8d3816a2017-07-03 18:52:15 -070035
Brian Silverman19ea60f2018-01-03 21:43:15 -080036static_assert((BUS_CLOCK_FREQUENCY % SWITCHING_FREQUENCY) == 0,
37 "Switching frequency needs to divide the bus clock frequency");
38
39static_assert(BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY < UINT16_MAX,
40 "Need to prescale");
41
42void Motor::Init() {
Brian Silverman8d3816a2017-07-03 18:52:15 -070043 pwm_ftm_->CNTIN = encoder_ftm_->CNTIN = 0;
44 pwm_ftm_->CNT = encoder_ftm_->CNT = 0;
45
Brian Silverman19ea60f2018-01-03 21:43:15 -080046 pwm_ftm_->MOD = counts_per_cycle() - 1;
47 encoder_ftm_->MOD = controls_->mechanical_counts_per_revolution() - 1;
Brian Silverman8d3816a2017-07-03 18:52:15 -070048
49 // I think you have to set this to something other than 0 for the quadrature
50 // encoder mode to actually work? This is "input capture on rising edge only",
51 // which should be fine.
52 encoder_ftm_->C0SC = FTM_CSC_ELSA;
53 encoder_ftm_->C1SC = FTM_CSC_ELSA;
54
55 // Initialize all the channels to 0.
Brian Silverman8d3816a2017-07-03 18:52:15 -070056 pwm_ftm_->OUTINIT = 0;
57
Brian Silverman19ea60f2018-01-03 21:43:15 -080058 // All of the channels are active high (low-side ones with separate high/low
59 // drives are defaulted on elsewhere).
Brian Silverman8d3816a2017-07-03 18:52:15 -070060 pwm_ftm_->POL = 0;
61
62 encoder_ftm_->FILTER = FTM_FILTER_CH0FVAL(0) /* No filter */ |
63 FTM_FILTER_CH1FVAL(0) /* No filter */;
64
65 // Could set PHAFLTREN and PHBFLTREN here to enable the filters.
66 encoder_ftm_->QDCTRL = FTM_QDCTRL_QUADEN;
67
68 pwm_ftm_->SYNCONF =
69 FTM_SYNCONF_HWWRBUF /* Hardware trigger flushes switching points */ |
70 FTM_SYNCONF_SWWRBUF /* Software trigger flushes switching points */ |
71 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
72 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
73 encoder_ftm_->SYNCONF =
74 FTM_SYNCONF_SWWRBUF /* Software trigger flushes MOD */ |
75 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
76 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
77
78 // Don't want any intermediate loading points.
79 pwm_ftm_->PWMLOAD = 0;
80
81 // This has to happen after messing with SYNCONF, and should happen after
82 // messing with various other things so the values can get flushed out of the
83 // buffers.
84 pwm_ftm_->SYNC =
85 FTM_SYNC_SWSYNC /* Flush everything out right now */ |
86 FTM_SYNC_CNTMAX /* Load new values at the end of the cycle */;
87 encoder_ftm_->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
88
89 // Wait for the software synchronization to finish.
90 while (pwm_ftm_->SYNC & FTM_SYNC_SWSYNC) {
91 }
92 while (encoder_ftm_->SYNC & FTM_SYNC_SWSYNC) {
93 }
94}
95
Brian Silverman8d3816a2017-07-03 18:52:15 -070096void Motor::Start() {
97 pwm_ftm_->SC = FTM_SC_TOIE /* Interrupt on overflow */ |
98 FTM_SC_CLKS(1) /* Use the system clock */ |
99 FTM_SC_PS(0) /* Don't prescale the clock */;
100 pwm_ftm_->MODE &= ~FTM_MODE_WPDIS;
101 encoder_ftm_->MODE &= ~FTM_MODE_WPDIS;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700102}
103
Brian Silverman19ea60f2018-01-03 21:43:15 -0800104#define USE_ABSOLUTE_CUTOFF 0
105#define DO_CONTROLS 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700106
Brian Silverman19ea60f2018-01-03 21:43:15 -0800107#define USE_CUTOFF 1
108#define PRINT_READINGS 0
109#define PRINT_ALL_READINGS 0
110#define TAKE_SAMPLE 0
111#define SAMPLE_UNTIL_DONE 0
112#define DO_STEP_RESPONSE 0
113#define DO_PULSE_SWEEP 0
114#define PRINT_TIMING 0
Brian Silverman8d3816a2017-07-03 18:52:15 -0700115
Austin Schuh6bf82752019-04-07 13:55:01 -0700116void Motor::CycleFixedPhaseInterupt() {
117 pwm_ftm_->SC &= ~FTM_SC_TOF;
118 // Step through all the phases one by one in a loop. This should slowly move
119 // the trigger.
120 // If we fire phase 1, we should go to PI radians.
121 // If we fire phase 2, we should go to 1.0 * PI / 3.0 radians.
122 // If we fire phase 3, we should go to -1.0 * PI / 3.0 radians.
123 // These numbers were confirmed by the python motor simulation.
124 static int phase_to_fire_count = -300000;
125 static int phase_to_fire = 0;
126 ++phase_to_fire_count;
127 if (phase_to_fire_count > 500000) {
128 phase_to_fire_count = 0;
129 ++phase_to_fire;
130 if (phase_to_fire > 2) {
131 phase_to_fire = 0;
132 }
133 }
134 phase_to_fire = 0;
135
136 // An on-width of 60 with 30V in means about 50A through the motor and about
137 // 30W total power dumped by the motor for the big one.
138 // For the small one, an on-width of 120/3000 with 14V in means about 2A
139 // through the motor.
140 //constexpr int kPhaseFireWidth = 80;
141 constexpr int kPhaseFireWidth = 80;
142 output_registers_[0][0] = 0;
143 output_registers_[0][2] = phase_to_fire == 0 ? kPhaseFireWidth : 0;
144
145 const float switching_points_max = static_cast<float>(counts_per_cycle());
146 switching_points_ratio_[0] =
147 static_cast<float>(output_registers_[0][2]) / switching_points_max;
148 output_registers_[1][0] = 0;
149 output_registers_[1][2] = phase_to_fire == 1 ? kPhaseFireWidth : 0;
150 switching_points_ratio_[1] =
151 static_cast<float>(output_registers_[1][2]) / switching_points_max;
152 output_registers_[2][0] = 0;
153 output_registers_[2][2] = phase_to_fire == 2 ? kPhaseFireWidth : 0;
154 switching_points_ratio_[2] =
155 static_cast<float>(output_registers_[2][2]) / switching_points_max;
156
157 // Tell the hardware to use the new switching points.
158 // TODO(Brian): Somehow verify that we consistently hit the first or second
159 // timer-cycle with the new values (if there's two).
160 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
161
162 // If another cycle has already started, turn the light on right now.
163 if (pwm_ftm_->SC & FTM_SC_TOF) {
164 GPIOC_PSOR = 1 << 5;
165 }
166}
167
Austin Schuh54c8c842019-04-07 13:54:23 -0700168void Motor::CurrentInterrupt(const BalancedReadings &balanced,
169 uint32_t captured_wrapped_encoder) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800170 pwm_ftm_->SC &= ~FTM_SC_TOF;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700171
Brian Silverman19ea60f2018-01-03 21:43:15 -0800172#if PRINT_TIMING
173 const uint32_t start_nanos = nanos();
James Kuszmaul998d3032018-09-08 15:41:41 -0700174#endif // PRINT_TIMING
Brian Silverman8d3816a2017-07-03 18:52:15 -0700175
Brian Silverman19ea60f2018-01-03 21:43:15 -0800176 if (!time_after(time_add(last_current_set_time_, 100000), micros())) {
177 goal_current_ = 0;
178 }
179
Brian Silverman8d3816a2017-07-03 18:52:15 -0700180#if DO_CONTROLS
James Kuszmaul998d3032018-09-08 15:41:41 -0700181 switching_points_ratio_ = controls_->DoIteration(
182 balanced.readings, captured_wrapped_encoder, goal_current_);
183 const float switching_points_max = static_cast<float>(counts_per_cycle());
184 const ::std::array<uint32_t, 3> switching_points = {
185 static_cast<uint32_t>(switching_points_ratio_[0] * switching_points_max),
186 static_cast<uint32_t>(switching_points_ratio_[1] * switching_points_max),
187 static_cast<uint32_t>(switching_points_ratio_[2] * switching_points_max)};
Brian Silverman19ea60f2018-01-03 21:43:15 -0800188#if USE_CUTOFF
James Kuszmaul998d3032018-09-08 15:41:41 -0700189 constexpr uint32_t kMax = 2995;
190 //constexpr uint32_t kMax = 1445;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700191 static bool done = false;
192 bool done_now = false;
193 if (switching_points[0] > kMax || switching_points[1] > kMax ||
194 switching_points[2] > kMax) {
195 done_now = true;
196 }
Brian Silverman8d3816a2017-07-03 18:52:15 -0700197#if USE_ABSOLUTE_CUTOFF
198 static unsigned int current_done_count = 0;
199 bool current_done = false;
200 for (int phase = 0; phase < 3; ++phase) {
201 const float scaled_reading =
Brian Silverman19ea60f2018-01-03 21:43:15 -0800202 controls_->scale_current_reading(balanced.readings[phase]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700203 static constexpr float kMaxBalancedCurrent = 50.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700204 if (scaled_reading > kMaxBalancedCurrent ||
205 scaled_reading < -kMaxBalancedCurrent) {
206 current_done = true;
207 }
208 }
209 if (current_done) {
210 if (current_done_count > 5) {
211 done_now = true;
212 }
213 ++current_done_count;
214 } else {
215 current_done_count = 0;
216 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700217#endif // USE_ABSOLUTE_CUTOFF
Brian Silverman8d3816a2017-07-03 18:52:15 -0700218 if (done_now && !done) {
219 printf("done now\n");
220 printf("switching_points %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
221 switching_points[0], switching_points[1], switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700222 printf("balanced %" PRIu16 " %" PRIu16 " %" PRIu16 "\n",
223 static_cast<uint16_t>(balanced.readings[0]),
224 static_cast<uint16_t>(balanced.readings[1]),
225 static_cast<uint16_t>(balanced.readings[2]));
226 done = true;
227 }
228 if (!done) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700229#else // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800230 if (true) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700231#endif // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800232 output_registers_[0][0] = CalculateOnTime(switching_points[0]);
233 output_registers_[0][2] = CalculateOffTime(switching_points[0]);
234 output_registers_[1][0] = CalculateOnTime(switching_points[1]);
235 output_registers_[1][2] = CalculateOffTime(switching_points[1]);
236 output_registers_[2][0] = CalculateOnTime(switching_points[2]);
237 output_registers_[2][2] = CalculateOffTime(switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700238 flip_time_offset_ = !flip_time_offset_;
239 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800240 output_registers_[0][0] = 0;
241 output_registers_[0][2] = 0;
242 output_registers_[1][0] = 0;
243 output_registers_[1][2] = 0;
244 output_registers_[2][0] = 0;
245 output_registers_[2][2] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700246 }
Austin Schuh6bf82752019-04-07 13:55:01 -0700247#endif // DO_CONTROLS
Brian Silverman6260c092018-01-14 15:21:36 -0800248 (void)balanced;
249 (void)captured_wrapped_encoder;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700250#if PRINT_READINGS
251 static int i = 0;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800252 if (i == 1000) {
Brian Silverman8d3816a2017-07-03 18:52:15 -0700253 i = 0;
James Kuszmaul998d3032018-09-08 15:41:41 -0700254 //SmallInitReadings readings;
255 //{
256 //DisableInterrupts disable_interrupts;
257 //readings = AdcReadSmallInit(disable_interrupts);
258 //}
Brian Silverman6260c092018-01-14 15:21:36 -0800259 //printf(
260 //"enc %" PRIu32 " %d %d\n", captured_wrapped_encoder,
261 //static_cast<int>((1.0f - analog_ratio(readings.motor1_abs)) * 7000.0f),
262 //static_cast<int>(captured_wrapped_encoder * 7.0f / 4096.0f * 1000.0f));
James Kuszmaul998d3032018-09-08 15:41:41 -0700263 //float wheel_position = absolute_wheel(analog_ratio(readings.wheel_abs));
Brian Silverman6260c092018-01-14 15:21:36 -0800264
Brian Silverman19ea60f2018-01-03 21:43:15 -0800265 printf(
James Kuszmaul998d3032018-09-08 15:41:41 -0700266 "ecnt %" PRIu32
267 //" arev:%d"
268 " erev:%d"
269 //" %d"
270 "\n", captured_wrapped_encoder,
271 //static_cast<int>((analog_ratio(readings.motor1_abs)) * 7000.0f),
272 static_cast<int>(captured_wrapped_encoder / 4096.0f * 1000.0f)
273 //static_cast<int>(wheel_position * 1000.0f)
274 );
Brian Silverman19ea60f2018-01-03 21:43:15 -0800275 } else if (i == 200) {
Brian Silverman6260c092018-01-14 15:21:36 -0800276#if DO_CONTROLS
Brian Silverman19ea60f2018-01-03 21:43:15 -0800277 printf("out %" PRIu32 " %" PRIu32 " %" PRIu32 "\n", switching_points[0],
278 switching_points[1], switching_points[2]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700279#else // DO_CONTROLS
Brian Silverman19ea60f2018-01-03 21:43:15 -0800280 printf("out %" PRIu32 " %" PRIu32 " %" PRIu32 "\n", output_registers_[0][2],
281 output_registers_[1][2], output_registers_[2][2]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700282#endif // DO_CONTROLS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700283 }
284 ++i;
James Kuszmaul998d3032018-09-08 15:41:41 -0700285#elif PRINT_ALL_READINGS // PRINT_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700286 printf("ref=%" PRIu16 " 0.0=%" PRIu16 " 1.0=%" PRIu16 " 2.0=%" PRIu16
287 " in=%" PRIu16 " 0.1=%" PRIu16 " 1.1=%" PRIu16 " 2.1=%" PRIu16 "\n",
288 adc_readings.motor_current_ref, adc_readings.motor_currents[0][0],
289 adc_readings.motor_currents[1][0], adc_readings.motor_currents[2][0],
290 adc_readings.input_voltage, adc_readings.motor_currents[0][1],
291 adc_readings.motor_currents[1][1], adc_readings.motor_currents[2][1]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700292#elif TAKE_SAMPLE // PRINT_READINGS/PRINT_ALL_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700293#if 0
294 constexpr int kStartupWait = 50000;
295#elif 0
296 constexpr int kStartupWait = 0;
297#elif 0
298 constexpr int kStartupWait = 30000;
299#elif 1
300 constexpr int kStartupWait = 2 * 20000;
301#endif
302 constexpr int kSubsampling = 1;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800303 //constexpr int kPoints = 5000;
304 constexpr int kPoints = 1000;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700305 constexpr int kSamplingEnd = kStartupWait + kPoints * kSubsampling;
306 (void)kSamplingEnd;
307 static int j = 0;
308 static int16_t data[kPoints][11];
309 static int written = 0;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800310 static bool done_writing = false;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700311 static_assert((kStartupWait % kSubsampling) == 0, "foo");
312 static_assert((kPoints % kSubsampling) == 0, "foo");
313 if (j < kStartupWait) {
314 // Wait to be started up.
315 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800316#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700317 } else if (!done) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700318#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800319 } else if (j < kSamplingEnd && (j % kSubsampling) == 0) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700320#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700321 {
322 const int index = ((j - kStartupWait) / kSubsampling) % kPoints;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800323 auto &point = data[index];
James Kuszmaul998d3032018-09-08 15:41:41 -0700324// Start obnoxious #if 0/#if 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700325#if 0
326 point[0] = adc_readings.motor_currents[0][0];
327 point[1] = adc_readings.motor_currents[1][0];
328 point[2] = adc_readings.motor_currents[2][0];
329 point[3] = adc_readings.motor_currents[0][1];
330 point[4] = adc_readings.motor_currents[1][1];
331 point[5] = adc_readings.motor_currents[2][1];
332#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800333 point[0] = balanced.readings[0];
334 point[1] = balanced.readings[1];
335 point[2] = balanced.readings[2];
Brian Silverman8d3816a2017-07-03 18:52:15 -0700336#if 1
337 point[3] = controls_->Debug(0);
338 point[4] = controls_->Debug(1);
339 point[5] = controls_->Debug(2);
340 point[6] = controls_->Debug(3);
341 point[7] = controls_->Debug(4);
342 point[8] = controls_->Debug(5);
343 point[9] = controls_->Debug(6);
344 point[10] = controls_->Debug(7);
345#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800346#if 0
Brian Silverman8d3816a2017-07-03 18:52:15 -0700347 point[3] = adc_readings.motor_currents[0][0];
348 point[4] = adc_readings.motor_currents[1][0];
349 point[5] = adc_readings.motor_currents[2][0];
350 point[6] = adc_readings.motor_currents[0][1];
351 point[7] = adc_readings.motor_currents[1][1];
352 point[8] = adc_readings.motor_currents[2][1];
Brian Silverman19ea60f2018-01-03 21:43:15 -0800353#else
354 point[3] = 0;
355 point[4] = 0;
356 point[5] = 0;
357 point[6] = 0;
358 point[7] = 0;
359 point[8] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700360#endif
Brian Silverman19ea60f2018-01-03 21:43:15 -0800361 point[9] = pwm_ftm_->C2V;
362 point[10] = pwm_ftm_->C3V;
363#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700364#if 0
365 point[3] = pwm_ftm_->C1V - pwm_ftm_->C0V;
366 point[4] = pwm_ftm_->C3V - pwm_ftm_->C2V;
367 point[5] = pwm_ftm_->C5V - pwm_ftm_->C4V;
368#endif
369#endif
James Kuszmaul998d3032018-09-08 15:41:41 -0700370// End obnoxious #if 0/#if 1
Brian Silverman19ea60f2018-01-03 21:43:15 -0800371 point[9] = captured_wrapped_encoder;
James Kuszmaul998d3032018-09-08 15:41:41 -0700372 //SmallInitReadings readings;
373 //{
374 //DisableInterrupts disable_interrupts;
375 //readings = AdcReadSmallInit(disable_interrupts);
376 //}
377 //point[10] = readings.motor0_abs;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700378 }
379
Brian Silverman8d3816a2017-07-03 18:52:15 -0700380#if DO_STEP_RESPONSE
381 // Step response
Brian Silverman19ea60f2018-01-03 21:43:15 -0800382 if (j > kStartupWait + 200 / kSubsampling) {
383 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700384 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700385#elif DO_PULSE_SWEEP // DO_STEP_RESPONSE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700386 // Sweep the pulse through the ADC sampling points.
387 static constexpr int kMax = 2500;
388 static constexpr int kExtraWait = 1500;
389 if (j > kStartupWait && j < kStartupWait + kExtraWait) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800390 pwm_ftm_->C2V = 0;
391 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700392 } else if (j < kStartupWait + kMax + kExtraWait) {
393 uint32_t start = j - kStartupWait - kExtraWait;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800394 pwm_ftm_->C2V = start;
395 pwm_ftm_->C3V = start + 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700396 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800397 pwm_ftm_->C2V = 0;
398 pwm_ftm_->C3V = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700399 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700400#endif // DO_STEP_RESPONSE/DO_PULSE_SWEEP
Brian Silverman8d3816a2017-07-03 18:52:15 -0700401
402 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800403#if SAMPLE_UNTIL_DONE
404 } else if (false) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700405#else // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700406 } else if (j < kSamplingEnd) {
407 ++j;
408 } else if (j == kSamplingEnd) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700409#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700410 printf("finished\n");
411 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800412#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700413 } else if (done) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700414#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800415 } else {
James Kuszmaul998d3032018-09-08 15:41:41 -0700416#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700417 // Time to write the data out.
Brian Silverman4787a6e2018-10-06 16:00:54 -0700418 if (written < (int)sizeof(data) && printing_implementation_ != nullptr) {
Brian Silverman8d3816a2017-07-03 18:52:15 -0700419 int to_write = sizeof(data) - written;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800420 if (to_write > 64) {
421 to_write = 64;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700422 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700423 int result = printing_implementation_->Write(((const char *)data) + written, to_write);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700424 if (result >= 0) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800425 written += result;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700426 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800427 printf("error\n");
Brian Silverman8d3816a2017-07-03 18:52:15 -0700428 }
Brian Silverman19ea60f2018-01-03 21:43:15 -0800429 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700430#if 0
Brian Silverman19ea60f2018-01-03 21:43:15 -0800431 if (!done_writing && written >= (int)sizeof(data) &&
Brian Silverman4787a6e2018-10-06 16:00:54 -0700432 printing_implementation_->write_queue_empty()) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800433 printf("done writing %d\n", written);
434 done_writing = true;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700435 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700436#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700437 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700438#endif // PRINT_READINGS/PRINT_ALL_READINGS/TAKE_SAMPLE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700439 (void)balanced;
440
441 // Tell the hardware to use the new switching points.
Brian Silverman19ea60f2018-01-03 21:43:15 -0800442 // TODO(Brian): Somehow verify that we consistently hit the first or second
443 // timer-cycle with the new values (if there's two).
Brian Silverman8d3816a2017-07-03 18:52:15 -0700444 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
445
Brian Silverman19ea60f2018-01-03 21:43:15 -0800446#if PRINT_TIMING
447 static int print_timing_count = 0;
448 static uint32_t print_timing_total = 0;
449 print_timing_total += time_subtract(nanos(), start_nanos);
450 if (++print_timing_count == 1000) {
451 printf("took %" PRIu32 "/%d\n", print_timing_total, print_timing_count);
452 print_timing_count = 0;
453 print_timing_total = 0;
454 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700455#endif // PRINT_TIMING
Brian Silverman19ea60f2018-01-03 21:43:15 -0800456
Brian Silverman8d3816a2017-07-03 18:52:15 -0700457 // If another cycle has already started, turn the light on right now.
458 if (pwm_ftm_->SC & FTM_SC_TOF) {
459 GPIOC_PSOR = 1 << 5;
460 }
461}
462
Brian Silverman19ea60f2018-01-03 21:43:15 -0800463uint32_t Motor::CalculateOnTime(uint32_t width) const {
464 if (width > 0) {
465 width += deadtime_compensation_;
466 if (flip_time_offset_) {
467 width += 1;
468 }
469 }
470 return (counts_per_cycle() - width) / 2;
471}
472
473uint32_t Motor::CalculateOffTime(uint32_t width) const {
474 if (width > 0) {
475 width += deadtime_compensation_;
476 if (!flip_time_offset_) {
477 width += 1;
478 }
479 }
480 return (counts_per_cycle() + width) / 2;
481}
482
Brian Silvermana96c1a42018-05-12 12:11:31 -0700483} // namespace motors
Brian Silverman8d3816a2017-07-03 18:52:15 -0700484} // namespace frc971