blob: 36d489faff66c76c01e245b46ed2278cf73bf725 [file] [log] [blame]
Brian Silverman54dd2fe2018-03-16 23:44:31 -07001// This file has the main for the Teensy on the simple receiver board.
2
3#include <inttypes.h>
4#include <stdio.h>
5#include <atomic>
6#include <cmath>
7
Austin Schuh4fae0fc2018-03-27 23:51:42 -07008#include "frc971/control_loops/drivetrain/polydrivetrain.h"
Brian Silverman54dd2fe2018-03-16 23:44:31 -07009#include "motors/core/kinetis.h"
Brian Silvermana3a172b2018-03-24 03:53:32 -040010#include "motors/core/time.h"
Brian Silverman54dd2fe2018-03-16 23:44:31 -070011#include "motors/peripheral/adc.h"
12#include "motors/peripheral/can.h"
Brian Silvermana3a172b2018-03-24 03:53:32 -040013#include "motors/peripheral/configuration.h"
Brian Silverman4787a6e2018-10-06 16:00:54 -070014#include "motors/print/print.h"
Austin Schuh4fae0fc2018-03-27 23:51:42 -070015#include "motors/seems_reasonable/drivetrain_dog_motor_plant.h"
16#include "motors/seems_reasonable/polydrivetrain_dog_motor_plant.h"
17#include "motors/seems_reasonable/spring.h"
Brian Silverman54dd2fe2018-03-16 23:44:31 -070018#include "motors/util.h"
19
20namespace frc971 {
21namespace motors {
22namespace {
23
Austin Schuhbcce26a2018-03-26 23:41:24 -070024using ::frc971::control_loops::drivetrain::DrivetrainConfig;
25using ::frc971::control_loops::drivetrain::PolyDrivetrain;
26using ::frc971::constants::ShifterHallEffect;
27using ::frc971::control_loops::DrivetrainQueue_Goal;
28using ::frc971::control_loops::DrivetrainQueue_Output;
Austin Schuh4fae0fc2018-03-27 23:51:42 -070029using ::motors::seems_reasonable::Spring;
Austin Schuhbcce26a2018-03-26 23:41:24 -070030
Brian Silverman9ed2cf12018-05-12 13:06:38 -070031struct SimpleAdcReadings {
32 uint16_t sin, cos;
33};
34
35void AdcInitSimple() {
36 AdcInitCommon();
37
38 // ENC_SIN ADC0_SE23
39 // ENC_COS ADC1_SE23
40}
41
42SimpleAdcReadings AdcReadSimple(const DisableInterrupts &) {
43 SimpleAdcReadings r;
44
45 ADC0_SC1A = 23;
46 ADC1_SC1A = 23;
47 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
48 }
49 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
50 }
51 r.sin = ADC0_RA;
52 r.cos = ADC1_RA;
53
54 return r;
55}
56
Austin Schuhbcce26a2018-03-26 23:41:24 -070057const ShifterHallEffect kThreeStateDriveShifter{0.0, 0.0, 0.25, 0.75};
58
59const DrivetrainConfig<float> &GetDrivetrainConfig() {
60 static DrivetrainConfig<float> kDrivetrainConfig{
61 ::frc971::control_loops::drivetrain::ShifterType::NO_SHIFTER,
62 ::frc971::control_loops::drivetrain::LoopType::OPEN_LOOP,
63 ::frc971::control_loops::drivetrain::GyroType::SPARTAN_GYRO,
64 ::frc971::control_loops::drivetrain::IMUType::IMU_X,
65
66 ::motors::seems_reasonable::MakeDrivetrainLoop,
67 ::motors::seems_reasonable::MakeVelocityDrivetrainLoop,
68 ::std::function<StateFeedbackLoop<7, 2, 4, float>()>(),
69
70 ::motors::seems_reasonable::kDt, ::motors::seems_reasonable::kRobotRadius,
71 ::motors::seems_reasonable::kWheelRadius, ::motors::seems_reasonable::kV,
72
73 ::motors::seems_reasonable::kHighGearRatio,
74 ::motors::seems_reasonable::kLowGearRatio, kThreeStateDriveShifter,
75 kThreeStateDriveShifter, true /* default_high_gear */,
76 0 /* down_offset if using constants use
77 constants::GetValues().down_error */, 0.8 /* wheel_non_linearity */,
78 1.2 /* quickturn_wheel_multiplier */, 1.5 /* wheel_multiplier */,
79 };
80
81 return kDrivetrainConfig;
82};
83
84
Austin Schuhbcce26a2018-03-26 23:41:24 -070085::std::atomic<PolyDrivetrain<float> *> global_polydrivetrain{nullptr};
Austin Schuh4fae0fc2018-03-27 23:51:42 -070086::std::atomic<Spring *> global_spring{nullptr};
Austin Schuhbcce26a2018-03-26 23:41:24 -070087
Brian Silvermana3a172b2018-03-24 03:53:32 -040088// Last width we received on each channel.
Brian Silverman7f5f1442018-04-06 13:00:50 -040089uint16_t pwm_input_widths[6];
Brian Silvermana3a172b2018-03-24 03:53:32 -040090// When we received a pulse on each channel in milliseconds.
Brian Silverman7f5f1442018-04-06 13:00:50 -040091uint32_t pwm_input_times[6];
Brian Silvermana3a172b2018-03-24 03:53:32 -040092
Austin Schuhbcce26a2018-03-26 23:41:24 -070093constexpr int kChannelTimeout = 100;
94
95bool lost_channel(int channel) {
96 DisableInterrupts disable_interrupts;
97 if (time_after(millis(),
98 time_add(pwm_input_times[channel], kChannelTimeout))) {
99 return true;
100 }
101 return false;
102}
103
Brian Silvermana3a172b2018-03-24 03:53:32 -0400104// Returns the most recently captured value for the specified input channel
105// scaled from -1 to 1, or 0 if it was captured over 100ms ago.
106float convert_input_width(int channel) {
107 uint16_t width;
108 {
109 DisableInterrupts disable_interrupts;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700110 if (time_after(millis(),
111 time_add(pwm_input_times[channel], kChannelTimeout))) {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400112 return 0;
113 }
114
115 width = pwm_input_widths[channel];
116 }
117
118 // Values measured with a channel mapped to a button.
119 static constexpr uint16_t kMinWidth = 4133;
120 static constexpr uint16_t kMaxWidth = 7177;
121 if (width < kMinWidth) {
122 width = kMinWidth;
123 } else if (width > kMaxWidth) {
124 width = kMaxWidth;
125 }
126 return (static_cast<float>(2 * (width - kMinWidth)) /
127 static_cast<float>(kMaxWidth - kMinWidth)) -
128 1.0f;
129}
130
131// Sends a SET_RPM command to the specified VESC.
132// Note that sending 6 VESC commands every 1ms doesn't quite fit in the CAN
133// bandwidth.
134void vesc_set_rpm(int vesc_id, float rpm) {
135 const int32_t rpm_int = rpm;
136 uint32_t id = CAN_EFF_FLAG;
137 id |= vesc_id;
138 id |= (0x03 /* SET_RPM */) << 8;
139 uint8_t data[4] = {
140 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
141 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
142 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
143 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
144 };
145 can_send(id, data, sizeof(data), 2 + vesc_id);
146}
147
148// Sends a SET_CURRENT command to the specified VESC.
149// current is in amps.
150// Note that sending 6 VESC commands every 1ms doesn't quite fit in the CAN
151// bandwidth.
152void vesc_set_current(int vesc_id, float current) {
Austin Schuhbcce26a2018-03-26 23:41:24 -0700153 constexpr float kMaxCurrent = 80.0f;
154 const int32_t current_int =
155 ::std::max(-kMaxCurrent, ::std::min(kMaxCurrent, current)) * 1000.0f;
Brian Silvermana3a172b2018-03-24 03:53:32 -0400156 uint32_t id = CAN_EFF_FLAG;
157 id |= vesc_id;
158 id |= (0x01 /* SET_CURRENT */) << 8;
159 uint8_t data[4] = {
160 static_cast<uint8_t>((current_int >> 24) & 0xFF),
161 static_cast<uint8_t>((current_int >> 16) & 0xFF),
162 static_cast<uint8_t>((current_int >> 8) & 0xFF),
163 static_cast<uint8_t>((current_int >> 0) & 0xFF),
164 };
165 can_send(id, data, sizeof(data), 2 + vesc_id);
166}
167
Brian Silverman4d1e5272018-03-26 03:18:42 -0400168// Sends a SET_DUTY command to the specified VESC.
169// duty is from -1 to 1.
170// Note that sending 6 VESC commands every 1ms doesn't quite fit in the CAN
171// bandwidth.
172void vesc_set_duty(int vesc_id, float duty) {
Austin Schuhbcce26a2018-03-26 23:41:24 -0700173 constexpr int32_t kMaxDuty = 99999;
174 const int32_t duty_int = ::std::max(
175 -kMaxDuty, ::std::min(kMaxDuty, static_cast<int32_t>(duty * 100000.0f)));
Brian Silverman4d1e5272018-03-26 03:18:42 -0400176 uint32_t id = CAN_EFF_FLAG;
177 id |= vesc_id;
178 id |= (0x00 /* SET_DUTY */) << 8;
179 uint8_t data[4] = {
180 static_cast<uint8_t>((duty_int >> 24) & 0xFF),
181 static_cast<uint8_t>((duty_int >> 16) & 0xFF),
182 static_cast<uint8_t>((duty_int >> 8) & 0xFF),
183 static_cast<uint8_t>((duty_int >> 0) & 0xFF),
184 };
185 can_send(id, data, sizeof(data), 2 + vesc_id);
186}
187
Brian Silverman6c8b88b2018-09-03 18:17:02 -0700188// TODO(Brian): Move these two test functions somewhere else.
189__attribute__((unused)) void DoVescTest() {
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700190 uint32_t time = micros();
191 while (true) {
192 for (int i = 0; i < 6; ++i) {
193 const uint32_t end = time_add(time, 500000);
194 while (true) {
195 const bool done = time_after(micros(), end);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700196 float current;
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700197 if (done) {
198 current = -6;
199 } else {
200 current = 6;
201 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400202 vesc_set_current(i, current);
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700203 if (done) {
204 break;
205 }
206 delay(5);
207 }
208 time = end;
209 }
210 }
211}
212
Brian Silverman6c8b88b2018-09-03 18:17:02 -0700213__attribute__((unused)) void DoReceiverTest2() {
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700214 static constexpr float kMaxRpm = 10000.0f;
215 while (true) {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400216 const bool flip = convert_input_width(2) > 0;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700217
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700218 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400219 const float value = convert_input_width(0);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700220
221 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400222 float rpm = ::std::min(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700223 if (flip) {
224 rpm *= -1.0f;
225 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400226 vesc_set_rpm(0, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700227 }
228
229 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400230 float rpm = ::std::max(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700231 if (flip) {
232 rpm *= -1.0f;
233 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400234 vesc_set_rpm(1, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700235 }
236 }
237
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700238 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400239 const float value = convert_input_width(1);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700240
241 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400242 float rpm = ::std::min(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700243 if (flip) {
244 rpm *= -1.0f;
245 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400246 vesc_set_rpm(2, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700247 }
248
249 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400250 float rpm = ::std::max(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700251 if (flip) {
252 rpm *= -1.0f;
253 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400254 vesc_set_rpm(3, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700255 }
256 }
257
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700258 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400259 const float value = convert_input_width(4);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700260
261 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400262 float rpm = ::std::min(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700263 if (flip) {
264 rpm *= -1.0f;
265 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400266 vesc_set_rpm(4, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700267 }
268
269 {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400270 float rpm = ::std::max(0.0f, value) * kMaxRpm;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700271 if (flip) {
272 rpm *= -1.0f;
273 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400274 vesc_set_rpm(5, rpm);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700275 }
276 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400277 // Give the CAN frames a chance to go out.
278 delay(5);
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700279 }
280}
281
282void SetupPwmFtm(BigFTM *ftm) {
283 ftm->MODE = FTM_MODE_WPDIS;
284 ftm->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
285 ftm->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
286
287 // Can't change MOD according to the reference manual ("The Dual Edge Capture
288 // mode must be used with ... the FTM counter in Free running counter.").
289 ftm->MOD = 0xFFFF;
290
291 // Capturing rising edge.
292 ftm->C0SC = FTM_CSC_MSA | FTM_CSC_ELSA;
293 // Capturing falling edge.
Brian Silvermana3a172b2018-03-24 03:53:32 -0400294 ftm->C1SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSB;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700295
296 // Capturing rising edge.
297 ftm->C2SC = FTM_CSC_MSA | FTM_CSC_ELSA;
298 // Capturing falling edge.
Brian Silvermana3a172b2018-03-24 03:53:32 -0400299 ftm->C3SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSB;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700300
301 // Capturing rising edge.
302 ftm->C4SC = FTM_CSC_MSA | FTM_CSC_ELSA;
303 // Capturing falling edge.
Brian Silvermana3a172b2018-03-24 03:53:32 -0400304 ftm->C5SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSB;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700305
306 // Capturing rising edge.
307 ftm->C6SC = FTM_CSC_MSA | FTM_CSC_ELSA;
308 // Capturing falling edge.
Brian Silvermana3a172b2018-03-24 03:53:32 -0400309 ftm->C7SC = FTM_CSC_CHIE | FTM_CSC_MSA | FTM_CSC_ELSB;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700310
Brian Silvermana3a172b2018-03-24 03:53:32 -0400311 (void)ftm->STATUS;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700312 ftm->STATUS = 0x00;
313
314 ftm->COMBINE = FTM_COMBINE_DECAP3 | FTM_COMBINE_DECAPEN3 |
315 FTM_COMBINE_DECAP2 | FTM_COMBINE_DECAPEN2 |
316 FTM_COMBINE_DECAP1 | FTM_COMBINE_DECAPEN1 |
317 FTM_COMBINE_DECAP0 | FTM_COMBINE_DECAPEN0;
318
319 // 34.95ms max period before it starts wrapping and being weird.
320 ftm->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
321 FTM_SC_PS(4) /* Prescaler=32 */;
322
323 ftm->MODE &= ~FTM_MODE_WPDIS;
324}
325
Brian Silverman2de95d62018-03-31 12:32:24 -0700326struct AccelerometerResult {
327 uint16_t result;
328 bool success;
329};
330
331// Does a transfer on the accelerometer. Returns the resulting frame, or a
332// failure if it takes until after end_micros.
333AccelerometerResult AccelerometerTransfer(uint16_t data, uint32_t end_micros) {
334 SPI0_SR = SPI_SR_RFDF;
335 SPI0_PUSHR = SPI_PUSHR_PCS(1) | data;
336
337 while (!(SPI0_SR & SPI_SR_RFDF)) {
338 if (time_after(micros(), end_micros)) {
339 return {0, false};
340 }
341 }
342 const uint32_t popr = SPI0_POPR;
343 SPI0_SR = SPI_SR_RFDF;
344 return {static_cast<uint16_t>(popr & 0xFFFF), true};
345}
346
347constexpr uint32_t kAccelerometerTimeout = 500;
348
349bool AccelerometerWrite(uint8_t address, uint8_t data, uint32_t end_micros) {
350 const AccelerometerResult r = AccelerometerTransfer(
351 (static_cast<uint16_t>(address) << 8) | static_cast<uint16_t>(data),
352 end_micros);
353 return r.success;
354}
355
356AccelerometerResult AccelerometerRead(uint8_t address, uint32_t end_micros) {
357 AccelerometerResult r = AccelerometerTransfer(
358 (static_cast<uint16_t>(address) << 8) | UINT16_C(0x8000), end_micros);
359 r.result = r.result & UINT16_C(0xFF);
360 return r;
361}
362
363bool accelerometer_inited = false;
364
365void AccelerometerInit() {
366 accelerometer_inited = false;
367 const uint32_t end_micros = time_add(micros(), kAccelerometerTimeout);
368 {
369 const auto who_am_i = AccelerometerRead(0xF, end_micros);
370 if (!who_am_i.success) {
371 return;
372 }
373 if (who_am_i.result != 0x32) {
374 return;
375 }
376 }
377 if (!AccelerometerWrite(
378 0x20, (1 << 5) /* Normal mode */ | (1 << 3) /* 100 Hz */ |
379 (1 << 2) /* Z enabled */ | (1 << 1) /* Y enabled */ |
380 (1 << 0) /* X enabled */,
381 end_micros)) {
382 }
383 // If want to read LSB, need to enable BDU to avoid splitting reads.
384 if (!AccelerometerWrite(0x23, (0 << 6) /* Data LSB at lower address */ |
385 (3 << 4) /* 400g full scale */ |
386 (0 << 0) /* 4-wire interface */,
387 end_micros)) {
388 }
389 accelerometer_inited = true;
390}
391
392float AccelerometerConvert(uint16_t value) {
393 return static_cast<float>(400.0 / 65536.0) * static_cast<float>(value);
394}
395
396// Returns the total acceleration (in any direction) or 0 if there's an error.
397float ReadAccelerometer() {
398 if (!accelerometer_inited) {
399 AccelerometerInit();
400 return 0;
401 }
402
403 const uint32_t end_micros = time_add(micros(), kAccelerometerTimeout);
404 const auto x = AccelerometerRead(0x29, end_micros);
405 const auto y = AccelerometerRead(0x2B, end_micros);
406 const auto z = AccelerometerRead(0x2D, end_micros);
407 if (!x.success || !y.success || !z.success) {
408 accelerometer_inited = false;
409 return 0;
410 }
411
412 const float x_g = AccelerometerConvert(x.result);
413 const float y_g = AccelerometerConvert(y.result);
414 const float z_g = AccelerometerConvert(z.result);
415 return ::std::sqrt(x_g * x_g + y_g * y_g + z_g * z_g);
416}
417
Brian Silvermana3a172b2018-03-24 03:53:32 -0400418extern "C" void ftm0_isr() {
419 while (true) {
420 const uint32_t status = FTM0->STATUS;
421 if (status == 0) {
422 return;
423 }
424
425 if (status & (1 << 1)) {
426 const uint32_t start = FTM0->C0V;
427 const uint32_t end = FTM0->C1V;
428 pwm_input_widths[0] = (end - start) & 0xFFFF;
429 pwm_input_times[0] = millis();
430 }
431 if (status & (1 << 7)) {
432 const uint32_t start = FTM0->C6V;
433 const uint32_t end = FTM0->C7V;
434 pwm_input_widths[1] = (end - start) & 0xFFFF;
435 pwm_input_times[1] = millis();
436 }
437 if (status & (1 << 5)) {
438 const uint32_t start = FTM0->C4V;
439 const uint32_t end = FTM0->C5V;
440 pwm_input_widths[2] = (end - start) & 0xFFFF;
441 pwm_input_times[2] = millis();
442 }
443 if (status & (1 << 3)) {
444 const uint32_t start = FTM0->C2V;
445 const uint32_t end = FTM0->C3V;
446 pwm_input_widths[4] = (end - start) & 0xFFFF;
447 pwm_input_times[4] = millis();
448 }
449
450 FTM0->STATUS = 0;
451 }
452}
453
454extern "C" void ftm3_isr() {
455 while (true) {
456 const uint32_t status = FTM3->STATUS;
457 if (status == 0) {
458 return;
459 }
460
461 if (status & (1 << 3)) {
462 const uint32_t start = FTM3->C2V;
463 const uint32_t end = FTM3->C3V;
464 pwm_input_widths[3] = (end - start) & 0xFFFF;
465 pwm_input_times[3] = millis();
466 }
Brian Silverman7f5f1442018-04-06 13:00:50 -0400467 if (status & (1 << 7)) {
468 const uint32_t start = FTM3->C6V;
469 const uint32_t end = FTM3->C7V;
470 pwm_input_widths[5] = (end - start) & 0xFFFF;
471 pwm_input_times[5] = millis();
472 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400473
474 FTM3->STATUS = 0;
475 }
476}
477
478float ConvertEncoderChannel(uint16_t reading) {
479 // Theoretical values based on the datasheet are 931 and 2917.
480 // With these values, the magnitude ranges from 0.99-1.03, which works fine
481 // (the encoder's output appears to get less accurate in one quadrant for some
482 // reason, hence the variation).
483 static constexpr uint16_t kMin = 802, kMax = 3088;
484 if (reading < kMin) {
485 reading = kMin;
486 } else if (reading > kMax) {
487 reading = kMax;
488 }
489 return (static_cast<float>(2 * (reading - kMin)) /
490 static_cast<float>(kMax - kMin)) -
491 1.0f;
492}
493
494struct EncoderReading {
Brian Silvermana96c1a42018-05-12 12:11:31 -0700495 EncoderReading(const SimpleAdcReadings &adc_readings) {
Brian Silvermana3a172b2018-03-24 03:53:32 -0400496 const float sin = ConvertEncoderChannel(adc_readings.sin);
497 const float cos = ConvertEncoderChannel(adc_readings.cos);
498
Austin Schuhbcce26a2018-03-26 23:41:24 -0700499 const float magnitude = hypot(sin, cos);
Brian Silvermana3a172b2018-03-24 03:53:32 -0400500 const float magnitude_error = ::std::abs(magnitude - 1.0f);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700501 valid = magnitude_error < 0.30f;
Brian Silvermana3a172b2018-03-24 03:53:32 -0400502
503 angle = ::std::atan2(sin, cos);
504 }
505
506 // Angle in radians, in [-pi, pi].
507 float angle;
508
509 bool valid;
510};
511
512extern "C" void pit3_isr() {
513 PIT_TFLG3 = 1;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700514 PolyDrivetrain<float> *polydrivetrain =
515 global_polydrivetrain.load(::std::memory_order_acquire);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700516 Spring *spring = global_spring.load(::std::memory_order_acquire);
Brian Silvermana3a172b2018-03-24 03:53:32 -0400517
Brian Silvermana96c1a42018-05-12 12:11:31 -0700518 SimpleAdcReadings adc_readings;
Brian Silvermana3a172b2018-03-24 03:53:32 -0400519 {
520 DisableInterrupts disable_interrupts;
Brian Silvermana96c1a42018-05-12 12:11:31 -0700521 adc_readings = AdcReadSimple(disable_interrupts);
Brian Silvermana3a172b2018-03-24 03:53:32 -0400522 }
523
524 EncoderReading encoder(adc_readings);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700525 static float last_good_encoder = 0.0f;
526 static int invalid_encoder_count = 0;
527 if (encoder.valid) {
528 last_good_encoder = encoder.angle;
529 invalid_encoder_count = 0;
530 } else {
531 ++invalid_encoder_count;
532 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400533
Austin Schuhe666dc62018-08-08 21:09:12 -0700534 const bool lost_spring_channel = lost_channel(2) || lost_channel(3) ||
535 lost_channel(4) || lost_channel(5) ||
536 (convert_input_width(4) < 0.5f);
537
538 const bool lost_drive_channel = lost_channel(0) || lost_channel(1) ||
539 (::std::abs(convert_input_width(4)) < 0.5f);
Austin Schuhbcce26a2018-03-26 23:41:24 -0700540
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700541 if (polydrivetrain != nullptr && spring != nullptr) {
Austin Schuhbcce26a2018-03-26 23:41:24 -0700542 DrivetrainQueue_Goal goal;
543 goal.control_loop_driving = false;
Austin Schuhe666dc62018-08-08 21:09:12 -0700544 if (lost_drive_channel) {
Austin Schuhbcce26a2018-03-26 23:41:24 -0700545 goal.throttle = 0.0f;
546 goal.wheel = 0.0f;
547 } else {
548 goal.throttle = convert_input_width(1);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700549 goal.wheel = -convert_input_width(0);
Austin Schuhbcce26a2018-03-26 23:41:24 -0700550 }
Austin Schuhbcce26a2018-03-26 23:41:24 -0700551 goal.quickturn = ::std::abs(polydrivetrain->velocity()) < 0.25f;
552
553 DrivetrainQueue_Output output;
554
555 polydrivetrain->SetGoal(goal);
556 polydrivetrain->Update();
557 polydrivetrain->SetOutput(&output);
558
559 vesc_set_duty(0, -output.left_voltage / 12.0f);
560 vesc_set_duty(1, -output.left_voltage / 12.0f);
561
562 vesc_set_duty(2, output.right_voltage / 12.0f);
563 vesc_set_duty(3, output.right_voltage / 12.0f);
564
Austin Schuhe666dc62018-08-08 21:09:12 -0700565 const bool prime = convert_input_width(2) > 0.1f;
566 const bool fire = convert_input_width(3) > 0.1f;
567 const bool force_move =
568 (convert_input_width(5) > 0.1f) && !lost_spring_channel;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700569
Austin Schuhe666dc62018-08-08 21:09:12 -0700570 bool unload = lost_spring_channel;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700571 static bool was_lost = true;
Austin Schuhe666dc62018-08-08 21:09:12 -0700572 bool force_reset = !lost_spring_channel && was_lost;
573 was_lost = lost_spring_channel;
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700574
Austin Schuhe666dc62018-08-08 21:09:12 -0700575 spring->Iterate(unload, prime, fire, force_reset, force_move,
576 invalid_encoder_count <= 2, last_good_encoder);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700577
578 float spring_output = spring->output();
579
580 vesc_set_duty(4, -spring_output);
581 vesc_set_duty(5, spring_output);
582
Brian Silverman2de95d62018-03-31 12:32:24 -0700583 const float accelerometer = ReadAccelerometer();
584 (void)accelerometer;
585
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700586 /*
587 // Massive debug. Turn on for useful bits.
Brian Silverman2de95d62018-03-31 12:32:24 -0700588 printf("acc %d/1000\n", (int)(accelerometer / 1000));
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700589 if (!encoder.valid) {
590 printf("Stuck encoder: ADC %" PRIu16 " %" PRIu16
591 " enc %d/1000 %s mag %d\n",
592 adc_readings.sin, adc_readings.cos, (int)(encoder.angle * 1000),
593 encoder.valid ? "T" : "f",
594 (int)(hypot(ConvertEncoderChannel(adc_readings.sin),
595 ConvertEncoderChannel(adc_readings.cos)) *
596 1000));
597 }
Austin Schuhbcce26a2018-03-26 23:41:24 -0700598 static int i = 0;
599 ++i;
600 if (i > 20) {
601 i = 0;
Austin Schuhe666dc62018-08-08 21:09:12 -0700602 if (lost_spring_channel || lost_drive_channel) {
603 printf("200Hz loop, disabled %d %d %d %d %d %d\n",
Austin Schuhbcce26a2018-03-26 23:41:24 -0700604 (int)(convert_input_width(0) * 1000),
605 (int)(convert_input_width(1) * 1000),
606 (int)(convert_input_width(2) * 1000),
607 (int)(convert_input_width(3) * 1000),
Austin Schuhe666dc62018-08-08 21:09:12 -0700608 (int)(convert_input_width(4) * 1000),
609 (int)(convert_input_width(5) * 1000));
Austin Schuhbcce26a2018-03-26 23:41:24 -0700610 } else {
611 printf(
Austin Schuhe666dc62018-08-08 21:09:12 -0700612 "TODO(Austin): 200Hz loop %d %d %d %d %d %d, lr, %d, %d velocity %d
613 "
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700614 " state: %d, near %d angle %d goal %d to: %d ADC %" PRIu16
615 " %" PRIu16 " enc %d/1000 %s from %d\n",
Austin Schuhbcce26a2018-03-26 23:41:24 -0700616 (int)(convert_input_width(0) * 1000),
617 (int)(convert_input_width(1) * 1000),
618 (int)(convert_input_width(2) * 1000),
619 (int)(convert_input_width(3) * 1000),
620 (int)(convert_input_width(4) * 1000),
Austin Schuhe666dc62018-08-08 21:09:12 -0700621 (int)(convert_input_width(5) * 1000),
Austin Schuhbcce26a2018-03-26 23:41:24 -0700622 static_cast<int>(output.left_voltage * 100),
623 static_cast<int>(output.right_voltage * 100),
624 static_cast<int>(polydrivetrain->velocity() * 100),
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700625 static_cast<int>(spring->state()), static_cast<int>(spring->Near()),
626 static_cast<int>(spring->angle() * 1000),
627 static_cast<int>(spring->goal() * 1000),
628 static_cast<int>(spring->timeout()), adc_readings.sin,
629 adc_readings.cos, (int)(encoder.angle * 1000),
Austin Schuhbcce26a2018-03-26 23:41:24 -0700630 encoder.valid ? "T" : "f",
631 (int)(::std::sqrt(ConvertEncoderChannel(adc_readings.sin) *
632 ConvertEncoderChannel(adc_readings.sin) +
633 ConvertEncoderChannel(adc_readings.cos) *
634 ConvertEncoderChannel(adc_readings.cos)) *
635 1000));
636 }
637 }
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700638 */
Austin Schuhbcce26a2018-03-26 23:41:24 -0700639 }
Brian Silvermana3a172b2018-03-24 03:53:32 -0400640}
641
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700642} // namespace
643
644extern "C" {
645
646void *__stack_chk_guard = (void *)0x67111971;
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700647void __stack_chk_fail(void);
648
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700649} // extern "C"
650
651extern "C" int main(void) {
652 // for background about this startup delay, please see these conversations
653 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
654 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
655 delay(400);
656
657 // Set all interrupts to the second-lowest priority to start with.
658 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
659
660 // Now set priorities for all the ones we care about. They only have meaning
661 // relative to each other, which means centralizing them here makes it a lot
662 // more manageable.
663 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
Brian Silvermana3a172b2018-03-24 03:53:32 -0400664 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0xa);
665 NVIC_SET_SANE_PRIORITY(IRQ_FTM3, 0xa);
666 NVIC_SET_SANE_PRIORITY(IRQ_PIT_CH3, 0x5);
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700667
668 // Builtin LED.
669 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 1;
670 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
671 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
672
673 // Set up the CAN pins.
674 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
675 PORTA_PCR13 = PORT_PCR_DSE | PORT_PCR_MUX(2);
676
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700677 // PWM_IN0
678 // FTM0_CH0
679 PORTC_PCR1 = PORT_PCR_MUX(4);
680
681 // PWM_IN1
682 // FTM0_CH6
683 PORTD_PCR6 = PORT_PCR_MUX(4);
684
685 // PWM_IN2
686 // FTM0_CH4
687 PORTD_PCR4 = PORT_PCR_MUX(4);
688
689 // PWM_IN3
690 // FTM3_CH2
691 PORTD_PCR2 = PORT_PCR_MUX(4);
692
693 // PWM_IN4
694 // FTM0_CH2
695 PORTC_PCR3 = PORT_PCR_MUX(4);
696
Brian Silverman7f5f1442018-04-06 13:00:50 -0400697 // PWM_IN5
698 // FTM3_CH6
699 PORTC_PCR10 = PORT_PCR_MUX(3);
700
Brian Silverman2de95d62018-03-31 12:32:24 -0700701 // SPI0
702 // ACC_CS PCS0
703 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(2);
704 // SCK
705 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(2);
706 // MOSI
707 PORTA_PCR16 = PORT_PCR_DSE | PORT_PCR_MUX(2);
708 // MISO
709 PORTA_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(2);
710
711 SIM_SCGC6 |= SIM_SCGC6_SPI0;
712 SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(1) | SPI_MCR_CLR_TXF |
713 SPI_MCR_CLR_RXF | SPI_MCR_HALT;
714 // 60 MHz "protocol clock"
715 // 6ns CS setup
716 // 8ns CS hold
717 SPI0_CTAR0 = SPI_CTAR_FMSZ(15) | SPI_CTAR_CPOL /* Clock idles high */ |
718 SPI_CTAR_CPHA /* Data captured on trailing edge */ |
719 0 /* !LSBFE MSB first */ |
720 SPI_CTAR_PCSSCK(0) /* PCS->SCK prescaler = 1 */ |
721 SPI_CTAR_PASC(0) /* SCK->PCS prescaler = 1 */ |
722 SPI_CTAR_PDT(0) /* PCS->PCS prescaler = 1 */ |
723 SPI_CTAR_PBR(0) /* baud prescaler = 1 */ |
724 SPI_CTAR_CSSCK(0) /* PCS->SCK 2/60MHz = 33.33ns */ |
725 SPI_CTAR_ASC(0) /* SCK->PCS 2/60MHz = 33.33ns */ |
726 SPI_CTAR_DT(2) /* PCS->PSC 8/60MHz = 133.33ns */ |
727 SPI_CTAR_BR(2) /* BR 60MHz/6 = 10MHz */;
728
729 SPI0_MCR &= ~SPI_MCR_HALT;
730
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700731 delay(100);
732
Brian Silverman4787a6e2018-10-06 16:00:54 -0700733 PrintingParameters printing_parameters;
734 printing_parameters.dedicated_usb = true;
735 const ::std::unique_ptr<PrintingImplementation> printing =
736 CreatePrinting(printing_parameters);
737 printing->Initialize();
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700738
Brian Silvermana3a172b2018-03-24 03:53:32 -0400739 SIM_SCGC6 |= SIM_SCGC6_PIT;
740 // Workaround for errata e7914.
741 (void)PIT_MCR;
742 PIT_MCR = 0;
Austin Schuhbcce26a2018-03-26 23:41:24 -0700743 PIT_LDVAL3 = (BUS_CLOCK_FREQUENCY / 200) - 1;
Brian Silvermana3a172b2018-03-24 03:53:32 -0400744 PIT_TCTRL3 = PIT_TCTRL_TIE | PIT_TCTRL_TEN;
745
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700746 can_init(0, 1);
Brian Silvermana96c1a42018-05-12 12:11:31 -0700747 AdcInitSimple();
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700748 SetupPwmFtm(FTM0);
749 SetupPwmFtm(FTM3);
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700750
Austin Schuhbcce26a2018-03-26 23:41:24 -0700751 PolyDrivetrain<float> polydrivetrain(GetDrivetrainConfig(), nullptr);
752 global_polydrivetrain.store(&polydrivetrain, ::std::memory_order_release);
Austin Schuh4fae0fc2018-03-27 23:51:42 -0700753 Spring spring;
754 global_spring.store(&spring, ::std::memory_order_release);
Austin Schuhbcce26a2018-03-26 23:41:24 -0700755
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700756 // Leave the LEDs on for a bit longer.
757 delay(300);
758 printf("Done starting up\n");
759
Brian Silverman2de95d62018-03-31 12:32:24 -0700760 AccelerometerInit();
761 printf("Accelerometer init %s\n", accelerometer_inited ? "success" : "fail");
762
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700763 // Done starting up, now turn the LED off.
764 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 0;
765
Brian Silvermana3a172b2018-03-24 03:53:32 -0400766 NVIC_ENABLE_IRQ(IRQ_FTM0);
767 NVIC_ENABLE_IRQ(IRQ_FTM3);
768 NVIC_ENABLE_IRQ(IRQ_PIT_CH3);
Austin Schuhe666dc62018-08-08 21:09:12 -0700769 printf("Done starting up2\n");
Brian Silvermana3a172b2018-03-24 03:53:32 -0400770
Austin Schuhe666dc62018-08-08 21:09:12 -0700771 //DoReceiverTest2();
Austin Schuhbcce26a2018-03-26 23:41:24 -0700772 while (true) {
773 }
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700774
775 return 0;
776}
777
778void __stack_chk_fail(void) {
779 while (true) {
780 GPIOC_PSOR = (1 << 5);
781 printf("Stack corruption detected\n");
782 delay(1000);
783 GPIOC_PCOR = (1 << 5);
784 delay(1000);
785 }
786}
787
788} // namespace motors
789} // namespace frc971