blob: 7fd7b15567ac7b4e61a451d0a108c945f7ab5f11 [file] [log] [blame]
Brian Silverman3240e102019-02-16 18:24:24 -08001#include "aos/time/time.h"
2#include "motors/core/kinetis.h"
3#include "motors/core/time.h"
4#include "motors/peripheral/configuration.h"
Brian Silvermand7d01102019-02-24 16:11:21 -08005#include "motors/peripheral/spi.h"
Brian Silverman3240e102019-02-16 18:24:24 -08006#include "motors/peripheral/uart.h"
7#include "motors/print/print.h"
8#include "motors/util.h"
Brian Silvermand7d01102019-02-24 16:11:21 -08009#include "third_party/GSL/include/gsl/gsl"
10#include "y2019/jevois/cobs.h"
11#include "y2019/jevois/spi.h"
12#include "y2019/jevois/uart.h"
13
14using frc971::teensy::InterruptBufferedUart;
15using frc971::teensy::InterruptBufferedSpi;
16
17// All indices here refer to the ports as numbered on the PCB.
Brian Silverman3240e102019-02-16 18:24:24 -080018
19namespace frc971 {
20namespace jevois {
21namespace {
22
Brian Silvermand7d01102019-02-24 16:11:21 -080023// Holds all of our hardware UARTs. There is exactly one global instance for
24// interrupt handlers to access.
Brian Silverman3240e102019-02-16 18:24:24 -080025struct Uarts {
26 Uarts() {
27 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080028 global_instance = this;
Brian Silverman3240e102019-02-16 18:24:24 -080029 }
30 ~Uarts() {
31 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080032 global_instance = nullptr;
Brian Silverman3240e102019-02-16 18:24:24 -080033 }
Brian Silvermand7d01102019-02-24 16:11:21 -080034 Uarts(const Uarts &) = delete;
35 Uarts &operator=(const Uarts &) = delete;
Brian Silverman3240e102019-02-16 18:24:24 -080036
37 void Initialize(int baud_rate) {
38 cam0.Initialize(baud_rate);
39 cam1.Initialize(baud_rate);
40 cam2.Initialize(baud_rate);
41 cam3.Initialize(baud_rate);
42 cam4.Initialize(baud_rate);
43 }
44
Brian Silvermand7d01102019-02-24 16:11:21 -080045 InterruptBufferedUart cam0{&UART1, F_CPU};
46 InterruptBufferedUart cam1{&UART0, F_CPU};
47 InterruptBufferedUart cam2{&UART2, BUS_CLOCK_FREQUENCY};
48 InterruptBufferedUart cam3{&UART3, BUS_CLOCK_FREQUENCY};
49 InterruptBufferedUart cam4{&UART4, BUS_CLOCK_FREQUENCY};
Brian Silverman3240e102019-02-16 18:24:24 -080050
Brian Silvermand7d01102019-02-24 16:11:21 -080051 static Uarts *global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -080052};
53
Brian Silvermand7d01102019-02-24 16:11:21 -080054Uarts *Uarts::global_instance = nullptr;
55
56// Manages the transmit buffer to a single camera.
57//
58// We have to add delays between sending each byte in order for the camera to
59// successfully receive them.
60struct TransmitBuffer {
61 TransmitBuffer(InterruptBufferedUart *camera_in) : camera(camera_in) {}
62 InterruptBufferedUart *const camera;
63
64 frc971::teensy::UartBuffer<1024> buffer;
65 aos::monotonic_clock::time_point last_send = aos::monotonic_clock::min_time;
66
67 // Sends a byte to the camera if it's time.
68 void Tick(aos::monotonic_clock::time_point now) {
69 if (buffer.empty()) {
70 return;
71 }
72 if (now < last_send + std::chrono::milliseconds(1)) {
73 return;
74 }
75 last_send = now;
76 camera->Write(std::array<char, 1>{{buffer.PopSingle()}});
77 }
78
79 // Queues up another packet to send, only if the previous one has finished.
80 void MaybeWritePacket(const CameraCalibration &calibration) {
81 if (!buffer.empty()) {
82 return;
83 }
84 const auto serialized = UartPackToCamera(calibration);
85 buffer.PushSingle(0);
86 if (buffer.PushSpan(serialized) == static_cast<int>(serialized.size())) {
87 buffer.PushSingle(0);
88 }
89 }
Brian Silvermanbac77542019-03-03 13:57:00 -080090
91 void FillAs() {
92 while (!buffer.full()) {
93 buffer.PushSingle('a');
94 }
95 }
Brian Silvermand7d01102019-02-24 16:11:21 -080096};
97
98InterruptBufferedSpi *global_spi_instance = nullptr;
99
100// Manages queueing a transfer to send via SPI.
101class SpiQueue {
102 public:
103 SpiQueue() {
104 DisableInterrupts disable_interrupts;
105 global_instance = this;
106 }
107 ~SpiQueue() {
108 DisableInterrupts disable_interrupts;
109 global_instance = nullptr;
110 }
111 SpiQueue(const SpiQueue &) = delete;
112 SpiQueue &operator=(const SpiQueue &) = delete;
113
114 tl::optional<gsl::span<const char, spi_transfer_size()>> Tick() {
115 {
116 DisableInterrupts disable_interrupts;
117 if (waiting_for_enable_ || waiting_for_disable_) {
118 return tl::nullopt;
119 }
120 }
121 const auto now = aos::monotonic_clock::now();
122 if (TransferTimedOut(now)) {
123 printf("SPI timeout with %d left\n", static_cast<int>(to_receive_.size()));
124 WaitForNextTransfer();
125 return tl::nullopt;
126 }
127 {
128 DisableInterrupts disable_interrupts;
129 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17) &&
130 cs_deassert_time_ == aos::monotonic_clock::max_time) {
131 cs_deassert_time_ = now;
132 }
133 }
134 if (DeassertHappened(now)) {
135 printf("CS deasserted with %d left\n", static_cast<int>(to_receive_.size()));
136 WaitForNextTransfer();
137 return tl::nullopt;
138 }
139 bool all_done;
140 {
141 DisableInterrupts disable_interrupts;
142 if (received_dummy_) {
143 to_receive_ = to_receive_.subspan(
144 global_spi_instance->Read(to_receive_, &disable_interrupts).size());
145 all_done = to_receive_.empty();
146 } else {
147 std::array<char, 1> dummy_data;
148 if (global_spi_instance->Read(dummy_data, &disable_interrupts).size() >=
149 1) {
150 received_dummy_ = true;
151 }
152 all_done = false;
153 }
154 }
155 if (all_done) {
156 WaitForNextTransfer();
157 return received_transfer_;
158 }
159 return tl::nullopt;
160 }
161
162 void HandleInterrupt() {
163 DisableInterrupts disable_interrupts;
164 if (waiting_for_disable_) {
165 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
166 PORTA_PCR17 =
167 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
168 // Clear the interrupt flag now that we've reconfigured it.
169 PORTA_ISFR = 1 << 17;
170 waiting_for_disable_ = false;
171 } else {
172 // Clear the interrupt flag. It shouldn't trigger again immediately
173 // because the pin is still asserted.
174 PORTA_ISFR = 1 << 17;
175 }
176 return;
177 }
178 if (waiting_for_enable_) {
179 if (PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
180 global_spi_instance->ClearQueues(disable_interrupts);
181 // Tell the SPI peripheral its CS is asserted.
182 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 0;
183 // Disable interrupts on the enable pin. We'll re-enable once we finish
184 // the transfer.
185 PORTA_PCR17 = PORT_PCR_MUX(1);
186 // Clear the interrupt flag now that we've reconfigured it.
187 PORTA_ISFR = 1 << 17;
188 if (have_transfer_) {
189 global_spi_instance->Write(transfer_, &disable_interrupts);
190 have_transfer_ = false;
191 } else {
192 printf("Writing dummy SPI frame\n");
193 // If we don't have anything, just write 0s to avoid getting the
194 // hardware confused.
195 global_spi_instance->Write(SpiTransfer{}, &disable_interrupts);
196 }
197 // Queue up a dummy byte at the end. This won't actually be sent,
198 // because the first byte we do send will be garbage, but it will
199 // synchronize our queues so we receive all the useful data bytes.
200 global_spi_instance->Write(std::array<char, 1>(), &disable_interrupts);
201 waiting_for_enable_ = false;
202 receive_start_ = aos::monotonic_clock::now();
203 cs_deassert_time_ = aos::monotonic_clock::max_time;
204 // To make debugging easier.
205 received_transfer_.fill(0);
206 } else {
207 // Clear the interrupt flag. It shouldn't trigger again immediately
208 // because the pin is still asserted.
209 PORTA_ISFR = 1 << 17;
210 }
211 return;
212 }
213 // We shouldn't ever get here. Clear all the flags and hope they don't get
214 // re-asserted immediately.
215 PORTA_ISFR = UINT32_C(0xFFFFFFFF);
216 }
217
218 void UpdateTransfer(const SpiTransfer &transfer, const DisableInterrupts &) {
219 have_transfer_ = true;
220 transfer_ = transfer;
221 }
222
223 // Returns whether a transfer is currently queued. This will be true between a
224 // call to UpdateTransfer and that transfer actually being moved out to the
225 // hardware.
226 bool HaveTransfer(const DisableInterrupts &) const { return have_transfer_; }
227
228 static SpiQueue *global_instance;
229
230 private:
231 void WaitForNextTransfer() {
232 to_receive_ = received_transfer_;
233 received_dummy_ = false;
234 {
235 DisableInterrupts disable_interrupts;
236 waiting_for_enable_ = true;
237 waiting_for_disable_ = true;
238 PORTA_PCR17 =
239 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0x8) /* Interrupt when logic 0 */;
240 // Clear the interrupt flag now that we've reconfigured it.
241 PORTA_ISFR = 1 << 17;
242 }
243 // Tell the SPI peripheral its CS is de-asserted.
244 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
245 }
246
247 bool TransferTimedOut(aos::monotonic_clock::time_point now) {
248 DisableInterrupts disable_interrupts;
249 // TODO: Revise this timeout.
250 return now - std::chrono::milliseconds(50) > receive_start_;
251 }
252
253 bool DeassertHappened(aos::monotonic_clock::time_point now) {
254 DisableInterrupts disable_interrupts;
255 return now - std::chrono::microseconds(50) > cs_deassert_time_;
256 }
257
258 bool waiting_for_enable_ = true;
259 bool waiting_for_disable_ = false;
260 bool have_transfer_ = false;
261 SpiTransfer transfer_;
262 bool received_dummy_ = false;
263 SpiTransfer received_transfer_;
264 gsl::span<char> to_receive_ = received_transfer_;
265 aos::monotonic_clock::time_point receive_start_;
266 aos::monotonic_clock::time_point cs_deassert_time_;
267};
268
269SpiQueue *SpiQueue::global_instance = nullptr;
270
271// All methods here must be fully synchronized by the caller.
272class FrameQueue {
273 public:
274 FrameQueue() = default;
275 FrameQueue(const FrameQueue &) = delete;
276 FrameQueue &operator=(const FrameQueue &) = delete;
277
Brian Silvermanc41fb862019-03-02 21:14:46 -0800278 void UpdateFrame(int camera, const CameraFrame &frame) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800279 frames_[camera].targets = frame.targets;
280 frames_[camera].capture_time = aos::monotonic_clock::now() - frame.age;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800281 frames_[camera].camera_index = camera;
Brian Silvermand7d01102019-02-24 16:11:21 -0800282 const aos::SizedArray<int, 3> old_last_frames = last_frames_;
283 last_frames_.clear();
284 for (int index : old_last_frames) {
285 if (index != camera) {
286 last_frames_.push_back(index);
287 }
288 }
289 }
290
291 // Creates and returns a transfer with all the current information.
292 //
293 // This does not actually record these frames as transferred until
294 // RemoveLatestFrames() is called.
295 SpiTransfer MakeTransfer();
296
297 // Records the frames represented in the result of the latest MakeTransfer()
298 // call as being transferred, so they will not be represented in subsequent
299 // MakeTransfer() calls.
300 void RemoveLatestFrames() {
301 for (int index : last_frames_) {
302 frames_[index].capture_time = aos::monotonic_clock::min_time;
303 }
304 last_frames_.clear();
305 }
306
307 private:
308 struct FrameData {
309 aos::SizedArray<Target, 3> targets;
310 aos::monotonic_clock::time_point capture_time =
311 aos::monotonic_clock::min_time;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800312 int camera_index;
Brian Silvermand7d01102019-02-24 16:11:21 -0800313 };
314
315 std::array<FrameData, 5> frames_;
316 // The indices into frames_ which we returned in the last MakeTransfer() call.
317 aos::SizedArray<int, 3> last_frames_;
318};
319
320SpiTransfer FrameQueue::MakeTransfer() {
321 aos::SizedArray<int, 5> oldest_indices;
322 for (size_t i = 0; i < frames_.size(); ++i) {
323 if (frames_[i].capture_time != aos::monotonic_clock::min_time) {
324 oldest_indices.push_back(i);
325 }
326 }
327 std::sort(oldest_indices.begin(), oldest_indices.end(), [this](int a, int b) {
328 return frames_[a].capture_time < frames_[b].capture_time;
329 });
330
331 TeensyToRoborio message;
332 last_frames_.clear();
333 for (int i = 0; i < std::min<int>(oldest_indices.size(), 3); ++i) {
334 const int index = oldest_indices[i];
335 const FrameData &frame = frames_[index];
336 const auto age = aos::monotonic_clock::now() - frame.capture_time;
337 const auto rounded_age = aos::time::round<camera_duration>(age);
Brian Silvermanc41fb862019-03-02 21:14:46 -0800338 message.frames.push_back({frame.targets, rounded_age, frame.camera_index});
Brian Silvermand7d01102019-02-24 16:11:21 -0800339 last_frames_.push_back(index);
340 }
341 return SpiPackToRoborio(message);
342}
Brian Silverman3240e102019-02-16 18:24:24 -0800343
Brian Silverman2294f352019-03-02 16:31:18 -0800344// Manages turning the debug light on and off periodically.
345//
346// It blinks at 1Hz with a variable duty cycle.
347class DebugLight {
348 public:
349 static constexpr aos::monotonic_clock::duration period() {
350 return std::chrono::seconds(1);
351 }
352
353 void set_next_off_time(aos::monotonic_clock::duration next_off_time) {
354 next_off_time_ = next_off_time;
355 }
356
357 void Tick() {
358 const auto now = aos::monotonic_clock::now();
359 if (last_cycle_start_ == aos::monotonic_clock::min_time) {
360 last_cycle_start_ = now;
361 current_off_point_ = last_cycle_start_ + next_off_time_;
362 } else if (now > last_cycle_start_ + period()) {
363 last_cycle_start_ += period();
364 current_off_point_ = last_cycle_start_ + next_off_time_;
365 }
366 if (now > current_off_point_) {
367 GPIOC_PCOR = 1 << 5;
368 } else {
369 GPIOC_PSOR = 1 << 5;
370 }
371 }
372
373 private:
374 aos::monotonic_clock::time_point last_cycle_start_ =
375 aos::monotonic_clock::min_time;
376
Brian Silvermanbac77542019-03-03 13:57:00 -0800377 aos::monotonic_clock::duration next_off_time_ =
378 std::chrono::milliseconds(100);
Brian Silverman2294f352019-03-02 16:31:18 -0800379 aos::monotonic_clock::time_point current_off_point_ =
380 aos::monotonic_clock::min_time;
381};
382
Brian Silverman3240e102019-02-16 18:24:24 -0800383extern "C" {
384
385void *__stack_chk_guard = (void *)0x67111971;
386void __stack_chk_fail(void) {
387 while (true) {
388 GPIOC_PSOR = (1 << 5);
389 printf("Stack corruption detected\n");
390 delay(1000);
391 GPIOC_PCOR = (1 << 5);
392 delay(1000);
393 }
394}
395
396extern char *__brkval;
397extern uint32_t __bss_ram_start__[];
398extern uint32_t __heap_start__[];
399extern uint32_t __stack_end__[];
400
401void uart0_status_isr(void) {
402 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800403 Uarts::global_instance->cam1.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800404}
405
406void uart1_status_isr(void) {
407 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800408 Uarts::global_instance->cam0.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800409}
410
411void uart2_status_isr(void) {
412 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800413 Uarts::global_instance->cam2.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800414}
415
416void uart3_status_isr(void) {
417 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800418 Uarts::global_instance->cam3.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800419}
420
421void uart4_status_isr(void) {
422 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800423 Uarts::global_instance->cam4.HandleInterrupt(disable_interrupts);
424}
425
426void spi0_isr(void) {
427 DisableInterrupts disable_interrupts;
428 global_spi_instance->HandleInterrupt(disable_interrupts);
429}
430
431void porta_isr(void) {
432 SpiQueue::global_instance->HandleInterrupt();
Brian Silverman3240e102019-02-16 18:24:24 -0800433}
434
435} // extern "C"
436
437// A test program which echos characters back after adding a per-UART offset to
438// them (CAM0 adds 1, CAM1 adds 2, etc).
439__attribute__((unused)) void TestUarts() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800440 Uarts *const uarts = Uarts::global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -0800441 while (true) {
442 {
443 std::array<char, 10> buffer;
444 const auto data = uarts->cam0.Read(buffer);
445 for (int i = 0; i < data.size(); ++i) {
446 data[i] += 1;
447 }
448 uarts->cam0.Write(data);
449 }
450 {
451 std::array<char, 10> buffer;
452 const auto data = uarts->cam1.Read(buffer);
453 for (int i = 0; i < data.size(); ++i) {
454 data[i] += 2;
455 }
456 uarts->cam1.Write(data);
457 }
458 {
459 std::array<char, 10> buffer;
460 const auto data = uarts->cam2.Read(buffer);
461 for (int i = 0; i < data.size(); ++i) {
462 data[i] += 3;
463 }
464 uarts->cam2.Write(data);
465 }
466 {
467 std::array<char, 10> buffer;
468 const auto data = uarts->cam3.Read(buffer);
469 for (int i = 0; i < data.size(); ++i) {
470 data[i] += 4;
471 }
472 uarts->cam3.Write(data);
473 }
474 {
475 std::array<char, 10> buffer;
476 const auto data = uarts->cam4.Read(buffer);
477 for (int i = 0; i < data.size(); ++i) {
478 data[i] += 5;
479 }
480 uarts->cam4.Write(data);
481 }
482 }
483}
484
485// Tests all the I/O pins. Cycles through each one for 1 second. While active,
486// each output is turned on, and each input has its value printed.
487__attribute__((unused)) void TestIo() {
488 // Set SPI0 pins to GPIO.
489 // SPI_OUT
490 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
491 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1);
492 // SPI_CS
493 PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0;
494 PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
495 // SPI_IN
496 PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0;
497 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
498 // SPI_SCK
499 PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0;
500 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
501
502 // Set LED pins to GPIO.
503 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
504 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1);
505 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
506 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1);
507 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
508 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1);
509 PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1;
510 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1);
511 PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1;
512 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1);
513 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
514 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
515 PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1;
516 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
517 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
518 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
519 PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1;
520 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1);
521 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
522 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
523
524 auto next = aos::monotonic_clock::now();
525 static constexpr auto kTick = std::chrono::seconds(1);
526 while (true) {
527 printf("SPI_MISO\n");
528 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
529 while (aos::monotonic_clock::now() < next + kTick) {
530 }
531 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
532 next += kTick;
533
534 while (aos::monotonic_clock::now() < next + kTick) {
535 printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0));
536 }
537 next += kTick;
538
539 while (aos::monotonic_clock::now() < next + kTick) {
540 printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7));
541 }
542 next += kTick;
543
544 while (aos::monotonic_clock::now() < next + kTick) {
545 printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1));
546 }
547 next += kTick;
548
549 printf("CAM0\n");
550 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
551 while (aos::monotonic_clock::now() < next + kTick) {
552 }
553 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
554 next += kTick;
555
556 printf("CAM1\n");
557 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
558 while (aos::monotonic_clock::now() < next + kTick) {
559 }
560 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
561 next += kTick;
562
563 printf("CAM2\n");
564 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
565 while (aos::monotonic_clock::now() < next + kTick) {
566 }
567 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0;
568 next += kTick;
569
570 printf("CAM3\n");
571 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1;
572 while (aos::monotonic_clock::now() < next + kTick) {
573 }
574 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0;
575 next += kTick;
576
577 printf("CAM4\n");
578 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1;
579 while (aos::monotonic_clock::now() < next + kTick) {
580 }
581 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0;
582 next += kTick;
583
584 printf("CAM5\n");
585 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1;
586 while (aos::monotonic_clock::now() < next + kTick) {
587 }
588 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0;
589 next += kTick;
590
591 printf("CAM6\n");
592 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1;
593 while (aos::monotonic_clock::now() < next + kTick) {
594 }
595 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0;
596 next += kTick;
597
598 printf("CAM7\n");
599 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1;
600 while (aos::monotonic_clock::now() < next + kTick) {
601 }
602 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0;
603 next += kTick;
604
605 printf("CAM8\n");
606 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1;
607 while (aos::monotonic_clock::now() < next + kTick) {
608 }
609 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0;
610 next += kTick;
611
612 printf("CAM9\n");
613 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1;
614 while (aos::monotonic_clock::now() < next + kTick) {
615 }
616 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0;
617 next += kTick;
618 }
619}
620
Brian Silvermand7d01102019-02-24 16:11:21 -0800621// Does the normal work of transferring data in all directions.
622//
623// https://community.nxp.com/thread/466937#comment-983881 is a post from NXP
624// claiming that it's impossible to queue up the first byte for the slave end of
625// an SPI connection properly. Instead, we just accept there will be a garbage
626// byte and the other end ignores it.
Brian Silverman83693e42019-03-02 15:45:52 -0800627__attribute__((unused)) void TransferData(
628 frc971::motors::PrintingImplementation *printing) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800629 Uarts *const uarts = Uarts::global_instance;
630 std::array<CobsPacketizer<uart_to_teensy_size()>, 5> packetizers;
631 std::array<TransmitBuffer, 5> transmit_buffers{
632 {&uarts->cam0, &uarts->cam1, &uarts->cam2, &uarts->cam3, &uarts->cam4}};
633 FrameQueue frame_queue;
634 aos::monotonic_clock::time_point last_camera_send =
635 aos::monotonic_clock::min_time;
Brian Silverman83693e42019-03-02 15:45:52 -0800636 CameraCommand stdin_camera_command = CameraCommand::kNormal;
637 CameraCommand last_roborio_camera_command = CameraCommand::kNormal;
Brian Silverman2294f352019-03-02 16:31:18 -0800638 DebugLight debug_light;
Brian Silverman83693e42019-03-02 15:45:52 -0800639
Brian Silvermand7d01102019-02-24 16:11:21 -0800640 bool first = true;
641 while (true) {
Brian Silverman2294f352019-03-02 16:31:18 -0800642 debug_light.Tick();
643
Brian Silvermand7d01102019-02-24 16:11:21 -0800644 {
645 const auto received_transfer = SpiQueue::global_instance->Tick();
646 if (received_transfer) {
647 const auto unpacked = SpiUnpackToTeensy(*received_transfer);
Brian Silverman83693e42019-03-02 15:45:52 -0800648 if (unpacked) {
649 last_roborio_camera_command = unpacked->camera_command;
650 } else {
Brian Silvermand7d01102019-02-24 16:11:21 -0800651 printf("UART decode error\n");
652 }
653 }
654 }
655
656 {
657 std::array<char, 20> buffer;
658 packetizers[0].ParseData(uarts->cam0.Read(buffer));
659 packetizers[1].ParseData(uarts->cam1.Read(buffer));
660 packetizers[2].ParseData(uarts->cam2.Read(buffer));
661 packetizers[3].ParseData(uarts->cam3.Read(buffer));
662 packetizers[4].ParseData(uarts->cam4.Read(buffer));
663 }
664 for (size_t i = 0; i < packetizers.size(); ++i) {
665 if (!packetizers[i].received_packet().empty()) {
666 const auto decoded =
667 UartUnpackToTeensy(packetizers[i].received_packet());
668 packetizers[i].clear_received_packet();
669 if (decoded) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800670 frame_queue.UpdateFrame(i, *decoded);
671 }
672 }
673 }
674 {
675 bool made_transfer = false;
676 if (!first) {
677 DisableInterrupts disable_interrupts;
678 made_transfer =
679 !SpiQueue::global_instance->HaveTransfer(disable_interrupts);
680 }
681 if (made_transfer) {
682 frame_queue.RemoveLatestFrames();
683 }
684 const auto transfer = frame_queue.MakeTransfer();
685 {
686 DisableInterrupts disable_interrupts;
687 SpiQueue::global_instance->UpdateTransfer(transfer, disable_interrupts);
688 }
689 }
690 {
691 const auto now = aos::monotonic_clock::now();
Brian Silvermanbac77542019-03-03 13:57:00 -0800692 CameraCommand current_camera_command = CameraCommand::kNormal;
693 if (last_roborio_camera_command != CameraCommand::kNormal) {
694 current_camera_command = last_roborio_camera_command;
695 } else {
696 current_camera_command = stdin_camera_command;
697 }
698 if (current_camera_command == CameraCommand::kUsb) {
699 debug_light.set_next_off_time(std::chrono::milliseconds(900));
700 } else if (current_camera_command == CameraCommand::kCameraPassthrough) {
701 debug_light.set_next_off_time(std::chrono::milliseconds(500));
702 } else {
703 debug_light.set_next_off_time(std::chrono::milliseconds(100));
704 }
705
706 if (current_camera_command == CameraCommand::kAs) {
707 for (size_t i = 0; i < transmit_buffers.size(); ++i) {
708 transmit_buffers[i].FillAs();
Brian Silverman83693e42019-03-02 15:45:52 -0800709 }
Brian Silvermanbac77542019-03-03 13:57:00 -0800710 } else {
711 if (last_camera_send + std::chrono::milliseconds(1000) < now) {
712 last_camera_send = now;
713 CameraCalibration calibration{};
714 calibration.teensy_now = aos::monotonic_clock::now();
715 calibration.realtime_now = aos::realtime_clock::min_time;
716 calibration.camera_command = current_camera_command;
717 // TODO(Brian): Actually fill out the calibration field.
718 transmit_buffers[0].MaybeWritePacket(calibration);
719 transmit_buffers[1].MaybeWritePacket(calibration);
720 transmit_buffers[2].MaybeWritePacket(calibration);
721 transmit_buffers[3].MaybeWritePacket(calibration);
722 transmit_buffers[4].MaybeWritePacket(calibration);
Brian Silverman2294f352019-03-02 16:31:18 -0800723 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800724 }
725 for (TransmitBuffer &transmit_buffer : transmit_buffers) {
726 transmit_buffer.Tick(now);
727 }
728 }
729
Brian Silverman83693e42019-03-02 15:45:52 -0800730 {
731 const auto stdin_data = printing->ReadStdin();
732 if (!stdin_data.empty()) {
733 switch (stdin_data.back()) {
734 case 'p':
735 printf("Entering passthrough mode\n");
736 stdin_camera_command = CameraCommand::kCameraPassthrough;
737 break;
738 case 'u':
739 printf("Entering USB mode\n");
740 stdin_camera_command = CameraCommand::kUsb;
741 break;
742 case 'n':
743 printf("Entering normal mode\n");
744 stdin_camera_command = CameraCommand::kNormal;
745 break;
Brian Silvermanbac77542019-03-03 13:57:00 -0800746 case 'a':
747 printf("Entering all-A mode\n");
748 stdin_camera_command = CameraCommand::kAs;
749 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800750 default:
751 printf("Unrecognized character\n");
752 break;
753 }
754 }
755 }
756
Brian Silvermand7d01102019-02-24 16:11:21 -0800757 first = false;
758 }
759}
760
Brian Silverman3240e102019-02-16 18:24:24 -0800761int Main() {
762 // for background about this startup delay, please see these conversations
763 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
764 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
765 delay(400);
766
767 // Set all interrupts to the second-lowest priority to start with.
768 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
769
770 // Now set priorities for all the ones we care about. They only have meaning
771 // relative to each other, which means centralizing them here makes it a lot
772 // more manageable.
Brian Silvermand7d01102019-02-24 16:11:21 -0800773 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
774 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0x3);
775 NVIC_SET_SANE_PRIORITY(IRQ_UART1_STATUS, 0x3);
776 NVIC_SET_SANE_PRIORITY(IRQ_UART2_STATUS, 0x3);
777 NVIC_SET_SANE_PRIORITY(IRQ_UART3_STATUS, 0x3);
778 NVIC_SET_SANE_PRIORITY(IRQ_UART4_STATUS, 0x3);
779 // This one is relatively sensitive to latencies. The buffer is ~4800 clock
780 // cycles long.
781 NVIC_SET_SANE_PRIORITY(IRQ_SPI0, 0x2);
782 NVIC_SET_SANE_PRIORITY(IRQ_PORTA, 0x3);
Brian Silverman3240e102019-02-16 18:24:24 -0800783
784 // Set the LED's pin to output mode.
785 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
786 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
787
788 frc971::motors::PrintingParameters printing_parameters;
789 printing_parameters.dedicated_usb = true;
790 const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing =
791 CreatePrinting(printing_parameters);
792 printing->Initialize();
793
794 DMA.CR = M_DMA_EMLM;
795
Brian Silvermand7d01102019-02-24 16:11:21 -0800796 SIM_SCGC1 |= SIM_SCGC1_UART4;
Brian Silverman3240e102019-02-16 18:24:24 -0800797 SIM_SCGC4 |=
798 SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3;
Brian Silvermand7d01102019-02-24 16:11:21 -0800799 SIM_SCGC6 |= SIM_SCGC6_SPI0;
Brian Silverman3240e102019-02-16 18:24:24 -0800800
801 // SPI0 goes to the roboRIO.
802 // SPI0_PCS0 is SPI_CS.
Brian Silvermand7d01102019-02-24 16:11:21 -0800803 PORTD_PCR0 = PORT_PCR_MUX(2);
Brian Silverman3240e102019-02-16 18:24:24 -0800804 // SPI0_SOUT is SPI_MISO.
805 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
806 // SPI0_SIN is SPI_MOSI.
807 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2);
808 // SPI0_SCK is SPI_CLK.
809 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2);
Brian Silvermand7d01102019-02-24 16:11:21 -0800810 // SPI_CS_DRIVE
811 PERIPHERAL_BITBAND(GPIOB_PDDR, 17) = 1;
812 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
813 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(1);
814 // SPI_CS_IN
815 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 0;
816 // Set the filter width.
817 PORTA_DFWR = 31;
818 // Enable the filter.
819 PERIPHERAL_BITBAND(PORTA_DFER, 17) = 1;
820 PORTA_PCR17 =
821 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
822 // Clear the interrupt flag now that we've reconfigured it.
823 PORTA_ISFR = 1 << 17;
Brian Silverman3240e102019-02-16 18:24:24 -0800824
825 // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel).
826 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
827 // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel).
828 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
829 // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel).
830 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4);
831 // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera).
832 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
833
834 // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera).
835 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3);
836 // FTM2_CH0 is LED5 (for CAM4).
837 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3);
838
839 // FTM3_CH4 is LED6 (for CAM2).
840 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3);
841 // FTM3_CH5 is LED7 (for CAM3).
842 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3);
843 // FTM3_CH6 is LED8 (for CAM1).
844 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3);
845 // FTM3_CH7 is LED9 (for CAM0).
846 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
847
848 // This hardware has been deactivated, but keep this comment for now to
849 // document which pins it is on.
850#if 0
851 // This is ODROID_EN.
852 PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1;
853 PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0;
854 PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
855 // This is CAM_EN.
856 PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1;
857 PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0;
858 PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
859#endif
860 // This is 5V_PGOOD.
861 PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0;
862 PORTD_PCR6 = PORT_PCR_MUX(1);
863
864 // These go to CAM1.
865 // UART0_RX (peripheral) is UART1_RX (schematic).
Brian Silvermand7d01102019-02-24 16:11:21 -0800866 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
867 0 /* !PS to pull down */;
Brian Silverman3240e102019-02-16 18:24:24 -0800868 // UART0_TX (peripheral) is UART1_TX (schematic).
869 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3);
870
871 // These go to CAM0.
872 // UART1_RX (peripheral) is UART0_RX (schematic).
Brian Silvermand7d01102019-02-24 16:11:21 -0800873 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
874 0 /* !PS to pull down */;
Brian Silverman3240e102019-02-16 18:24:24 -0800875 // UART1_TX (peripheral) is UART0_TX (schematic).
876 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3);
877
878 // These go to CAM2.
879 // UART2_RX
Brian Silvermand7d01102019-02-24 16:11:21 -0800880 PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
881 0 /* !PS to pull down */;
Brian Silverman3240e102019-02-16 18:24:24 -0800882 // UART2_TX
883 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3);
884
885 // These go to CAM3.
886 // UART3_RX
Brian Silvermand7d01102019-02-24 16:11:21 -0800887 PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
888 0 /* !PS to pull down */;
Brian Silverman3240e102019-02-16 18:24:24 -0800889 // UART3_TX
890 PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
891
892 // These go to CAM4.
893 // UART4_RX
Brian Silvermand7d01102019-02-24 16:11:21 -0800894 PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
895 0 /* !PS to pull down */;
Brian Silverman3240e102019-02-16 18:24:24 -0800896 // UART4_TX
897 PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3);
898
899 Uarts uarts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800900 InterruptBufferedSpi spi0{&SPI0, BUS_CLOCK_FREQUENCY};
901 global_spi_instance = &spi0;
902 SpiQueue spi_queue;
Brian Silverman3240e102019-02-16 18:24:24 -0800903
904 // Give everything a chance to get going.
905 delay(100);
906
907 printf("Ram start: %p\n", __bss_ram_start__);
908 printf("Heap start: %p\n", __heap_start__);
909 printf("Heap end: %p\n", __brkval);
910 printf("Stack start: %p\n", __stack_end__);
911
912 uarts.Initialize(115200);
913 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
914 NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
915 NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
916 NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
917 NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
Brian Silvermand7d01102019-02-24 16:11:21 -0800918 spi0.Initialize();
919 NVIC_ENABLE_IRQ(IRQ_SPI0);
920 NVIC_ENABLE_IRQ(IRQ_PORTA);
921
Brian Silverman83693e42019-03-02 15:45:52 -0800922 TransferData(printing.get());
Brian Silverman3240e102019-02-16 18:24:24 -0800923
924 while (true) {
925 }
926}
927
928extern "C" {
929
930int main(void) {
931 return Main();
932}
933
934} // extern "C"
935
936} // namespace
937} // namespace jevois
938} // namespace frc971