blob: 8427e021648557c924531e5fb5e1a6aa5c755e77 [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
8#include "motors/core/time.h"
9#include "motors/core/kinetis.h"
10#include "motors/peripheral/adc.h"
11#include "motors/peripheral/can.h"
12#include "motors/usb/usb.h"
13#include "motors/usb/cdc.h"
14#include "motors/util.h"
15
16namespace frc971 {
17namespace motors {
18namespace {
19
20::std::atomic<teensy::AcmTty *> global_stdout{nullptr};
21
Brian Silverman4f8c6a72018-03-17 23:12:45 -070022void DoVescTest() {
Brian Silverman54dd2fe2018-03-16 23:44:31 -070023 uint32_t time = micros();
24 while (true) {
25 for (int i = 0; i < 6; ++i) {
26 const uint32_t end = time_add(time, 500000);
27 while (true) {
28 const bool done = time_after(micros(), end);
Brian Silverman4f8c6a72018-03-17 23:12:45 -070029 float current;
Brian Silverman54dd2fe2018-03-16 23:44:31 -070030 if (done) {
31 current = -6;
32 } else {
33 current = 6;
34 }
35 const int32_t current_int = current * 1000;
36 uint32_t id = CAN_EFF_FLAG;
37 id |= i;
38 id |= (0x01 /* SET_CURRENT */) << 8;
39 uint8_t data[4] = {
40 static_cast<uint8_t>((current_int >> 24) & 0xFF),
41 static_cast<uint8_t>((current_int >> 16) & 0xFF),
42 static_cast<uint8_t>((current_int >> 8) & 0xFF),
43 static_cast<uint8_t>((current_int >> 0) & 0xFF),
44 };
45 can_send(id, data, sizeof(data), 2);
46 if (done) {
47 break;
48 }
49 delay(5);
50 }
51 time = end;
52 }
53 }
54}
55
Brian Silverman4f8c6a72018-03-17 23:12:45 -070056void DoReceiverTest() {
57 while (true) {
58 FTM0->STATUS = 0x00;
59 while (!(FTM0->STATUS & (1 << 1))) {}
60 const uint32_t start = FTM0->C0V;
61 const uint32_t end = FTM0->C1V;
62 const uint32_t now = micros();
63 const uint32_t width = (end - start) & 0xFFFF;
64 printf("got pulse %" PRIu32 "-%" PRIu32 "=%" PRIu32 " at %" PRIu32 "\n",
65 start, end, width, now);
66
67 for (int i = 0; i < 6; ++i) {
68 // 4290 - 6966
69 // 4133 - 7117
70#if 0
71 float current =
72 static_cast<float>(static_cast<int>(width) - 5625) / 1338.0f * 4.0f;
73 const int32_t current_int = current * 1000;
74 uint32_t id = CAN_EFF_FLAG;
75 id |= i;
76 id |= (0x01 /* SET_CURRENT */) << 8;
77 uint8_t data[4] = {
78 static_cast<uint8_t>((current_int >> 24) & 0xFF),
79 static_cast<uint8_t>((current_int >> 16) & 0xFF),
80 static_cast<uint8_t>((current_int >> 8) & 0xFF),
81 static_cast<uint8_t>((current_int >> 0) & 0xFF),
82 };
83#else
84 float rpm = static_cast<float>(static_cast<int>(width) - 5625) / 1338.0f *
85 10000.0f;
86 const int32_t rpm_int = rpm;
87 uint32_t id = CAN_EFF_FLAG;
88 id |= i;
89 id |= (0x03 /* SET_RPM */) << 8;
90 uint8_t data[4] = {
91 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
92 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
93 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
94 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
95 };
96#endif
97 can_send(id, data, sizeof(data), 2);
98 delay(1);
99 }
100 }
101}
102
103// 4290 - 6966
104// 4133 - 7117
105void DoReceiverTest2() {
106 static constexpr int kMin = 4133, kMax = 7177;
107 static constexpr int kMid = (kMin + kMax) / 2, kRange = kMax - kMin;
108 static constexpr float kMaxRpm = 10000.0f;
109 while (true) {
110 FTM0->STATUS = 0x00;
111
112 while (!(FTM0->STATUS & (1 << 5))) {
113 }
114 const uint32_t flip_start = FTM0->C4V;
115 const uint32_t flip_end = FTM0->C5V;
116 const bool flip = ((flip_end - flip_start) & 0xFFFF) > kMid;
117
118 while (!(FTM0->STATUS & (1 << 1))) {
119 }
120 {
121 const uint32_t start = FTM0->C0V;
122 const uint32_t end = FTM0->C1V;
123 const int width = (end - start) & 0xFFFF;
124
125 {
126 float rpm = static_cast<float>(::std::min(0, width - kMid)) /
127 static_cast<float>(kRange) * kMaxRpm;
128 if (flip) {
129 rpm *= -1.0f;
130 }
131 const int32_t rpm_int = rpm;
132 uint32_t id = CAN_EFF_FLAG;
133 id |= 0;
134 id |= (0x03 /* SET_RPM */) << 8;
135 uint8_t data[4] = {
136 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
137 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
138 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
139 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
140 };
141 can_send(id, data, sizeof(data), 2);
142 delay(1);
143 }
144
145 {
146 float rpm = static_cast<float>(::std::max(0, width - kMid)) /
147 static_cast<float>(kRange) * kMaxRpm;
148 if (flip) {
149 rpm *= -1.0f;
150 }
151 const int32_t rpm_int = rpm;
152 uint32_t id = CAN_EFF_FLAG;
153 id |= 1;
154 id |= (0x03 /* SET_RPM */) << 8;
155 uint8_t data[4] = {
156 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
157 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
158 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
159 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
160 };
161 can_send(id, data, sizeof(data), 2);
162 delay(1);
163 }
164 }
165
166 while (!(FTM0->STATUS & (1 << 7))) {
167 }
168 {
169 const uint32_t start = FTM0->C6V;
170 const uint32_t end = FTM0->C7V;
171 const int width = (end - start) & 0xFFFF;
172
173 {
174 float rpm = static_cast<float>(::std::min(0, width - kMid)) /
175 static_cast<float>(kRange) * kMaxRpm;
176 if (flip) {
177 rpm *= -1.0f;
178 }
179 const int32_t rpm_int = rpm;
180 uint32_t id = CAN_EFF_FLAG;
181 id |= 2;
182 id |= (0x03 /* SET_RPM */) << 8;
183 uint8_t data[4] = {
184 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
185 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
186 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
187 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
188 };
189 can_send(id, data, sizeof(data), 2);
190 delay(1);
191 }
192
193 {
194 float rpm = static_cast<float>(::std::max(0, width - kMid)) /
195 static_cast<float>(kRange) * kMaxRpm;
196 if (flip) {
197 rpm *= -1.0f;
198 }
199 const int32_t rpm_int = rpm;
200 uint32_t id = CAN_EFF_FLAG;
201 id |= 3;
202 id |= (0x03 /* SET_RPM */) << 8;
203 uint8_t data[4] = {
204 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
205 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
206 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
207 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
208 };
209 can_send(id, data, sizeof(data), 2);
210 delay(1);
211 }
212 }
213
214 while (!(FTM0->STATUS & (1 << 3))) {
215 }
216 {
217 const uint32_t start = FTM0->C2V;
218 const uint32_t end = FTM0->C3V;
219 const int width = (end - start) & 0xFFFF;
220
221 {
222 float rpm = static_cast<float>(::std::min(0, width - kMid)) /
223 static_cast<float>(kRange) * kMaxRpm;
224 if (flip) {
225 rpm *= -1.0f;
226 }
227 const int32_t rpm_int = rpm;
228 uint32_t id = CAN_EFF_FLAG;
229 id |= 4;
230 id |= (0x03 /* SET_RPM */) << 8;
231 uint8_t data[4] = {
232 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
233 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
234 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
235 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
236 };
237 can_send(id, data, sizeof(data), 2);
238 delay(1);
239 }
240
241 {
242 float rpm = static_cast<float>(::std::max(0, width - kMid)) /
243 static_cast<float>(kRange) * kMaxRpm;
244 if (flip) {
245 rpm *= -1.0f;
246 }
247 const int32_t rpm_int = rpm;
248 uint32_t id = CAN_EFF_FLAG;
249 id |= 5;
250 id |= (0x03 /* SET_RPM */) << 8;
251 uint8_t data[4] = {
252 static_cast<uint8_t>((rpm_int >> 24) & 0xFF),
253 static_cast<uint8_t>((rpm_int >> 16) & 0xFF),
254 static_cast<uint8_t>((rpm_int >> 8) & 0xFF),
255 static_cast<uint8_t>((rpm_int >> 0) & 0xFF),
256 };
257 can_send(id, data, sizeof(data), 2);
258 delay(1);
259 }
260 }
261 }
262}
263
264void SetupPwmFtm(BigFTM *ftm) {
265 ftm->MODE = FTM_MODE_WPDIS;
266 ftm->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
267 ftm->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
268
269 // Can't change MOD according to the reference manual ("The Dual Edge Capture
270 // mode must be used with ... the FTM counter in Free running counter.").
271 ftm->MOD = 0xFFFF;
272
273 // Capturing rising edge.
274 ftm->C0SC = FTM_CSC_MSA | FTM_CSC_ELSA;
275 // Capturing falling edge.
276 ftm->C1SC = FTM_CSC_MSA | FTM_CSC_ELSB;
277
278 // Capturing rising edge.
279 ftm->C2SC = FTM_CSC_MSA | FTM_CSC_ELSA;
280 // Capturing falling edge.
281 ftm->C3SC = FTM_CSC_MSA | FTM_CSC_ELSB;
282
283 // Capturing rising edge.
284 ftm->C4SC = FTM_CSC_MSA | FTM_CSC_ELSA;
285 // Capturing falling edge.
286 ftm->C5SC = FTM_CSC_MSA | FTM_CSC_ELSB;
287
288 // Capturing rising edge.
289 ftm->C6SC = FTM_CSC_MSA | FTM_CSC_ELSA;
290 // Capturing falling edge.
291 ftm->C7SC = FTM_CSC_MSA | FTM_CSC_ELSB;
292
293 ftm->STATUS = 0x00;
294
295 ftm->COMBINE = FTM_COMBINE_DECAP3 | FTM_COMBINE_DECAPEN3 |
296 FTM_COMBINE_DECAP2 | FTM_COMBINE_DECAPEN2 |
297 FTM_COMBINE_DECAP1 | FTM_COMBINE_DECAPEN1 |
298 FTM_COMBINE_DECAP0 | FTM_COMBINE_DECAPEN0;
299
300 // 34.95ms max period before it starts wrapping and being weird.
301 ftm->SC = FTM_SC_CLKS(1) /* Use the system clock */ |
302 FTM_SC_PS(4) /* Prescaler=32 */;
303
304 ftm->MODE &= ~FTM_MODE_WPDIS;
305}
306
307} // namespace
308
309extern "C" {
310
311void *__stack_chk_guard = (void *)0x67111971;
312
313int _write(int /*file*/, char *ptr, int len) {
314 teensy::AcmTty *const tty = global_stdout.load(::std::memory_order_acquire);
315 if (tty != nullptr) {
316 return tty->Write(ptr, len);
317 }
318 return 0;
319}
320
321void __stack_chk_fail(void);
322
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700323} // extern "C"
324
325extern "C" int main(void) {
326 // for background about this startup delay, please see these conversations
327 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
328 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
329 delay(400);
330
331 // Set all interrupts to the second-lowest priority to start with.
332 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
333
334 // Now set priorities for all the ones we care about. They only have meaning
335 // relative to each other, which means centralizing them here makes it a lot
336 // more manageable.
337 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
338
339 // Builtin LED.
340 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 1;
341 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
342 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
343
344 // Set up the CAN pins.
345 PORTA_PCR12 = PORT_PCR_DSE | PORT_PCR_MUX(2);
346 PORTA_PCR13 = PORT_PCR_DSE | PORT_PCR_MUX(2);
347
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700348 // PWM_IN0
349 // FTM0_CH0
350 PORTC_PCR1 = PORT_PCR_MUX(4);
351
352 // PWM_IN1
353 // FTM0_CH6
354 PORTD_PCR6 = PORT_PCR_MUX(4);
355
356 // PWM_IN2
357 // FTM0_CH4
358 PORTD_PCR4 = PORT_PCR_MUX(4);
359
360 // PWM_IN3
361 // FTM3_CH2
362 PORTD_PCR2 = PORT_PCR_MUX(4);
363
364 // PWM_IN4
365 // FTM0_CH2
366 PORTC_PCR3 = PORT_PCR_MUX(4);
367
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700368 delay(100);
369
370 teensy::UsbDevice usb_device(0, 0x16c0, 0x0492);
371 usb_device.SetManufacturer("Seems Reasonable LLC");
372 usb_device.SetProduct("Simple Receiver Board");
373
374 teensy::AcmTty tty0(&usb_device);
375 global_stdout.store(&tty0, ::std::memory_order_release);
376 usb_device.Initialize();
377
378 can_init(0, 1);
379 salsa::AdcInitJoystick();
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700380 SetupPwmFtm(FTM0);
381 SetupPwmFtm(FTM3);
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700382
383 // Leave the LEDs on for a bit longer.
384 delay(300);
385 printf("Done starting up\n");
386
387 // Done starting up, now turn the LED off.
388 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = 0;
389
Brian Silverman4f8c6a72018-03-17 23:12:45 -0700390 DoReceiverTest2();
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700391
392 return 0;
393}
394
395void __stack_chk_fail(void) {
396 while (true) {
397 GPIOC_PSOR = (1 << 5);
398 printf("Stack corruption detected\n");
399 delay(1000);
400 GPIOC_PCOR = (1 << 5);
401 delay(1000);
402 }
403}
404
405} // namespace motors
406} // namespace frc971