blob: d2c977ccf7eb3c4de3fdf9209f67922bf9434071 [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080015namespace frc971::motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -070016
Brian Silverman19ea60f2018-01-03 21:43:15 -080017Motor::Motor(BigFTM *pwm_ftm, LittleFTM *encoder_ftm, MotorControls *controls,
18 const ::std::array<volatile uint32_t *, 3> &output_registers)
19 : pwm_ftm_(pwm_ftm),
20 encoder_ftm_(encoder_ftm),
21 controls_(controls),
22 output_registers_(output_registers) {
Brian Silverman8d3816a2017-07-03 18:52:15 -070023 // PWMSYNC doesn't matter because we set SYNCMODE down below.
24 pwm_ftm_->MODE = FTM_MODE_WPDIS;
25 pwm_ftm_->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
26 encoder_ftm_->MODE = FTM_MODE_WPDIS;
27 encoder_ftm_->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
28
29 pwm_ftm_->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
30 encoder_ftm_->SC =
31 FTM_SC_CLKS(1) /* Use the system clock (not sure it matters) */ |
32 FTM_SC_PS(0) /* Don't prescale the clock (not sure it matters) */;
Brian Silverman19ea60f2018-01-03 21:43:15 -080033}
Brian Silverman8d3816a2017-07-03 18:52:15 -070034
Brian Silverman19ea60f2018-01-03 21:43:15 -080035static_assert((BUS_CLOCK_FREQUENCY % SWITCHING_FREQUENCY) == 0,
36 "Switching frequency needs to divide the bus clock frequency");
37
38static_assert(BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY < UINT16_MAX,
39 "Need to prescale");
40
41void Motor::Init() {
James Kuszmaulef420da2023-12-27 12:02:15 -080042 pwm_ftm_->CNTIN = 0;
43 encoder_ftm_->CNTIN = 0;
44 pwm_ftm_->CNT = 0;
45 encoder_ftm_->CNT = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -070046
Brian Silverman19ea60f2018-01-03 21:43:15 -080047 pwm_ftm_->MOD = counts_per_cycle() - 1;
48 encoder_ftm_->MOD = controls_->mechanical_counts_per_revolution() - 1;
Brian Silverman8d3816a2017-07-03 18:52:15 -070049
50 // I think you have to set this to something other than 0 for the quadrature
51 // encoder mode to actually work? This is "input capture on rising edge only",
52 // which should be fine.
53 encoder_ftm_->C0SC = FTM_CSC_ELSA;
54 encoder_ftm_->C1SC = FTM_CSC_ELSA;
55
56 // Initialize all the channels to 0.
Brian Silverman8d3816a2017-07-03 18:52:15 -070057 pwm_ftm_->OUTINIT = 0;
58
Brian Silverman19ea60f2018-01-03 21:43:15 -080059 // All of the channels are active high (low-side ones with separate high/low
60 // drives are defaulted on elsewhere).
Brian Silverman8d3816a2017-07-03 18:52:15 -070061 pwm_ftm_->POL = 0;
62
63 encoder_ftm_->FILTER = FTM_FILTER_CH0FVAL(0) /* No filter */ |
64 FTM_FILTER_CH1FVAL(0) /* No filter */;
65
66 // Could set PHAFLTREN and PHBFLTREN here to enable the filters.
67 encoder_ftm_->QDCTRL = FTM_QDCTRL_QUADEN;
68
69 pwm_ftm_->SYNCONF =
70 FTM_SYNCONF_HWWRBUF /* Hardware trigger flushes switching points */ |
71 FTM_SYNCONF_SWWRBUF /* Software trigger flushes switching points */ |
72 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
73 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
74 encoder_ftm_->SYNCONF =
75 FTM_SYNCONF_SWWRBUF /* Software trigger flushes MOD */ |
76 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
77 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
78
79 // Don't want any intermediate loading points.
80 pwm_ftm_->PWMLOAD = 0;
81
82 // This has to happen after messing with SYNCONF, and should happen after
83 // messing with various other things so the values can get flushed out of the
84 // buffers.
85 pwm_ftm_->SYNC =
86 FTM_SYNC_SWSYNC /* Flush everything out right now */ |
87 FTM_SYNC_CNTMAX /* Load new values at the end of the cycle */;
88 encoder_ftm_->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
89
90 // Wait for the software synchronization to finish.
91 while (pwm_ftm_->SYNC & FTM_SYNC_SWSYNC) {
92 }
93 while (encoder_ftm_->SYNC & FTM_SYNC_SWSYNC) {
94 }
95}
96
Brian Silverman8d3816a2017-07-03 18:52:15 -070097void Motor::Start() {
98 pwm_ftm_->SC = FTM_SC_TOIE /* Interrupt on overflow */ |
99 FTM_SC_CLKS(1) /* Use the system clock */ |
100 FTM_SC_PS(0) /* Don't prescale the clock */;
101 pwm_ftm_->MODE &= ~FTM_MODE_WPDIS;
102 encoder_ftm_->MODE &= ~FTM_MODE_WPDIS;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700103}
104
Brian Silverman19ea60f2018-01-03 21:43:15 -0800105#define USE_ABSOLUTE_CUTOFF 0
106#define DO_CONTROLS 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700107
Brian Silverman19ea60f2018-01-03 21:43:15 -0800108#define USE_CUTOFF 1
Brian Silverman19ea60f2018-01-03 21:43:15 -0800109#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 Schuhefe72932019-04-13 00:03:19 -0700116// An on-width of 60 with 30V in means about 50A through the motor and about
117// 30W total power dumped by the motor for the big one.
118// For the small one, an on-width of 120/3000 with 14V in means about 2A
119// through the motor.
120void Motor::CycleFixedPhaseInterupt(int period) {
Austin Schuh6bf82752019-04-07 13:55:01 -0700121 pwm_ftm_->SC &= ~FTM_SC_TOF;
122 // Step through all the phases one by one in a loop. This should slowly move
123 // the trigger.
124 // If we fire phase 1, we should go to PI radians.
125 // If we fire phase 2, we should go to 1.0 * PI / 3.0 radians.
126 // If we fire phase 3, we should go to -1.0 * PI / 3.0 radians.
127 // These numbers were confirmed by the python motor simulation.
128 static int phase_to_fire_count = -300000;
129 static int phase_to_fire = 0;
130 ++phase_to_fire_count;
131 if (phase_to_fire_count > 500000) {
132 phase_to_fire_count = 0;
133 ++phase_to_fire;
134 if (phase_to_fire > 2) {
135 phase_to_fire = 0;
136 }
137 }
138 phase_to_fire = 0;
139
Austin Schuh6bf82752019-04-07 13:55:01 -0700140 output_registers_[0][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700141 output_registers_[0][2] = phase_to_fire == 0 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700142
143 const float switching_points_max = static_cast<float>(counts_per_cycle());
144 switching_points_ratio_[0] =
145 static_cast<float>(output_registers_[0][2]) / switching_points_max;
146 output_registers_[1][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700147 output_registers_[1][2] = phase_to_fire == 1 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700148 switching_points_ratio_[1] =
149 static_cast<float>(output_registers_[1][2]) / switching_points_max;
150 output_registers_[2][0] = 0;
Austin Schuhefe72932019-04-13 00:03:19 -0700151 output_registers_[2][2] = phase_to_fire == 2 ? period : 0;
Austin Schuh6bf82752019-04-07 13:55:01 -0700152 switching_points_ratio_[2] =
153 static_cast<float>(output_registers_[2][2]) / switching_points_max;
154
155 // Tell the hardware to use the new switching points.
156 // TODO(Brian): Somehow verify that we consistently hit the first or second
157 // timer-cycle with the new values (if there's two).
158 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
159
160 // If another cycle has already started, turn the light on right now.
161 if (pwm_ftm_->SC & FTM_SC_TOF) {
162 GPIOC_PSOR = 1 << 5;
163 }
164}
165
Austin Schuh54c8c842019-04-07 13:54:23 -0700166void Motor::CurrentInterrupt(const BalancedReadings &balanced,
167 uint32_t captured_wrapped_encoder) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800168 pwm_ftm_->SC &= ~FTM_SC_TOF;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700169
Brian Silverman19ea60f2018-01-03 21:43:15 -0800170#if PRINT_TIMING
171 const uint32_t start_nanos = nanos();
James Kuszmaul998d3032018-09-08 15:41:41 -0700172#endif // PRINT_TIMING
Brian Silverman8d3816a2017-07-03 18:52:15 -0700173
Brian Silverman19ea60f2018-01-03 21:43:15 -0800174 if (!time_after(time_add(last_current_set_time_, 100000), micros())) {
175 goal_current_ = 0;
176 }
177
Brian Silverman8d3816a2017-07-03 18:52:15 -0700178#if DO_CONTROLS
James Kuszmaul998d3032018-09-08 15:41:41 -0700179 switching_points_ratio_ = controls_->DoIteration(
180 balanced.readings, captured_wrapped_encoder, goal_current_);
181 const float switching_points_max = static_cast<float>(counts_per_cycle());
182 const ::std::array<uint32_t, 3> switching_points = {
183 static_cast<uint32_t>(switching_points_ratio_[0] * switching_points_max),
184 static_cast<uint32_t>(switching_points_ratio_[1] * switching_points_max),
185 static_cast<uint32_t>(switching_points_ratio_[2] * switching_points_max)};
Brian Silverman19ea60f2018-01-03 21:43:15 -0800186#if USE_CUTOFF
James Kuszmaul998d3032018-09-08 15:41:41 -0700187 constexpr uint32_t kMax = 2995;
Philipp Schrader790cb542023-07-05 21:06:52 -0700188 // constexpr uint32_t kMax = 1445;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700189 static bool done = false;
190 bool done_now = false;
191 if (switching_points[0] > kMax || switching_points[1] > kMax ||
192 switching_points[2] > kMax) {
193 done_now = true;
194 }
Brian Silverman8d3816a2017-07-03 18:52:15 -0700195#if USE_ABSOLUTE_CUTOFF
196 static unsigned int current_done_count = 0;
197 bool current_done = false;
198 for (int phase = 0; phase < 3; ++phase) {
199 const float scaled_reading =
Brian Silverman19ea60f2018-01-03 21:43:15 -0800200 controls_->scale_current_reading(balanced.readings[phase]);
James Kuszmaul998d3032018-09-08 15:41:41 -0700201 static constexpr float kMaxBalancedCurrent = 50.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700202 if (scaled_reading > kMaxBalancedCurrent ||
203 scaled_reading < -kMaxBalancedCurrent) {
204 current_done = true;
205 }
206 }
207 if (current_done) {
208 if (current_done_count > 5) {
209 done_now = true;
210 }
211 ++current_done_count;
212 } else {
213 current_done_count = 0;
214 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700215#endif // USE_ABSOLUTE_CUTOFF
Brian Silverman8d3816a2017-07-03 18:52:15 -0700216 if (done_now && !done) {
217 printf("done now\n");
218 printf("switching_points %" PRIu32 " %" PRIu32 " %" PRIu32 "\n",
219 switching_points[0], switching_points[1], switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700220 printf("balanced %" PRIu16 " %" PRIu16 " %" PRIu16 "\n",
221 static_cast<uint16_t>(balanced.readings[0]),
222 static_cast<uint16_t>(balanced.readings[1]),
223 static_cast<uint16_t>(balanced.readings[2]));
224 done = true;
225 }
226 if (!done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700227#else // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800228 if (true) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700229#endif // USE_CUTOFF
Brian Silverman19ea60f2018-01-03 21:43:15 -0800230 output_registers_[0][0] = CalculateOnTime(switching_points[0]);
231 output_registers_[0][2] = CalculateOffTime(switching_points[0]);
232 output_registers_[1][0] = CalculateOnTime(switching_points[1]);
233 output_registers_[1][2] = CalculateOffTime(switching_points[1]);
234 output_registers_[2][0] = CalculateOnTime(switching_points[2]);
235 output_registers_[2][2] = CalculateOffTime(switching_points[2]);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700236 flip_time_offset_ = !flip_time_offset_;
237 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800238 output_registers_[0][0] = 0;
239 output_registers_[0][2] = 0;
240 output_registers_[1][0] = 0;
241 output_registers_[1][2] = 0;
242 output_registers_[2][0] = 0;
243 output_registers_[2][2] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700244 }
Austin Schuh6bf82752019-04-07 13:55:01 -0700245#endif // DO_CONTROLS
Brian Silverman6260c092018-01-14 15:21:36 -0800246 (void)balanced;
247 (void)captured_wrapped_encoder;
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700248#if PRINT_ALL_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700249 printf("ref=%" PRIu16 " 0.0=%" PRIu16 " 1.0=%" PRIu16 " 2.0=%" PRIu16
250 " in=%" PRIu16 " 0.1=%" PRIu16 " 1.1=%" PRIu16 " 2.1=%" PRIu16 "\n",
251 adc_readings.motor_current_ref, adc_readings.motor_currents[0][0],
252 adc_readings.motor_currents[1][0], adc_readings.motor_currents[2][0],
253 adc_readings.input_voltage, adc_readings.motor_currents[0][1],
254 adc_readings.motor_currents[1][1], adc_readings.motor_currents[2][1]);
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700255#elif TAKE_SAMPLE // PRINT_ALL_READINGS
Brian Silverman8d3816a2017-07-03 18:52:15 -0700256#if 0
257 constexpr int kStartupWait = 50000;
258#elif 0
259 constexpr int kStartupWait = 0;
260#elif 0
261 constexpr int kStartupWait = 30000;
262#elif 1
263 constexpr int kStartupWait = 2 * 20000;
264#endif
265 constexpr int kSubsampling = 1;
Philipp Schrader790cb542023-07-05 21:06:52 -0700266 // constexpr int kPoints = 5000;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800267 constexpr int kPoints = 1000;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700268 constexpr int kSamplingEnd = kStartupWait + kPoints * kSubsampling;
269 (void)kSamplingEnd;
270 static int j = 0;
271 static int16_t data[kPoints][11];
272 static int written = 0;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800273 static bool done_writing = false;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700274 static_assert((kStartupWait % kSubsampling) == 0, "foo");
275 static_assert((kPoints % kSubsampling) == 0, "foo");
276 if (j < kStartupWait) {
277 // Wait to be started up.
278 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800279#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700280 } else if (!done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700281#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800282 } else if (j < kSamplingEnd && (j % kSubsampling) == 0) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700283#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700284 {
285 const int index = ((j - kStartupWait) / kSubsampling) % kPoints;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800286 auto &point = data[index];
James Kuszmaul998d3032018-09-08 15:41:41 -0700287// Start obnoxious #if 0/#if 1
Brian Silverman8d3816a2017-07-03 18:52:15 -0700288#if 0
289 point[0] = adc_readings.motor_currents[0][0];
290 point[1] = adc_readings.motor_currents[1][0];
291 point[2] = adc_readings.motor_currents[2][0];
292 point[3] = adc_readings.motor_currents[0][1];
293 point[4] = adc_readings.motor_currents[1][1];
294 point[5] = adc_readings.motor_currents[2][1];
295#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800296 point[0] = balanced.readings[0];
297 point[1] = balanced.readings[1];
298 point[2] = balanced.readings[2];
Brian Silverman8d3816a2017-07-03 18:52:15 -0700299#if 1
300 point[3] = controls_->Debug(0);
301 point[4] = controls_->Debug(1);
302 point[5] = controls_->Debug(2);
303 point[6] = controls_->Debug(3);
304 point[7] = controls_->Debug(4);
305 point[8] = controls_->Debug(5);
306 point[9] = controls_->Debug(6);
307 point[10] = controls_->Debug(7);
308#else
Brian Silverman19ea60f2018-01-03 21:43:15 -0800309#if 0
Brian Silverman8d3816a2017-07-03 18:52:15 -0700310 point[3] = adc_readings.motor_currents[0][0];
311 point[4] = adc_readings.motor_currents[1][0];
312 point[5] = adc_readings.motor_currents[2][0];
313 point[6] = adc_readings.motor_currents[0][1];
314 point[7] = adc_readings.motor_currents[1][1];
315 point[8] = adc_readings.motor_currents[2][1];
Brian Silverman19ea60f2018-01-03 21:43:15 -0800316#else
317 point[3] = 0;
318 point[4] = 0;
319 point[5] = 0;
320 point[6] = 0;
321 point[7] = 0;
322 point[8] = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700323#endif
Brian Silverman19ea60f2018-01-03 21:43:15 -0800324 point[9] = pwm_ftm_->C2V;
325 point[10] = pwm_ftm_->C3V;
326#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700327#if 0
328 point[3] = pwm_ftm_->C1V - pwm_ftm_->C0V;
329 point[4] = pwm_ftm_->C3V - pwm_ftm_->C2V;
330 point[5] = pwm_ftm_->C5V - pwm_ftm_->C4V;
331#endif
332#endif
Philipp Schrader790cb542023-07-05 21:06:52 -0700333 // End obnoxious #if 0/#if 1
Brian Silverman19ea60f2018-01-03 21:43:15 -0800334 point[9] = captured_wrapped_encoder;
Philipp Schrader790cb542023-07-05 21:06:52 -0700335 // SmallInitReadings readings;
James Kuszmaul998d3032018-09-08 15:41:41 -0700336 //{
Philipp Schrader790cb542023-07-05 21:06:52 -0700337 // DisableInterrupts disable_interrupts;
338 // readings = AdcReadSmallInit(disable_interrupts);
James Kuszmaul998d3032018-09-08 15:41:41 -0700339 //}
Philipp Schrader790cb542023-07-05 21:06:52 -0700340 // point[10] = readings.motor0_abs;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700341 }
342
Brian Silverman8d3816a2017-07-03 18:52:15 -0700343#if DO_STEP_RESPONSE
344 // Step response
Brian Silverman19ea60f2018-01-03 21:43:15 -0800345 if (j > kStartupWait + 200 / kSubsampling) {
346 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700347 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700348#elif DO_PULSE_SWEEP // DO_STEP_RESPONSE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700349 // Sweep the pulse through the ADC sampling points.
350 static constexpr int kMax = 2500;
351 static constexpr int kExtraWait = 1500;
352 if (j > kStartupWait && j < kStartupWait + kExtraWait) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800353 pwm_ftm_->C2V = 0;
354 pwm_ftm_->C3V = 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700355 } else if (j < kStartupWait + kMax + kExtraWait) {
356 uint32_t start = j - kStartupWait - kExtraWait;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800357 pwm_ftm_->C2V = start;
358 pwm_ftm_->C3V = start + 240;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700359 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800360 pwm_ftm_->C2V = 0;
361 pwm_ftm_->C3V = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700362 }
Philipp Schrader790cb542023-07-05 21:06:52 -0700363#endif // DO_STEP_RESPONSE/DO_PULSE_SWEEP
Brian Silverman8d3816a2017-07-03 18:52:15 -0700364
365 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800366#if SAMPLE_UNTIL_DONE
367 } else if (false) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700368#else // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700369 } else if (j < kSamplingEnd) {
370 ++j;
371 } else if (j == kSamplingEnd) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700372#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700373 printf("finished\n");
374 ++j;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800375#if SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700376 } else if (done) {
Philipp Schrader790cb542023-07-05 21:06:52 -0700377#else // SAMPLE_UNTIL_DONE
Brian Silverman19ea60f2018-01-03 21:43:15 -0800378 } else {
James Kuszmaul998d3032018-09-08 15:41:41 -0700379#endif // SAMPLE_UNTIL_DONE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700380 // Time to write the data out.
Brian Silverman4787a6e2018-10-06 16:00:54 -0700381 if (written < (int)sizeof(data) && printing_implementation_ != nullptr) {
Brian Silverman8d3816a2017-07-03 18:52:15 -0700382 int to_write = sizeof(data) - written;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800383 if (to_write > 64) {
384 to_write = 64;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700385 }
Philipp Schrader790cb542023-07-05 21:06:52 -0700386 int result = printing_implementation_->Write(
387 ((const char *)data) + written, to_write);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700388 if (result >= 0) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800389 written += result;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700390 } else {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800391 printf("error\n");
Brian Silverman8d3816a2017-07-03 18:52:15 -0700392 }
Brian Silverman19ea60f2018-01-03 21:43:15 -0800393 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700394#if 0
Brian Silverman19ea60f2018-01-03 21:43:15 -0800395 if (!done_writing && written >= (int)sizeof(data) &&
Brian Silverman4787a6e2018-10-06 16:00:54 -0700396 printing_implementation_->write_queue_empty()) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800397 printf("done writing %d\n", written);
398 done_writing = true;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700399 }
Brian Silverman4787a6e2018-10-06 16:00:54 -0700400#endif
Brian Silverman8d3816a2017-07-03 18:52:15 -0700401 }
Austin Schuh5b0e6b62019-04-07 14:23:37 -0700402#endif // PRINT_ALL_READINGS/TAKE_SAMPLE
Brian Silverman8d3816a2017-07-03 18:52:15 -0700403 (void)balanced;
404
405 // Tell the hardware to use the new switching points.
Brian Silverman19ea60f2018-01-03 21:43:15 -0800406 // TODO(Brian): Somehow verify that we consistently hit the first or second
407 // timer-cycle with the new values (if there's two).
Brian Silverman8d3816a2017-07-03 18:52:15 -0700408 pwm_ftm_->PWMLOAD = FTM_PWMLOAD_LDOK;
409
Brian Silverman19ea60f2018-01-03 21:43:15 -0800410#if PRINT_TIMING
411 static int print_timing_count = 0;
412 static uint32_t print_timing_total = 0;
413 print_timing_total += time_subtract(nanos(), start_nanos);
414 if (++print_timing_count == 1000) {
415 printf("took %" PRIu32 "/%d\n", print_timing_total, print_timing_count);
416 print_timing_count = 0;
417 print_timing_total = 0;
418 }
James Kuszmaul998d3032018-09-08 15:41:41 -0700419#endif // PRINT_TIMING
Brian Silverman19ea60f2018-01-03 21:43:15 -0800420
Brian Silverman8d3816a2017-07-03 18:52:15 -0700421 // If another cycle has already started, turn the light on right now.
422 if (pwm_ftm_->SC & FTM_SC_TOF) {
423 GPIOC_PSOR = 1 << 5;
424 }
425}
426
Brian Silverman19ea60f2018-01-03 21:43:15 -0800427uint32_t Motor::CalculateOnTime(uint32_t width) const {
428 if (width > 0) {
429 width += deadtime_compensation_;
430 if (flip_time_offset_) {
431 width += 1;
432 }
433 }
434 return (counts_per_cycle() - width) / 2;
435}
436
437uint32_t Motor::CalculateOffTime(uint32_t width) const {
438 if (width > 0) {
439 width += deadtime_compensation_;
440 if (!flip_time_offset_) {
441 width += 1;
442 }
443 }
444 return (counts_per_cycle() + width) / 2;
445}
446
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800447} // namespace frc971::motors