blob: 58d157073dabef440c2ee58c344a9d48875947ec [file] [log] [blame]
Brian Silvermana498bbb2019-03-03 17:18:04 -08001#include <inttypes.h>
2#include <stdio.h>
3
Brian Silverman3240e102019-02-16 18:24:24 -08004#include "aos/time/time.h"
5#include "motors/core/kinetis.h"
6#include "motors/core/time.h"
7#include "motors/peripheral/configuration.h"
Brian Silvermand7d01102019-02-24 16:11:21 -08008#include "motors/peripheral/spi.h"
Brian Silverman3240e102019-02-16 18:24:24 -08009#include "motors/peripheral/uart.h"
10#include "motors/print/print.h"
11#include "motors/util.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080012#include "third_party/GSL/include/gsl/gsl"
13#include "y2019/jevois/cobs.h"
14#include "y2019/jevois/spi.h"
15#include "y2019/jevois/uart.h"
Brian Silvermana498bbb2019-03-03 17:18:04 -080016#include "y2019/vision/constants.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080017
18using frc971::teensy::InterruptBufferedUart;
19using frc971::teensy::InterruptBufferedSpi;
20
21// All indices here refer to the ports as numbered on the PCB.
Brian Silverman3240e102019-02-16 18:24:24 -080022
23namespace frc971 {
24namespace jevois {
25namespace {
26
Brian Silvermand7d01102019-02-24 16:11:21 -080027// Holds all of our hardware UARTs. There is exactly one global instance for
28// interrupt handlers to access.
Brian Silverman3240e102019-02-16 18:24:24 -080029struct Uarts {
30 Uarts() {
31 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080032 global_instance = this;
Brian Silverman3240e102019-02-16 18:24:24 -080033 }
34 ~Uarts() {
35 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080036 global_instance = nullptr;
Brian Silverman3240e102019-02-16 18:24:24 -080037 }
Brian Silvermand7d01102019-02-24 16:11:21 -080038 Uarts(const Uarts &) = delete;
39 Uarts &operator=(const Uarts &) = delete;
Brian Silverman3240e102019-02-16 18:24:24 -080040
41 void Initialize(int baud_rate) {
42 cam0.Initialize(baud_rate);
43 cam1.Initialize(baud_rate);
44 cam2.Initialize(baud_rate);
45 cam3.Initialize(baud_rate);
46 cam4.Initialize(baud_rate);
47 }
48
Brian Silvermand7d01102019-02-24 16:11:21 -080049 InterruptBufferedUart cam0{&UART1, F_CPU};
50 InterruptBufferedUart cam1{&UART0, F_CPU};
51 InterruptBufferedUart cam2{&UART2, BUS_CLOCK_FREQUENCY};
52 InterruptBufferedUart cam3{&UART3, BUS_CLOCK_FREQUENCY};
53 InterruptBufferedUart cam4{&UART4, BUS_CLOCK_FREQUENCY};
Brian Silverman3240e102019-02-16 18:24:24 -080054
Brian Silvermand7d01102019-02-24 16:11:21 -080055 static Uarts *global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -080056};
57
Brian Silvermand7d01102019-02-24 16:11:21 -080058Uarts *Uarts::global_instance = nullptr;
59
60// Manages the transmit buffer to a single camera.
61//
62// We have to add delays between sending each byte in order for the camera to
63// successfully receive them.
64struct TransmitBuffer {
65 TransmitBuffer(InterruptBufferedUart *camera_in) : camera(camera_in) {}
66 InterruptBufferedUart *const camera;
67
68 frc971::teensy::UartBuffer<1024> buffer;
69 aos::monotonic_clock::time_point last_send = aos::monotonic_clock::min_time;
70
71 // Sends a byte to the camera if it's time.
72 void Tick(aos::monotonic_clock::time_point now) {
73 if (buffer.empty()) {
74 return;
75 }
76 if (now < last_send + std::chrono::milliseconds(1)) {
77 return;
78 }
79 last_send = now;
80 camera->Write(std::array<char, 1>{{buffer.PopSingle()}});
81 }
82
83 // Queues up another packet to send, only if the previous one has finished.
84 void MaybeWritePacket(const CameraCalibration &calibration) {
85 if (!buffer.empty()) {
86 return;
87 }
88 const auto serialized = UartPackToCamera(calibration);
89 buffer.PushSingle(0);
90 if (buffer.PushSpan(serialized) == static_cast<int>(serialized.size())) {
91 buffer.PushSingle(0);
92 }
93 }
Brian Silvermanbac77542019-03-03 13:57:00 -080094
95 void FillAs() {
96 while (!buffer.full()) {
97 buffer.PushSingle('a');
98 }
99 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800100};
101
102InterruptBufferedSpi *global_spi_instance = nullptr;
103
104// Manages queueing a transfer to send via SPI.
105class SpiQueue {
106 public:
107 SpiQueue() {
108 DisableInterrupts disable_interrupts;
109 global_instance = this;
110 }
111 ~SpiQueue() {
112 DisableInterrupts disable_interrupts;
113 global_instance = nullptr;
114 }
115 SpiQueue(const SpiQueue &) = delete;
116 SpiQueue &operator=(const SpiQueue &) = delete;
117
118 tl::optional<gsl::span<const char, spi_transfer_size()>> Tick() {
119 {
120 DisableInterrupts disable_interrupts;
121 if (waiting_for_enable_ || waiting_for_disable_) {
122 return tl::nullopt;
123 }
124 }
125 const auto now = aos::monotonic_clock::now();
126 if (TransferTimedOut(now)) {
127 printf("SPI timeout with %d left\n", static_cast<int>(to_receive_.size()));
128 WaitForNextTransfer();
129 return tl::nullopt;
130 }
131 {
132 DisableInterrupts disable_interrupts;
133 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17) &&
134 cs_deassert_time_ == aos::monotonic_clock::max_time) {
135 cs_deassert_time_ = now;
136 }
137 }
138 if (DeassertHappened(now)) {
139 printf("CS deasserted with %d left\n", static_cast<int>(to_receive_.size()));
140 WaitForNextTransfer();
141 return tl::nullopt;
142 }
143 bool all_done;
144 {
145 DisableInterrupts disable_interrupts;
146 if (received_dummy_) {
147 to_receive_ = to_receive_.subspan(
148 global_spi_instance->Read(to_receive_, &disable_interrupts).size());
149 all_done = to_receive_.empty();
150 } else {
151 std::array<char, 1> dummy_data;
152 if (global_spi_instance->Read(dummy_data, &disable_interrupts).size() >=
153 1) {
154 received_dummy_ = true;
155 }
156 all_done = false;
157 }
158 }
159 if (all_done) {
160 WaitForNextTransfer();
161 return received_transfer_;
162 }
163 return tl::nullopt;
164 }
165
166 void HandleInterrupt() {
167 DisableInterrupts disable_interrupts;
168 if (waiting_for_disable_) {
169 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
170 PORTA_PCR17 =
171 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
172 // Clear the interrupt flag now that we've reconfigured it.
173 PORTA_ISFR = 1 << 17;
174 waiting_for_disable_ = false;
175 } else {
176 // Clear the interrupt flag. It shouldn't trigger again immediately
177 // because the pin is still asserted.
178 PORTA_ISFR = 1 << 17;
179 }
180 return;
181 }
182 if (waiting_for_enable_) {
183 if (PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
184 global_spi_instance->ClearQueues(disable_interrupts);
185 // Tell the SPI peripheral its CS is asserted.
186 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 0;
187 // Disable interrupts on the enable pin. We'll re-enable once we finish
188 // the transfer.
189 PORTA_PCR17 = PORT_PCR_MUX(1);
190 // Clear the interrupt flag now that we've reconfigured it.
191 PORTA_ISFR = 1 << 17;
192 if (have_transfer_) {
193 global_spi_instance->Write(transfer_, &disable_interrupts);
194 have_transfer_ = false;
195 } else {
196 printf("Writing dummy SPI frame\n");
197 // If we don't have anything, just write 0s to avoid getting the
198 // hardware confused.
199 global_spi_instance->Write(SpiTransfer{}, &disable_interrupts);
200 }
201 // Queue up a dummy byte at the end. This won't actually be sent,
202 // because the first byte we do send will be garbage, but it will
203 // synchronize our queues so we receive all the useful data bytes.
204 global_spi_instance->Write(std::array<char, 1>(), &disable_interrupts);
205 waiting_for_enable_ = false;
206 receive_start_ = aos::monotonic_clock::now();
207 cs_deassert_time_ = aos::monotonic_clock::max_time;
208 // To make debugging easier.
209 received_transfer_.fill(0);
210 } else {
211 // Clear the interrupt flag. It shouldn't trigger again immediately
212 // because the pin is still asserted.
213 PORTA_ISFR = 1 << 17;
214 }
215 return;
216 }
217 // We shouldn't ever get here. Clear all the flags and hope they don't get
218 // re-asserted immediately.
219 PORTA_ISFR = UINT32_C(0xFFFFFFFF);
220 }
221
222 void UpdateTransfer(const SpiTransfer &transfer, const DisableInterrupts &) {
223 have_transfer_ = true;
224 transfer_ = transfer;
225 }
226
227 // Returns whether a transfer is currently queued. This will be true between a
228 // call to UpdateTransfer and that transfer actually being moved out to the
229 // hardware.
230 bool HaveTransfer(const DisableInterrupts &) const { return have_transfer_; }
231
232 static SpiQueue *global_instance;
233
234 private:
235 void WaitForNextTransfer() {
236 to_receive_ = received_transfer_;
237 received_dummy_ = false;
238 {
239 DisableInterrupts disable_interrupts;
240 waiting_for_enable_ = true;
241 waiting_for_disable_ = true;
242 PORTA_PCR17 =
243 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0x8) /* Interrupt when logic 0 */;
244 // Clear the interrupt flag now that we've reconfigured it.
245 PORTA_ISFR = 1 << 17;
246 }
247 // Tell the SPI peripheral its CS is de-asserted.
248 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
249 }
250
251 bool TransferTimedOut(aos::monotonic_clock::time_point now) {
252 DisableInterrupts disable_interrupts;
253 // TODO: Revise this timeout.
254 return now - std::chrono::milliseconds(50) > receive_start_;
255 }
256
257 bool DeassertHappened(aos::monotonic_clock::time_point now) {
258 DisableInterrupts disable_interrupts;
259 return now - std::chrono::microseconds(50) > cs_deassert_time_;
260 }
261
262 bool waiting_for_enable_ = true;
263 bool waiting_for_disable_ = false;
264 bool have_transfer_ = false;
265 SpiTransfer transfer_;
266 bool received_dummy_ = false;
267 SpiTransfer received_transfer_;
268 gsl::span<char> to_receive_ = received_transfer_;
269 aos::monotonic_clock::time_point receive_start_;
270 aos::monotonic_clock::time_point cs_deassert_time_;
271};
272
273SpiQueue *SpiQueue::global_instance = nullptr;
274
275// All methods here must be fully synchronized by the caller.
276class FrameQueue {
277 public:
278 FrameQueue() = default;
279 FrameQueue(const FrameQueue &) = delete;
280 FrameQueue &operator=(const FrameQueue &) = delete;
281
Brian Silvermanc41fb862019-03-02 21:14:46 -0800282 void UpdateFrame(int camera, const CameraFrame &frame) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800283 frames_[camera].targets = frame.targets;
284 frames_[camera].capture_time = aos::monotonic_clock::now() - frame.age;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800285 frames_[camera].camera_index = camera;
Brian Silvermand7d01102019-02-24 16:11:21 -0800286 const aos::SizedArray<int, 3> old_last_frames = last_frames_;
287 last_frames_.clear();
288 for (int index : old_last_frames) {
289 if (index != camera) {
290 last_frames_.push_back(index);
291 }
292 }
293 }
294
295 // Creates and returns a transfer with all the current information.
296 //
297 // This does not actually record these frames as transferred until
298 // RemoveLatestFrames() is called.
299 SpiTransfer MakeTransfer();
300
301 // Records the frames represented in the result of the latest MakeTransfer()
302 // call as being transferred, so they will not be represented in subsequent
303 // MakeTransfer() calls.
304 void RemoveLatestFrames() {
305 for (int index : last_frames_) {
306 frames_[index].capture_time = aos::monotonic_clock::min_time;
307 }
308 last_frames_.clear();
309 }
310
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700311 bool HaveLatestFrames() const { return !last_frames_.empty(); }
312
Brian Silvermand7d01102019-02-24 16:11:21 -0800313 private:
314 struct FrameData {
315 aos::SizedArray<Target, 3> targets;
316 aos::monotonic_clock::time_point capture_time =
317 aos::monotonic_clock::min_time;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800318 int camera_index;
Brian Silvermand7d01102019-02-24 16:11:21 -0800319 };
320
321 std::array<FrameData, 5> frames_;
322 // The indices into frames_ which we returned in the last MakeTransfer() call.
323 aos::SizedArray<int, 3> last_frames_;
324};
325
326SpiTransfer FrameQueue::MakeTransfer() {
327 aos::SizedArray<int, 5> oldest_indices;
328 for (size_t i = 0; i < frames_.size(); ++i) {
329 if (frames_[i].capture_time != aos::monotonic_clock::min_time) {
330 oldest_indices.push_back(i);
331 }
332 }
333 std::sort(oldest_indices.begin(), oldest_indices.end(), [this](int a, int b) {
334 return frames_[a].capture_time < frames_[b].capture_time;
335 });
336
337 TeensyToRoborio message;
338 last_frames_.clear();
339 for (int i = 0; i < std::min<int>(oldest_indices.size(), 3); ++i) {
340 const int index = oldest_indices[i];
341 const FrameData &frame = frames_[index];
342 const auto age = aos::monotonic_clock::now() - frame.capture_time;
343 const auto rounded_age = aos::time::round<camera_duration>(age);
Brian Silvermanc41fb862019-03-02 21:14:46 -0800344 message.frames.push_back({frame.targets, rounded_age, frame.camera_index});
Brian Silvermand7d01102019-02-24 16:11:21 -0800345 last_frames_.push_back(index);
346 }
347 return SpiPackToRoborio(message);
348}
Brian Silverman3240e102019-02-16 18:24:24 -0800349
Brian Silverman2294f352019-03-02 16:31:18 -0800350// Manages turning the debug light on and off periodically.
351//
352// It blinks at 1Hz with a variable duty cycle.
353class DebugLight {
354 public:
355 static constexpr aos::monotonic_clock::duration period() {
356 return std::chrono::seconds(1);
357 }
358
359 void set_next_off_time(aos::monotonic_clock::duration next_off_time) {
360 next_off_time_ = next_off_time;
361 }
362
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800363 bool Tick(aos::monotonic_clock::time_point now) {
Brian Silverman2294f352019-03-02 16:31:18 -0800364 if (last_cycle_start_ == aos::monotonic_clock::min_time) {
365 last_cycle_start_ = now;
366 current_off_point_ = last_cycle_start_ + next_off_time_;
367 } else if (now > last_cycle_start_ + period()) {
368 last_cycle_start_ += period();
369 current_off_point_ = last_cycle_start_ + next_off_time_;
370 }
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800371 return now > current_off_point_;
Brian Silverman2294f352019-03-02 16:31:18 -0800372 }
373
374 private:
375 aos::monotonic_clock::time_point last_cycle_start_ =
376 aos::monotonic_clock::min_time;
377
Brian Silvermanbac77542019-03-03 13:57:00 -0800378 aos::monotonic_clock::duration next_off_time_ =
379 std::chrono::milliseconds(100);
Brian Silverman2294f352019-03-02 16:31:18 -0800380 aos::monotonic_clock::time_point current_off_point_ =
381 aos::monotonic_clock::min_time;
382};
383
Brian Silvermana498bbb2019-03-03 17:18:04 -0800384// Returns an identifier for the processor we're running on.
385uint32_t ProcessorIdentifier() {
386 uint32_t r = 0;
387 r |= SIM_UIDH << 24;
388 r |= SIM_UIDMH << 16;
389 r |= SIM_UIDML << 8;
390 r |= SIM_UIDL << 0;
391 return r;
392}
393
Brian Silverman3240e102019-02-16 18:24:24 -0800394extern "C" {
395
396void *__stack_chk_guard = (void *)0x67111971;
397void __stack_chk_fail(void) {
398 while (true) {
399 GPIOC_PSOR = (1 << 5);
400 printf("Stack corruption detected\n");
401 delay(1000);
402 GPIOC_PCOR = (1 << 5);
403 delay(1000);
404 }
405}
406
407extern char *__brkval;
408extern uint32_t __bss_ram_start__[];
409extern uint32_t __heap_start__[];
410extern uint32_t __stack_end__[];
411
412void uart0_status_isr(void) {
413 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800414 Uarts::global_instance->cam1.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800415}
416
417void uart1_status_isr(void) {
418 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800419 Uarts::global_instance->cam0.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800420}
421
422void uart2_status_isr(void) {
423 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800424 Uarts::global_instance->cam2.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800425}
426
427void uart3_status_isr(void) {
428 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800429 Uarts::global_instance->cam3.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800430}
431
432void uart4_status_isr(void) {
433 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800434 Uarts::global_instance->cam4.HandleInterrupt(disable_interrupts);
435}
436
437void spi0_isr(void) {
438 DisableInterrupts disable_interrupts;
439 global_spi_instance->HandleInterrupt(disable_interrupts);
440}
441
442void porta_isr(void) {
443 SpiQueue::global_instance->HandleInterrupt();
Brian Silverman3240e102019-02-16 18:24:24 -0800444}
445
446} // extern "C"
447
448// A test program which echos characters back after adding a per-UART offset to
449// them (CAM0 adds 1, CAM1 adds 2, etc).
450__attribute__((unused)) void TestUarts() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800451 Uarts *const uarts = Uarts::global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -0800452 while (true) {
453 {
454 std::array<char, 10> buffer;
455 const auto data = uarts->cam0.Read(buffer);
456 for (int i = 0; i < data.size(); ++i) {
457 data[i] += 1;
458 }
459 uarts->cam0.Write(data);
460 }
461 {
462 std::array<char, 10> buffer;
463 const auto data = uarts->cam1.Read(buffer);
464 for (int i = 0; i < data.size(); ++i) {
465 data[i] += 2;
466 }
467 uarts->cam1.Write(data);
468 }
469 {
470 std::array<char, 10> buffer;
471 const auto data = uarts->cam2.Read(buffer);
472 for (int i = 0; i < data.size(); ++i) {
473 data[i] += 3;
474 }
475 uarts->cam2.Write(data);
476 }
477 {
478 std::array<char, 10> buffer;
479 const auto data = uarts->cam3.Read(buffer);
480 for (int i = 0; i < data.size(); ++i) {
481 data[i] += 4;
482 }
483 uarts->cam3.Write(data);
484 }
485 {
486 std::array<char, 10> buffer;
487 const auto data = uarts->cam4.Read(buffer);
488 for (int i = 0; i < data.size(); ++i) {
489 data[i] += 5;
490 }
491 uarts->cam4.Write(data);
492 }
493 }
494}
495
496// Tests all the I/O pins. Cycles through each one for 1 second. While active,
497// each output is turned on, and each input has its value printed.
498__attribute__((unused)) void TestIo() {
499 // Set SPI0 pins to GPIO.
500 // SPI_OUT
501 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
502 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1);
503 // SPI_CS
504 PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0;
505 PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
506 // SPI_IN
507 PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0;
508 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
509 // SPI_SCK
510 PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0;
511 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
512
Brian Silverman3240e102019-02-16 18:24:24 -0800513 auto next = aos::monotonic_clock::now();
514 static constexpr auto kTick = std::chrono::seconds(1);
515 while (true) {
516 printf("SPI_MISO\n");
517 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
518 while (aos::monotonic_clock::now() < next + kTick) {
519 }
520 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
521 next += kTick;
522
523 while (aos::monotonic_clock::now() < next + kTick) {
524 printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0));
525 }
526 next += kTick;
527
528 while (aos::monotonic_clock::now() < next + kTick) {
529 printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7));
530 }
531 next += kTick;
532
533 while (aos::monotonic_clock::now() < next + kTick) {
534 printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1));
535 }
536 next += kTick;
537
538 printf("CAM0\n");
539 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
540 while (aos::monotonic_clock::now() < next + kTick) {
541 }
542 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
543 next += kTick;
544
545 printf("CAM1\n");
546 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
547 while (aos::monotonic_clock::now() < next + kTick) {
548 }
549 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
550 next += kTick;
551
552 printf("CAM2\n");
553 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
554 while (aos::monotonic_clock::now() < next + kTick) {
555 }
556 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0;
557 next += kTick;
558
559 printf("CAM3\n");
560 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1;
561 while (aos::monotonic_clock::now() < next + kTick) {
562 }
563 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0;
564 next += kTick;
565
566 printf("CAM4\n");
567 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1;
568 while (aos::monotonic_clock::now() < next + kTick) {
569 }
570 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0;
571 next += kTick;
572
573 printf("CAM5\n");
574 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1;
575 while (aos::monotonic_clock::now() < next + kTick) {
576 }
577 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0;
578 next += kTick;
579
580 printf("CAM6\n");
581 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1;
582 while (aos::monotonic_clock::now() < next + kTick) {
583 }
584 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0;
585 next += kTick;
586
587 printf("CAM7\n");
588 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1;
589 while (aos::monotonic_clock::now() < next + kTick) {
590 }
591 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0;
592 next += kTick;
593
594 printf("CAM8\n");
595 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1;
596 while (aos::monotonic_clock::now() < next + kTick) {
597 }
598 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0;
599 next += kTick;
600
601 printf("CAM9\n");
602 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1;
603 while (aos::monotonic_clock::now() < next + kTick) {
604 }
605 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0;
606 next += kTick;
607 }
608}
609
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800610struct LightRingState {
611 DebugLight debug_light;
612 aos::monotonic_clock::time_point last_frame = aos::monotonic_clock::max_time;
613
614 bool Tick(aos::monotonic_clock::time_point now) {
615 if (last_frame == aos::monotonic_clock::max_time) {
616 last_frame = now;
617 }
618 if (now > last_frame + std::chrono::seconds(1)) {
619 debug_light.set_next_off_time(std::chrono::milliseconds(500));
620 } else {
621 debug_light.set_next_off_time(std::chrono::seconds(0));
622 }
623 return debug_light.Tick(now);
624 }
625};
626
Brian Silvermand7d01102019-02-24 16:11:21 -0800627// Does the normal work of transferring data in all directions.
628//
629// https://community.nxp.com/thread/466937#comment-983881 is a post from NXP
630// claiming that it's impossible to queue up the first byte for the slave end of
631// an SPI connection properly. Instead, we just accept there will be a garbage
632// byte and the other end ignores it.
Brian Silverman83693e42019-03-02 15:45:52 -0800633__attribute__((unused)) void TransferData(
634 frc971::motors::PrintingImplementation *printing) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800635 Uarts *const uarts = Uarts::global_instance;
636 std::array<CobsPacketizer<uart_to_teensy_size()>, 5> packetizers;
637 std::array<TransmitBuffer, 5> transmit_buffers{
638 {&uarts->cam0, &uarts->cam1, &uarts->cam2, &uarts->cam3, &uarts->cam4}};
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800639 std::array<LightRingState, 5> light_rings;
Brian Silvermand7d01102019-02-24 16:11:21 -0800640 FrameQueue frame_queue;
641 aos::monotonic_clock::time_point last_camera_send =
642 aos::monotonic_clock::min_time;
Brian Silverman83693e42019-03-02 15:45:52 -0800643 CameraCommand stdin_camera_command = CameraCommand::kNormal;
644 CameraCommand last_roborio_camera_command = CameraCommand::kNormal;
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800645 DebugLight teensy_debug_light;
Brian Silverman83693e42019-03-02 15:45:52 -0800646
Austin Schuhf7d60c42019-03-03 20:44:02 -0800647 bool verbose = false;
648
Brian Silvermand7d01102019-02-24 16:11:21 -0800649 bool first = true;
650 while (true) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800651 {
652 const auto now = aos::monotonic_clock::now();
653 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = !teensy_debug_light.Tick(now);
654 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = light_rings[0].Tick(now);
655 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = light_rings[1].Tick(now);
656 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = light_rings[2].Tick(now);
657 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = light_rings[3].Tick(now);
658 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = light_rings[4].Tick(now);
659 }
Brian Silverman2294f352019-03-02 16:31:18 -0800660
Brian Silvermand7d01102019-02-24 16:11:21 -0800661 {
662 const auto received_transfer = SpiQueue::global_instance->Tick();
663 if (received_transfer) {
664 const auto unpacked = SpiUnpackToTeensy(*received_transfer);
Brian Silverman83693e42019-03-02 15:45:52 -0800665 if (unpacked) {
666 last_roborio_camera_command = unpacked->camera_command;
667 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800668 printf("SPI decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800669 }
670 }
671 }
672
673 {
674 std::array<char, 20> buffer;
675 packetizers[0].ParseData(uarts->cam0.Read(buffer));
676 packetizers[1].ParseData(uarts->cam1.Read(buffer));
677 packetizers[2].ParseData(uarts->cam2.Read(buffer));
678 packetizers[3].ParseData(uarts->cam3.Read(buffer));
679 packetizers[4].ParseData(uarts->cam4.Read(buffer));
680 }
681 for (size_t i = 0; i < packetizers.size(); ++i) {
682 if (!packetizers[i].received_packet().empty()) {
683 const auto decoded =
684 UartUnpackToTeensy(packetizers[i].received_packet());
685 packetizers[i].clear_received_packet();
686 if (decoded) {
Austin Schuhf7d60c42019-03-03 20:44:02 -0800687 if (verbose) {
Brian Silverman177f0662019-03-09 15:45:02 -0800688 printf("uart frame cam %d, %d targets\n", static_cast<int>(i),
689 static_cast<int>(decoded->targets.size()));
Austin Schuhf7d60c42019-03-03 20:44:02 -0800690 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800691 frame_queue.UpdateFrame(i, *decoded);
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800692 light_rings[i].last_frame = aos::monotonic_clock::now();
693 } else {
694 printf("UART decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800695 }
696 }
697 }
698 {
699 bool made_transfer = false;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700700 const bool have_old_frames = frame_queue.HaveLatestFrames();
701 {
702 const auto new_transfer = frame_queue.MakeTransfer();
Brian Silvermand7d01102019-02-24 16:11:21 -0800703 DisableInterrupts disable_interrupts;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700704 if (!first) {
705 made_transfer =
706 !SpiQueue::global_instance->HaveTransfer(disable_interrupts);
707 }
708 // If we made a transfer just now, then new_transfer might contain
709 // duplicate targets, in which case don't use it.
710 if (!have_old_frames || !made_transfer) {
711 SpiQueue::global_instance->UpdateTransfer(new_transfer,
712 disable_interrupts);
713 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800714 }
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700715 // If we made a transfer, then make sure we aren't remembering any
716 // in-flight frames.
Brian Silvermand7d01102019-02-24 16:11:21 -0800717 if (made_transfer) {
718 frame_queue.RemoveLatestFrames();
719 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800720 }
721 {
722 const auto now = aos::monotonic_clock::now();
Brian Silvermanbac77542019-03-03 13:57:00 -0800723 CameraCommand current_camera_command = CameraCommand::kNormal;
724 if (last_roborio_camera_command != CameraCommand::kNormal) {
725 current_camera_command = last_roborio_camera_command;
726 } else {
727 current_camera_command = stdin_camera_command;
728 }
729 if (current_camera_command == CameraCommand::kUsb) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800730 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(900));
Brian Silvermanbac77542019-03-03 13:57:00 -0800731 } else if (current_camera_command == CameraCommand::kCameraPassthrough) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800732 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(500));
Brian Silvermanbac77542019-03-03 13:57:00 -0800733 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800734 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(100));
Brian Silvermanbac77542019-03-03 13:57:00 -0800735 }
736
737 if (current_camera_command == CameraCommand::kAs) {
738 for (size_t i = 0; i < transmit_buffers.size(); ++i) {
739 transmit_buffers[i].FillAs();
Brian Silverman83693e42019-03-02 15:45:52 -0800740 }
Brian Silvermanbac77542019-03-03 13:57:00 -0800741 } else {
742 if (last_camera_send + std::chrono::milliseconds(1000) < now) {
743 last_camera_send = now;
744 CameraCalibration calibration{};
745 calibration.teensy_now = aos::monotonic_clock::now();
746 calibration.realtime_now = aos::realtime_clock::min_time;
747 calibration.camera_command = current_camera_command;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800748
749 for (int i = 0; i < 5; ++i) {
750 const y2019::vision::CameraCalibration *const constants =
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800751 y2019::vision::GetCamera(y2019::vision::CameraSerialNumbers(
752 ProcessorIdentifier())[i]);
Alex Perryf3e46be2019-03-03 17:26:14 -0800753 calibration.calibration(0, 0) = constants->intrinsics.mount_angle;
754 calibration.calibration(0, 1) = constants->intrinsics.focal_length;
755 calibration.calibration(0, 2) = constants->intrinsics.barrel_mount;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800756 transmit_buffers[i].MaybeWritePacket(calibration);
757 }
Brian Silverman2294f352019-03-02 16:31:18 -0800758 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800759 }
760 for (TransmitBuffer &transmit_buffer : transmit_buffers) {
761 transmit_buffer.Tick(now);
762 }
763 }
764
Brian Silverman83693e42019-03-02 15:45:52 -0800765 {
766 const auto stdin_data = printing->ReadStdin();
767 if (!stdin_data.empty()) {
768 switch (stdin_data.back()) {
769 case 'p':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800770 printf("Sending passthrough mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800771 stdin_camera_command = CameraCommand::kCameraPassthrough;
772 break;
773 case 'u':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800774 printf("Sending USB mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800775 stdin_camera_command = CameraCommand::kUsb;
776 break;
Austin Schuh4e2629d2019-03-28 14:44:37 -0700777 case 'l':
778 printf("Log mode\n");
779 stdin_camera_command = CameraCommand::kLog;
780 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800781 case 'n':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800782 printf("Sending normal mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800783 stdin_camera_command = CameraCommand::kNormal;
784 break;
Brian Silvermanbac77542019-03-03 13:57:00 -0800785 case 'a':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800786 printf("Sending all 'a's\n");
Brian Silvermanbac77542019-03-03 13:57:00 -0800787 stdin_camera_command = CameraCommand::kAs;
788 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800789 case 'c':
790 printf("This UART board is 0x%" PRIx32 "\n", ProcessorIdentifier());
791 for (int i = 0; i < 5; ++i) {
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800792 printf(
793 "Camera slot %d's serial number is %d\n", i,
794 y2019::vision::CameraSerialNumbers(ProcessorIdentifier())[i]);
Brian Silvermana498bbb2019-03-03 17:18:04 -0800795 }
796 break;
Austin Schuhf7d60c42019-03-03 20:44:02 -0800797 case 'v':
798 printf("Toggling verbose mode\n");
799 verbose = !verbose;
800 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800801 case 'h':
802 printf("UART board commands:\n");
803 printf(" p: Send passthrough mode\n");
804 printf(" u: Send USB mode\n");
Austin Schuh4e2629d2019-03-28 14:44:37 -0700805 printf(" l: Send Log mode\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800806 printf(" n: Send normal mode\n");
807 printf(" a: Send all-'a' mode\n");
808 printf(" c: Dump camera configuration\n");
Austin Schuhf7d60c42019-03-03 20:44:02 -0800809 printf(" v: Toggle verbose print\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800810 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800811 default:
812 printf("Unrecognized character\n");
813 break;
814 }
815 }
816 }
817
Brian Silvermand7d01102019-02-24 16:11:21 -0800818 first = false;
819 }
820}
821
Brian Silverman3240e102019-02-16 18:24:24 -0800822int Main() {
823 // for background about this startup delay, please see these conversations
824 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
825 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
826 delay(400);
827
828 // Set all interrupts to the second-lowest priority to start with.
829 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
830
831 // Now set priorities for all the ones we care about. They only have meaning
832 // relative to each other, which means centralizing them here makes it a lot
833 // more manageable.
Brian Silvermand7d01102019-02-24 16:11:21 -0800834 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
835 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0x3);
836 NVIC_SET_SANE_PRIORITY(IRQ_UART1_STATUS, 0x3);
837 NVIC_SET_SANE_PRIORITY(IRQ_UART2_STATUS, 0x3);
838 NVIC_SET_SANE_PRIORITY(IRQ_UART3_STATUS, 0x3);
839 NVIC_SET_SANE_PRIORITY(IRQ_UART4_STATUS, 0x3);
840 // This one is relatively sensitive to latencies. The buffer is ~4800 clock
841 // cycles long.
842 NVIC_SET_SANE_PRIORITY(IRQ_SPI0, 0x2);
843 NVIC_SET_SANE_PRIORITY(IRQ_PORTA, 0x3);
Brian Silverman3240e102019-02-16 18:24:24 -0800844
845 // Set the LED's pin to output mode.
846 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
847 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
848
849 frc971::motors::PrintingParameters printing_parameters;
850 printing_parameters.dedicated_usb = true;
851 const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing =
852 CreatePrinting(printing_parameters);
853 printing->Initialize();
854
855 DMA.CR = M_DMA_EMLM;
856
Brian Silvermand7d01102019-02-24 16:11:21 -0800857 SIM_SCGC1 |= SIM_SCGC1_UART4;
Brian Silverman3240e102019-02-16 18:24:24 -0800858 SIM_SCGC4 |=
859 SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3;
Brian Silvermand7d01102019-02-24 16:11:21 -0800860 SIM_SCGC6 |= SIM_SCGC6_SPI0;
Brian Silverman3240e102019-02-16 18:24:24 -0800861
862 // SPI0 goes to the roboRIO.
863 // SPI0_PCS0 is SPI_CS.
Brian Silvermand7d01102019-02-24 16:11:21 -0800864 PORTD_PCR0 = PORT_PCR_MUX(2);
Brian Silverman3240e102019-02-16 18:24:24 -0800865 // SPI0_SOUT is SPI_MISO.
866 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
867 // SPI0_SIN is SPI_MOSI.
868 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2);
869 // SPI0_SCK is SPI_CLK.
870 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2);
Brian Silvermand7d01102019-02-24 16:11:21 -0800871 // SPI_CS_DRIVE
872 PERIPHERAL_BITBAND(GPIOB_PDDR, 17) = 1;
873 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
874 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(1);
875 // SPI_CS_IN
876 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 0;
877 // Set the filter width.
878 PORTA_DFWR = 31;
879 // Enable the filter.
880 PERIPHERAL_BITBAND(PORTA_DFER, 17) = 1;
881 PORTA_PCR17 =
882 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
883 // Clear the interrupt flag now that we've reconfigured it.
884 PORTA_ISFR = 1 << 17;
Brian Silverman3240e102019-02-16 18:24:24 -0800885
Brian Silverman177f0662019-03-09 15:45:02 -0800886 // For now, we have no need to dim the LEDs, so we're just going to set them
887 // all to GPIO mode for simplicity of programming.
888#if 0
Brian Silverman3240e102019-02-16 18:24:24 -0800889 // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel).
890 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
891 // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel).
892 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
893 // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel).
894 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4);
895 // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera).
896 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
897
898 // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera).
899 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3);
900 // FTM2_CH0 is LED5 (for CAM4).
901 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3);
902
903 // FTM3_CH4 is LED6 (for CAM2).
904 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3);
905 // FTM3_CH5 is LED7 (for CAM3).
906 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3);
907 // FTM3_CH6 is LED8 (for CAM1).
908 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3);
909 // FTM3_CH7 is LED9 (for CAM0).
910 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
Brian Silverman177f0662019-03-09 15:45:02 -0800911#else
912 // Set all the LED pins to GPIO.
913 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
914 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1);
915 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
916 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1);
917 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
918 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1);
919 PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1;
920 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1);
921 PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1;
922 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1);
923 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
924 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
925 PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1;
926 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
927 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
928 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
929 PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1;
930 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1);
931 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
932 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
933#endif
Brian Silverman3240e102019-02-16 18:24:24 -0800934
935 // This hardware has been deactivated, but keep this comment for now to
936 // document which pins it is on.
937#if 0
938 // This is ODROID_EN.
939 PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1;
940 PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0;
941 PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
942 // This is CAM_EN.
943 PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1;
944 PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0;
945 PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
946#endif
947 // This is 5V_PGOOD.
948 PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0;
949 PORTD_PCR6 = PORT_PCR_MUX(1);
950
951 // These go to CAM1.
Brian Silverman30adf342019-03-09 18:27:56 -0800952 // UART0_RX (peripheral) is UART1_RX (schematic) is UART1_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800953 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
954 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800955 // UART0_TX (peripheral) is UART1_TX (schematic) is UART1_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800956 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3);
957
958 // These go to CAM0.
Brian Silverman30adf342019-03-09 18:27:56 -0800959 // UART1_RX (peripheral) is UART0_RX (schematic) is UART0_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800960 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
961 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800962 // UART1_TX (peripheral) is UART0_TX (schematic) is UART0_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800963 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3);
964
965 // These go to CAM2.
Brian Silverman30adf342019-03-09 18:27:56 -0800966 // UART2_RX is UART2_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800967 PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
968 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800969 // UART2_TX is UART2_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800970 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3);
971
972 // These go to CAM3.
Brian Silverman30adf342019-03-09 18:27:56 -0800973 // UART3_RX is UART3_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800974 PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
975 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800976 // UART3_TX is UART3_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800977 PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
978
979 // These go to CAM4.
Brian Silverman30adf342019-03-09 18:27:56 -0800980 // UART4_RX is UART4_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800981 PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
982 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800983 // UART4_TX is UART4_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800984 PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3);
985
986 Uarts uarts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800987 InterruptBufferedSpi spi0{&SPI0, BUS_CLOCK_FREQUENCY};
988 global_spi_instance = &spi0;
989 SpiQueue spi_queue;
Brian Silverman3240e102019-02-16 18:24:24 -0800990
991 // Give everything a chance to get going.
992 delay(100);
993
994 printf("Ram start: %p\n", __bss_ram_start__);
995 printf("Heap start: %p\n", __heap_start__);
996 printf("Heap end: %p\n", __brkval);
997 printf("Stack start: %p\n", __stack_end__);
998
999 uarts.Initialize(115200);
1000 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
1001 NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
1002 NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
1003 NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
1004 NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
Brian Silvermand7d01102019-02-24 16:11:21 -08001005 spi0.Initialize();
1006 NVIC_ENABLE_IRQ(IRQ_SPI0);
1007 NVIC_ENABLE_IRQ(IRQ_PORTA);
1008
Brian Silverman83693e42019-03-02 15:45:52 -08001009 TransferData(printing.get());
Brian Silverman3240e102019-02-16 18:24:24 -08001010
1011 while (true) {
1012 }
1013}
1014
1015extern "C" {
1016
1017int main(void) {
1018 return Main();
1019}
1020
1021} // extern "C"
1022
1023} // namespace
1024} // namespace jevois
1025} // namespace frc971