blob: ed1296c7b7b09b61632e4164280284732525e170 [file] [log] [blame]
Brian Silverman8d3816a2017-07-03 18:52:15 -07001#include "motors/motor.h"
2
Philipp Schrader790cb542023-07-05 21:06:52 -07003#include <inttypes.h>
Brian Silverman8d3816a2017-07-03 18:52:15 -07004#include <limits.h>
Brian Silverman19ea60f2018-01-03 21:43:15 -08005#include <stdio.h>
Brian Silverman8d3816a2017-07-03 18:52:15 -07006
7#include <array>
8
Brian Silverman8d3816a2017-07-03 18:52:15 -07009#include "motors/peripheral/can.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070010#include "motors/peripheral/configuration.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -070011
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() {
James Kuszmaulef420da2023-12-27 12:02:15 -080043 pwm_ftm_->CNTIN = 0;
44 encoder_ftm_->CNTIN = 0;
45 pwm_ftm_->CNT = 0;
46 encoder_ftm_->CNT = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -070047
Brian Silverman19ea60f2018-01-03 21:43:15 -080048 pwm_ftm_->MOD = counts_per_cycle() - 1;
49 encoder_ftm_->MOD = controls_->mechanical_counts_per_revolution() - 1;
Brian Silverman8d3816a2017-07-03 18:52:15 -070050
51 // I think you have to set this to something other than 0 for the quadrature
52 // encoder mode to actually work? This is "input capture on rising edge only",
53 // which should be fine.
54 encoder_ftm_->C0SC = FTM_CSC_ELSA;
55 encoder_ftm_->C1SC = FTM_CSC_ELSA;
56
57 // Initialize all the channels to 0.
Brian Silverman8d3816a2017-07-03 18:52:15 -070058 pwm_ftm_->OUTINIT = 0;
59
Brian Silverman19ea60f2018-01-03 21:43:15 -080060 // All of the channels are active high (low-side ones with separate high/low
61 // drives are defaulted on elsewhere).
Brian Silverman8d3816a2017-07-03 18:52:15 -070062 pwm_ftm_->POL = 0;
63
64 encoder_ftm_->FILTER = FTM_FILTER_CH0FVAL(0) /* No filter */ |
65 FTM_FILTER_CH1FVAL(0) /* No filter */;
66
67 // Could set PHAFLTREN and PHBFLTREN here to enable the filters.
68 encoder_ftm_->QDCTRL = FTM_QDCTRL_QUADEN;
69
70 pwm_ftm_->SYNCONF =
71 FTM_SYNCONF_HWWRBUF /* Hardware trigger flushes switching points */ |
72 FTM_SYNCONF_SWWRBUF /* Software trigger flushes switching points */ |
73 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
74 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
75 encoder_ftm_->SYNCONF =
76 FTM_SYNCONF_SWWRBUF /* Software trigger flushes MOD */ |
77 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
78 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
79
80 // Don't want any intermediate loading points.
81 pwm_ftm_->PWMLOAD = 0;
82
83 // This has to happen after messing with SYNCONF, and should happen after
84 // messing with various other things so the values can get flushed out of the
85 // buffers.
86 pwm_ftm_->SYNC =
87 FTM_SYNC_SWSYNC /* Flush everything out right now */ |
88 FTM_SYNC_CNTMAX /* Load new values at the end of the cycle */;
89 encoder_ftm_->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
90
91 // Wait for the software synchronization to finish.
92 while (pwm_ftm_->SYNC & FTM_SYNC_SWSYNC) {
93 }
94 while (encoder_ftm_->SYNC & FTM_SYNC_SWSYNC) {
95 }
96}
97
Brian Silverman8d3816a2017-07-03 18:52:15 -070098void Motor::Start() {
99 pwm_ftm_->SC = FTM_SC_TOIE /* Interrupt on overflow */ |
100 FTM_SC_CLKS(1) /* Use the system clock */ |
101 FTM_SC_PS(0) /* Don't prescale the clock */;
102 pwm_ftm_->MODE &= ~FTM_MODE_WPDIS;
103 encoder_ftm_->MODE &= ~FTM_MODE_WPDIS;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700104}
105
Brian Silverman19ea60f2018-01-03 21:43:15 -0800106#define USE_ABSOLUTE_CUTOFF 0
107#define DO_CONTROLS 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700108
Brian Silverman19ea60f2018-01-03 21:43:15 -0800109#define USE_CUTOFF 1
Brian Silverman19ea60f2018-01-03 21:43:15 -0800110#define PRINT_ALL_READINGS 0
111#define TAKE_SAMPLE 0
112#define SAMPLE_UNTIL_DONE 0
113#define DO_STEP_RESPONSE 0
114#define DO_PULSE_SWEEP 0
115#define PRINT_TIMING 0
Brian Silverman8d3816a2017-07-03 18:52:15 -0700116
Austin Schuhefe72932019-04-13 00:03:19 -0700117// An on-width of 60 with 30V in means about 50A through the motor and about
118// 30W total power dumped by the motor for the big one.
119// For the small one, an on-width of 120/3000 with 14V in means about 2A
120// through the motor.
121void Motor::CycleFixedPhaseInterupt(int period) {
Austin Schuh6bf82752019-04-07 13:55:01 -0700122 pwm_ftm_->SC &= ~FTM_SC_TOF;
123 // Step through all the phases one by one in a loop. This should slowly move
124 // the trigger.
125 // If we fire phase 1, we should go to PI radians.
126 // If we fire phase 2, we should go to 1.0 * PI / 3.0 radians.
127 // If we fire phase 3, we should go to -1.0 * PI / 3.0 radians.
128 // These numbers were confirmed by the python motor simulation.
129 static int phase_to_fire_count = -300000;
130 static int phase_to_fire = 0;
131 ++phase_to_fire_count;
132 if (phase_to_fire_count > 500000) {
133 phase_to_fire_count = 0;
134 ++phase_to_fire;
135 if (phase_to_fire > 2) {
136 phase_to_fire = 0;
137 }
138 }
139 phase_to_fire = 0;
140
Austin Schuh6bf82752019-04-07 13:55:01 -0700141 output_registers_[0][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700142 output_registers_[0][2] = phase_to_fire == 0 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700143
144 const float switching_points_max = static_cast<float>(counts_per_cycle());
145 switching_points_ratio_[0] =
146 static_cast<float>(output_registers_[0][2]) / switching_points_max;
147 output_registers_[1][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700148 output_registers_[1][2] = phase_to_fire == 1 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700149 switching_points_ratio_[1] =
150 static_cast<float>(output_registers_[1][2]) / switching_points_max;
151 output_registers_[2][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700152 output_registers_[2][2] = phase_to_fire == 2 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700153 switching_points_ratio_[2] =
154 static_cast<float>(output_registers_[2][2]) / switching_points_max;
155
156 // Tell the hardware to use the new switching points.
157 // TODO(Brian): Somehow verify that we consistently hit the first or second
158 // timer-cycle with the new values (if there's two).
159 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
160
161 // If another cycle has already started, turn the light on right now.
162 if (pwm_ftm_->SC & FTM_SC_TOF) {
163 GPIOC_PSOR = 1 << 5;
164 }
165}
166
Austin Schuh54c8c842019-04-07 13:54:23 -0700167void Motor::CurrentInterrupt(const BalancedReadings &balanced,
168 uint32_t captured_wrapped_encoder) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800169 pwm_ftm_->SC &= ~FTM_SC_TOF;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700170
Brian Silverman19ea60f2018-01-03 21:43:15 -0800171#if PRINT_TIMING
172 const uint32_t start_nanos = nanos();
James Kuszmaul998d3032018-09-08 15:41:41 -0700173#endif // PRINT_TIMING
Brian Silverman8d3816a2017-07-03 18:52:15 -0700174
Brian Silverman19ea60f2018-01-03 21:43:15 -0800175 if (!time_after(time_add(last_current_set_time_, 100000), micros())) {
176 goal_current_ = 0;
177 }
178
Brian Silverman8d3816a2017-07-03 18:52:15 -0700179#if DO_CONTROLS
James Kuszmaul998d3032018-09-08 15:41:41 -0700180 switching_points_ratio_ = controls_->DoIteration(
181 balanced.readings, captured_wrapped_encoder, goal_current_);
182 const float switching_points_max = static_cast<float>(counts_per_cycle());
183 const ::std::array<uint32_t, 3> switching_points = {
184 static_cast<uint32_t>(switching_points_ratio_[0] * switching_points_max),
185 static_cast<uint32_t>(switching_points_ratio_[1] * switching_points_max),
186 static_cast<uint32_t>(switching_points_ratio_[2] * switching_points_max)};
Brian Silverman19ea60f2018-01-03 21:43:15 -0800187#if USE_CUTOFF
James Kuszmaul998d3032018-09-08 15:41:41 -0700188 constexpr uint32_t kMax = 2995;
Philipp Schrader790cb542023-07-05 21:06:52 -0700189 // constexpr uint32_t kMax = 1445;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700190 static bool done = false;
191 bool done_now = false;
192 if (switching_points[0] > kMax || switching_points[1] > kMax ||
193 switching_points[2] > kMax) {
194 done_now = true;
195 }
Brian Silverman8d3816a2017-07-03 18:52:15 -0700196#if USE_ABSOLUTE_CUTOFF
197 static unsigned int current_done_count = 0;
198 bool current_done = false;
199 for (int phase = 0; phase < 3; ++phase) {
200 const float scaled_reading =
Brian Silverman19ea60f2018-01-03 21:43:15 -0800201 controls_->scale_current_reading(balanced.readings[phase]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700202 static constexpr float kMaxBalancedCurrent = 50.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700203 if (scaled_reading > kMaxBalancedCurrent ||
204 scaled_reading < -kMaxBalancedCurrent) {
205 current_done = true;
206 }
207 }
208 if (current_done) {
209 if (current_done_count > 5) {
210 done_now = true;
211 }
212 ++current_done_count;
213 } else {
214 current_done_count = 0;
215 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700216#endif // USE_ABSOLUTE_CUTOFF
Brian Silverman8d3816a2017-07-03 18:52:15 -0700217 if (done_now && !done) {
218 printf("done now\n");
219 printf("switching_points %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
220 switching_points[0], switching_points[1], switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700221 printf("balanced %" PRIu16 " %" PRIu16 " %" PRIu16 "\n",
222 static_cast<uint16_t>(balanced.readings[0]),
223 static_cast<uint16_t>(balanced.readings[1]),
224 static_cast<uint16_t>(balanced.readings[2]));
225 done = true;
226 }
227 if (!done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700228#else // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800229 if (true) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700230#endif // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800231 output_registers_[0][0] = CalculateOnTime(switching_points[0]);
232 output_registers_[0][2] = CalculateOffTime(switching_points[0]);
233 output_registers_[1][0] = CalculateOnTime(switching_points[1]);
234 output_registers_[1][2] = CalculateOffTime(switching_points[1]);
235 output_registers_[2][0] = CalculateOnTime(switching_points[2]);
236 output_registers_[2][2] = CalculateOffTime(switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700237 flip_time_offset_ = !flip_time_offset_;
238 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800239 output_registers_[0][0] = 0;
240 output_registers_[0][2] = 0;
241 output_registers_[1][0] = 0;
242 output_registers_[1][2] = 0;
243 output_registers_[2][0] = 0;
244 output_registers_[2][2] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700245 }
Austin Schuh6bf82752019-04-07 13:55:01 -0700246#endif // DO_CONTROLS
Brian Silverman6260c092018-01-14 15:21:36 -0800247 (void)balanced;
248 (void)captured_wrapped_encoder;
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700249#if PRINT_ALL_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700250 printf("ref=%" PRIu16 " 0.0=%" PRIu16 " 1.0=%" PRIu16 " 2.0=%" PRIu16
251 " in=%" PRIu16 " 0.1=%" PRIu16 " 1.1=%" PRIu16 " 2.1=%" PRIu16 "\n",
252 adc_readings.motor_current_ref, adc_readings.motor_currents[0][0],
253 adc_readings.motor_currents[1][0], adc_readings.motor_currents[2][0],
254 adc_readings.input_voltage, adc_readings.motor_currents[0][1],
255 adc_readings.motor_currents[1][1], adc_readings.motor_currents[2][1]);
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700256#elif TAKE_SAMPLE // PRINT_ALL_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700257#if 0
258 constexpr int kStartupWait = 50000;
259#elif 0
260 constexpr int kStartupWait = 0;
261#elif 0
262 constexpr int kStartupWait = 30000;
263#elif 1
264 constexpr int kStartupWait = 2 * 20000;
265#endif
266 constexpr int kSubsampling = 1;
Philipp Schrader790cb542023-07-05 21:06:52 -0700267 // constexpr int kPoints = 5000;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800268 constexpr int kPoints = 1000;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700269 constexpr int kSamplingEnd = kStartupWait + kPoints * kSubsampling;
270 (void)kSamplingEnd;
271 static int j = 0;
272 static int16_t data[kPoints][11];
273 static int written = 0;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800274 static bool done_writing = false;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700275 static_assert((kStartupWait % kSubsampling) == 0, "foo");
276 static_assert((kPoints % kSubsampling) == 0, "foo");
277 if (j < kStartupWait) {
278 // Wait to be started up.
279 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800280#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700281 } else if (!done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700282#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800283 } else if (j < kSamplingEnd && (j % kSubsampling) == 0) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700284#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700285 {
286 const int index = ((j - kStartupWait) / kSubsampling) % kPoints;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800287 auto &point = data[index];
James Kuszmaul998d3032018-09-08 15:41:41 -0700288// Start obnoxious #if 0/#if 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700289#if 0
290 point[0] = adc_readings.motor_currents[0][0];
291 point[1] = adc_readings.motor_currents[1][0];
292 point[2] = adc_readings.motor_currents[2][0];
293 point[3] = adc_readings.motor_currents[0][1];
294 point[4] = adc_readings.motor_currents[1][1];
295 point[5] = adc_readings.motor_currents[2][1];
296#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800297 point[0] = balanced.readings[0];
298 point[1] = balanced.readings[1];
299 point[2] = balanced.readings[2];
Brian Silverman8d3816a2017-07-03 18:52:15 -0700300#if 1
301 point[3] = controls_->Debug(0);
302 point[4] = controls_->Debug(1);
303 point[5] = controls_->Debug(2);
304 point[6] = controls_->Debug(3);
305 point[7] = controls_->Debug(4);
306 point[8] = controls_->Debug(5);
307 point[9] = controls_->Debug(6);
308 point[10] = controls_->Debug(7);
309#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800310#if 0
Brian Silverman8d3816a2017-07-03 18:52:15 -0700311 point[3] = adc_readings.motor_currents[0][0];
312 point[4] = adc_readings.motor_currents[1][0];
313 point[5] = adc_readings.motor_currents[2][0];
314 point[6] = adc_readings.motor_currents[0][1];
315 point[7] = adc_readings.motor_currents[1][1];
316 point[8] = adc_readings.motor_currents[2][1];
Brian Silverman19ea60f2018-01-03 21:43:15 -0800317#else
318 point[3] = 0;
319 point[4] = 0;
320 point[5] = 0;
321 point[6] = 0;
322 point[7] = 0;
323 point[8] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700324#endif
Brian Silverman19ea60f2018-01-03 21:43:15 -0800325 point[9] = pwm_ftm_->C2V;
326 point[10] = pwm_ftm_->C3V;
327#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700328#if 0
329 point[3] = pwm_ftm_->C1V - pwm_ftm_->C0V;
330 point[4] = pwm_ftm_->C3V - pwm_ftm_->C2V;
331 point[5] = pwm_ftm_->C5V - pwm_ftm_->C4V;
332#endif
333#endif
Philipp Schrader790cb542023-07-05 21:06:52 -0700334 // End obnoxious #if 0/#if 1
Brian Silverman19ea60f2018-01-03 21:43:15 -0800335 point[9] = captured_wrapped_encoder;
Philipp Schrader790cb542023-07-05 21:06:52 -0700336 // SmallInitReadings readings;
James Kuszmaul998d3032018-09-08 15:41:41 -0700337 //{
Philipp Schrader790cb542023-07-05 21:06:52 -0700338 // DisableInterrupts disable_interrupts;
339 // readings = AdcReadSmallInit(disable_interrupts);
James Kuszmaul998d3032018-09-08 15:41:41 -0700340 //}
Philipp Schrader790cb542023-07-05 21:06:52 -0700341 // point[10] = readings.motor0_abs;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700342 }
343
Brian Silverman8d3816a2017-07-03 18:52:15 -0700344#if DO_STEP_RESPONSE
345 // Step response
Brian Silverman19ea60f2018-01-03 21:43:15 -0800346 if (j > kStartupWait + 200 / kSubsampling) {
347 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700348 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700349#elif DO_PULSE_SWEEP // DO_STEP_RESPONSE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700350 // Sweep the pulse through the ADC sampling points.
351 static constexpr int kMax = 2500;
352 static constexpr int kExtraWait = 1500;
353 if (j > kStartupWait && j < kStartupWait + kExtraWait) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800354 pwm_ftm_->C2V = 0;
355 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700356 } else if (j < kStartupWait + kMax + kExtraWait) {
357 uint32_t start = j - kStartupWait - kExtraWait;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800358 pwm_ftm_->C2V = start;
359 pwm_ftm_->C3V = start + 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700360 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800361 pwm_ftm_->C2V = 0;
362 pwm_ftm_->C3V = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700363 }
Philipp Schrader790cb542023-07-05 21:06:52 -0700364#endif // DO_STEP_RESPONSE/DO_PULSE_SWEEP
Brian Silverman8d3816a2017-07-03 18:52:15 -0700365
366 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800367#if SAMPLE_UNTIL_DONE
368 } else if (false) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700369#else // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700370 } else if (j < kSamplingEnd) {
371 ++j;
372 } else if (j == kSamplingEnd) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700373#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700374 printf("finished\n");
375 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800376#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700377 } else if (done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700378#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800379 } else {
James Kuszmaul998d3032018-09-08 15:41:41 -0700380#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700381 // Time to write the data out.
Brian Silverman4787a6e2018-10-06 16:00:54 -0700382 if (written < (int)sizeof(data) && printing_implementation_ != nullptr) {
Brian Silverman8d3816a2017-07-03 18:52:15 -0700383 int to_write = sizeof(data) - written;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800384 if (to_write > 64) {
385 to_write = 64;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700386 }
Philipp Schrader790cb542023-07-05 21:06:52 -0700387 int result = printing_implementation_->Write(
388 ((const char *)data) + written, to_write);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700389 if (result >= 0) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800390 written += result;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700391 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800392 printf("error\n");
Brian Silverman8d3816a2017-07-03 18:52:15 -0700393 }
Brian Silverman19ea60f2018-01-03 21:43:15 -0800394 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700395#if 0
Brian Silverman19ea60f2018-01-03 21:43:15 -0800396 if (!done_writing && written >= (int)sizeof(data) &&
Brian Silverman4787a6e2018-10-06 16:00:54 -0700397 printing_implementation_->write_queue_empty()) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800398 printf("done writing %d\n", written);
399 done_writing = true;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700400 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700401#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700402 }
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700403#endif // PRINT_ALL_READINGS/TAKE_SAMPLE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700404 (void)balanced;
405
406 // Tell the hardware to use the new switching points.
Brian Silverman19ea60f2018-01-03 21:43:15 -0800407 // TODO(Brian): Somehow verify that we consistently hit the first or second
408 // timer-cycle with the new values (if there's two).
Brian Silverman8d3816a2017-07-03 18:52:15 -0700409 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
410
Brian Silverman19ea60f2018-01-03 21:43:15 -0800411#if PRINT_TIMING
412 static int print_timing_count = 0;
413 static uint32_t print_timing_total = 0;
414 print_timing_total += time_subtract(nanos(), start_nanos);
415 if (++print_timing_count == 1000) {
416 printf("took %" PRIu32 "/%d\n", print_timing_total, print_timing_count);
417 print_timing_count = 0;
418 print_timing_total = 0;
419 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700420#endif // PRINT_TIMING
Brian Silverman19ea60f2018-01-03 21:43:15 -0800421
Brian Silverman8d3816a2017-07-03 18:52:15 -0700422 // If another cycle has already started, turn the light on right now.
423 if (pwm_ftm_->SC & FTM_SC_TOF) {
424 GPIOC_PSOR = 1 << 5;
425 }
426}
427
Brian Silverman19ea60f2018-01-03 21:43:15 -0800428uint32_t Motor::CalculateOnTime(uint32_t width) const {
429 if (width > 0) {
430 width += deadtime_compensation_;
431 if (flip_time_offset_) {
432 width += 1;
433 }
434 }
435 return (counts_per_cycle() - width) / 2;
436}
437
438uint32_t Motor::CalculateOffTime(uint32_t width) const {
439 if (width > 0) {
440 width += deadtime_compensation_;
441 if (!flip_time_offset_) {
442 width += 1;
443 }
444 }
445 return (counts_per_cycle() + width) / 2;
446}
447
Brian Silvermana96c1a42018-05-12 12:11:31 -0700448} // namespace motors
Brian Silverman8d3816a2017-07-03 18:52:15 -0700449} // namespace frc971