blob: 7c71ae86aa6a0d2f5decb72a03334ca6f7df92e9 [file] [log] [blame]
Tyler Chatowbf0609c2021-07-31 16:13:27 -07001#include <cinttypes>
2#include <cstdio>
James Kuszmaul3ae42262019-11-08 12:33:41 -08003#include <optional>
4
Austin Schuh7fe04492022-01-02 13:37:21 -08005#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07006
Brian Silverman3240e102019-02-16 18:24:24 -08007#include "aos/time/time.h"
8#include "motors/core/kinetis.h"
9#include "motors/core/time.h"
10#include "motors/peripheral/configuration.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080011#include "motors/peripheral/spi.h"
Brian Silverman3240e102019-02-16 18:24:24 -080012#include "motors/peripheral/uart.h"
13#include "motors/print/print.h"
14#include "motors/util.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080015#include "y2019/jevois/cobs.h"
16#include "y2019/jevois/spi.h"
17#include "y2019/jevois/uart.h"
Brian Silvermana498bbb2019-03-03 17:18:04 -080018#include "y2019/vision/constants.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080019
Brian Silvermand7d01102019-02-24 16:11:21 -080020using frc971::teensy::InterruptBufferedSpi;
Tyler Chatowbf0609c2021-07-31 16:13:27 -070021using frc971::teensy::InterruptBufferedUart;
Brian Silvermand7d01102019-02-24 16:11:21 -080022
23// All indices here refer to the ports as numbered on the PCB.
Brian Silverman3240e102019-02-16 18:24:24 -080024
25namespace frc971 {
26namespace jevois {
27namespace {
28
Brian Silvermand7d01102019-02-24 16:11:21 -080029// Holds all of our hardware UARTs. There is exactly one global instance for
30// interrupt handlers to access.
Brian Silverman3240e102019-02-16 18:24:24 -080031struct Uarts {
32 Uarts() {
33 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080034 global_instance = this;
Brian Silverman3240e102019-02-16 18:24:24 -080035 }
36 ~Uarts() {
37 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080038 global_instance = nullptr;
Brian Silverman3240e102019-02-16 18:24:24 -080039 }
Brian Silvermand7d01102019-02-24 16:11:21 -080040 Uarts(const Uarts &) = delete;
41 Uarts &operator=(const Uarts &) = delete;
Brian Silverman3240e102019-02-16 18:24:24 -080042
43 void Initialize(int baud_rate) {
44 cam0.Initialize(baud_rate);
45 cam1.Initialize(baud_rate);
46 cam2.Initialize(baud_rate);
47 cam3.Initialize(baud_rate);
48 cam4.Initialize(baud_rate);
49 }
50
Brian Silvermand7d01102019-02-24 16:11:21 -080051 InterruptBufferedUart cam0{&UART1, F_CPU};
52 InterruptBufferedUart cam1{&UART0, F_CPU};
53 InterruptBufferedUart cam2{&UART2, BUS_CLOCK_FREQUENCY};
54 InterruptBufferedUart cam3{&UART3, BUS_CLOCK_FREQUENCY};
55 InterruptBufferedUart cam4{&UART4, BUS_CLOCK_FREQUENCY};
Brian Silverman3240e102019-02-16 18:24:24 -080056
Brian Silvermand7d01102019-02-24 16:11:21 -080057 static Uarts *global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -080058};
59
Brian Silvermand7d01102019-02-24 16:11:21 -080060Uarts *Uarts::global_instance = nullptr;
61
62// Manages the transmit buffer to a single camera.
63//
64// We have to add delays between sending each byte in order for the camera to
65// successfully receive them.
66struct TransmitBuffer {
67 TransmitBuffer(InterruptBufferedUart *camera_in) : camera(camera_in) {}
68 InterruptBufferedUart *const camera;
69
70 frc971::teensy::UartBuffer<1024> buffer;
71 aos::monotonic_clock::time_point last_send = aos::monotonic_clock::min_time;
72
73 // Sends a byte to the camera if it's time.
74 void Tick(aos::monotonic_clock::time_point now) {
75 if (buffer.empty()) {
76 return;
77 }
78 if (now < last_send + std::chrono::milliseconds(1)) {
79 return;
80 }
81 last_send = now;
82 camera->Write(std::array<char, 1>{{buffer.PopSingle()}});
83 }
84
85 // Queues up another packet to send, only if the previous one has finished.
86 void MaybeWritePacket(const CameraCalibration &calibration) {
87 if (!buffer.empty()) {
88 return;
89 }
90 const auto serialized = UartPackToCamera(calibration);
91 buffer.PushSingle(0);
92 if (buffer.PushSpan(serialized) == static_cast<int>(serialized.size())) {
93 buffer.PushSingle(0);
94 }
95 }
Brian Silvermanbac77542019-03-03 13:57:00 -080096
97 void FillAs() {
98 while (!buffer.full()) {
99 buffer.PushSingle('a');
100 }
101 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800102};
103
104InterruptBufferedSpi *global_spi_instance = nullptr;
105
106// Manages queueing a transfer to send via SPI.
107class SpiQueue {
108 public:
109 SpiQueue() {
110 DisableInterrupts disable_interrupts;
111 global_instance = this;
112 }
113 ~SpiQueue() {
114 DisableInterrupts disable_interrupts;
115 global_instance = nullptr;
116 }
117 SpiQueue(const SpiQueue &) = delete;
118 SpiQueue &operator=(const SpiQueue &) = delete;
119
Austin Schuhb72be802022-01-02 12:26:28 -0800120 std::optional<absl::Span<const char>> Tick() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800121 {
122 DisableInterrupts disable_interrupts;
123 if (waiting_for_enable_ || waiting_for_disable_) {
James Kuszmaul3ae42262019-11-08 12:33:41 -0800124 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800125 }
126 }
127 const auto now = aos::monotonic_clock::now();
128 if (TransferTimedOut(now)) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700129 printf("SPI timeout with %d left\n",
130 static_cast<int>(to_receive_.size()));
Brian Silvermand7d01102019-02-24 16:11:21 -0800131 WaitForNextTransfer();
James Kuszmaul3ae42262019-11-08 12:33:41 -0800132 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800133 }
134 {
135 DisableInterrupts disable_interrupts;
136 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17) &&
137 cs_deassert_time_ == aos::monotonic_clock::max_time) {
138 cs_deassert_time_ = now;
139 }
140 }
141 if (DeassertHappened(now)) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700142 printf("CS deasserted with %d left\n",
143 static_cast<int>(to_receive_.size()));
Brian Silvermand7d01102019-02-24 16:11:21 -0800144 WaitForNextTransfer();
James Kuszmaul3ae42262019-11-08 12:33:41 -0800145 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800146 }
147 bool all_done;
148 {
149 DisableInterrupts disable_interrupts;
150 if (received_dummy_) {
151 to_receive_ = to_receive_.subspan(
152 global_spi_instance->Read(to_receive_, &disable_interrupts).size());
153 all_done = to_receive_.empty();
154 } else {
155 std::array<char, 1> dummy_data;
Austin Schuh7fe04492022-01-02 13:37:21 -0800156 if (global_spi_instance
157 ->Read(absl::Span<char>(dummy_data), &disable_interrupts)
158 .size() >= 1) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800159 received_dummy_ = true;
160 }
161 all_done = false;
162 }
163 }
164 if (all_done) {
165 WaitForNextTransfer();
166 return received_transfer_;
167 }
James Kuszmaul3ae42262019-11-08 12:33:41 -0800168 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800169 }
170
171 void HandleInterrupt() {
172 DisableInterrupts disable_interrupts;
173 if (waiting_for_disable_) {
174 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
175 PORTA_PCR17 =
176 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
177 // Clear the interrupt flag now that we've reconfigured it.
178 PORTA_ISFR = 1 << 17;
179 waiting_for_disable_ = false;
180 } else {
181 // Clear the interrupt flag. It shouldn't trigger again immediately
182 // because the pin is still asserted.
183 PORTA_ISFR = 1 << 17;
184 }
185 return;
186 }
187 if (waiting_for_enable_) {
188 if (PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
189 global_spi_instance->ClearQueues(disable_interrupts);
190 // Tell the SPI peripheral its CS is asserted.
191 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 0;
192 // Disable interrupts on the enable pin. We'll re-enable once we finish
193 // the transfer.
194 PORTA_PCR17 = PORT_PCR_MUX(1);
195 // Clear the interrupt flag now that we've reconfigured it.
196 PORTA_ISFR = 1 << 17;
197 if (have_transfer_) {
198 global_spi_instance->Write(transfer_, &disable_interrupts);
199 have_transfer_ = false;
200 } else {
201 printf("Writing dummy SPI frame\n");
202 // If we don't have anything, just write 0s to avoid getting the
203 // hardware confused.
204 global_spi_instance->Write(SpiTransfer{}, &disable_interrupts);
205 }
206 // Queue up a dummy byte at the end. This won't actually be sent,
207 // because the first byte we do send will be garbage, but it will
208 // synchronize our queues so we receive all the useful data bytes.
209 global_spi_instance->Write(std::array<char, 1>(), &disable_interrupts);
210 waiting_for_enable_ = false;
211 receive_start_ = aos::monotonic_clock::now();
212 cs_deassert_time_ = aos::monotonic_clock::max_time;
213 // To make debugging easier.
214 received_transfer_.fill(0);
215 } else {
216 // Clear the interrupt flag. It shouldn't trigger again immediately
217 // because the pin is still asserted.
218 PORTA_ISFR = 1 << 17;
219 }
220 return;
221 }
222 // We shouldn't ever get here. Clear all the flags and hope they don't get
223 // re-asserted immediately.
224 PORTA_ISFR = UINT32_C(0xFFFFFFFF);
225 }
226
227 void UpdateTransfer(const SpiTransfer &transfer, const DisableInterrupts &) {
228 have_transfer_ = true;
229 transfer_ = transfer;
230 }
231
232 // Returns whether a transfer is currently queued. This will be true between a
233 // call to UpdateTransfer and that transfer actually being moved out to the
234 // hardware.
235 bool HaveTransfer(const DisableInterrupts &) const { return have_transfer_; }
236
237 static SpiQueue *global_instance;
238
239 private:
240 void WaitForNextTransfer() {
Austin Schuhb72be802022-01-02 12:26:28 -0800241 to_receive_ = absl::Span<char>(received_transfer_);
Brian Silvermand7d01102019-02-24 16:11:21 -0800242 received_dummy_ = false;
243 {
244 DisableInterrupts disable_interrupts;
245 waiting_for_enable_ = true;
246 waiting_for_disable_ = true;
247 PORTA_PCR17 =
248 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0x8) /* Interrupt when logic 0 */;
249 // Clear the interrupt flag now that we've reconfigured it.
250 PORTA_ISFR = 1 << 17;
251 }
252 // Tell the SPI peripheral its CS is de-asserted.
253 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
254 }
255
256 bool TransferTimedOut(aos::monotonic_clock::time_point now) {
257 DisableInterrupts disable_interrupts;
258 // TODO: Revise this timeout.
259 return now - std::chrono::milliseconds(50) > receive_start_;
260 }
261
262 bool DeassertHappened(aos::monotonic_clock::time_point now) {
263 DisableInterrupts disable_interrupts;
264 return now - std::chrono::microseconds(50) > cs_deassert_time_;
265 }
266
267 bool waiting_for_enable_ = true;
268 bool waiting_for_disable_ = false;
269 bool have_transfer_ = false;
270 SpiTransfer transfer_;
271 bool received_dummy_ = false;
272 SpiTransfer received_transfer_;
Austin Schuhb72be802022-01-02 12:26:28 -0800273 absl::Span<char> to_receive_{received_transfer_};
Brian Silvermand7d01102019-02-24 16:11:21 -0800274 aos::monotonic_clock::time_point receive_start_;
275 aos::monotonic_clock::time_point cs_deassert_time_;
276};
277
278SpiQueue *SpiQueue::global_instance = nullptr;
279
280// All methods here must be fully synchronized by the caller.
281class FrameQueue {
282 public:
283 FrameQueue() = default;
284 FrameQueue(const FrameQueue &) = delete;
285 FrameQueue &operator=(const FrameQueue &) = delete;
286
Brian Silvermanc41fb862019-03-02 21:14:46 -0800287 void UpdateFrame(int camera, const CameraFrame &frame) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800288 frames_[camera].targets = frame.targets;
289 frames_[camera].capture_time = aos::monotonic_clock::now() - frame.age;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800290 frames_[camera].camera_index = camera;
Brian Silvermand7d01102019-02-24 16:11:21 -0800291 const aos::SizedArray<int, 3> old_last_frames = last_frames_;
292 last_frames_.clear();
293 for (int index : old_last_frames) {
294 if (index != camera) {
295 last_frames_.push_back(index);
296 }
297 }
298 }
299
300 // Creates and returns a transfer with all the current information.
301 //
302 // This does not actually record these frames as transferred until
303 // RemoveLatestFrames() is called.
304 SpiTransfer MakeTransfer();
305
306 // Records the frames represented in the result of the latest MakeTransfer()
307 // call as being transferred, so they will not be represented in subsequent
308 // MakeTransfer() calls.
309 void RemoveLatestFrames() {
310 for (int index : last_frames_) {
311 frames_[index].capture_time = aos::monotonic_clock::min_time;
312 }
313 last_frames_.clear();
314 }
315
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700316 bool HaveLatestFrames() const { return !last_frames_.empty(); }
317
Brian Silvermand7d01102019-02-24 16:11:21 -0800318 private:
319 struct FrameData {
320 aos::SizedArray<Target, 3> targets;
321 aos::monotonic_clock::time_point capture_time =
322 aos::monotonic_clock::min_time;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800323 int camera_index;
Brian Silvermand7d01102019-02-24 16:11:21 -0800324 };
325
326 std::array<FrameData, 5> frames_;
327 // The indices into frames_ which we returned in the last MakeTransfer() call.
328 aos::SizedArray<int, 3> last_frames_;
329};
330
331SpiTransfer FrameQueue::MakeTransfer() {
332 aos::SizedArray<int, 5> oldest_indices;
333 for (size_t i = 0; i < frames_.size(); ++i) {
334 if (frames_[i].capture_time != aos::monotonic_clock::min_time) {
335 oldest_indices.push_back(i);
336 }
337 }
338 std::sort(oldest_indices.begin(), oldest_indices.end(), [this](int a, int b) {
339 return frames_[a].capture_time < frames_[b].capture_time;
340 });
341
342 TeensyToRoborio message;
343 last_frames_.clear();
344 for (int i = 0; i < std::min<int>(oldest_indices.size(), 3); ++i) {
345 const int index = oldest_indices[i];
346 const FrameData &frame = frames_[index];
347 const auto age = aos::monotonic_clock::now() - frame.capture_time;
Austin Schuhb72be802022-01-02 12:26:28 -0800348 const auto rounded_age = std::chrono::round<camera_duration>(age);
Brian Silvermanc41fb862019-03-02 21:14:46 -0800349 message.frames.push_back({frame.targets, rounded_age, frame.camera_index});
Brian Silvermand7d01102019-02-24 16:11:21 -0800350 last_frames_.push_back(index);
351 }
352 return SpiPackToRoborio(message);
353}
Brian Silverman3240e102019-02-16 18:24:24 -0800354
Brian Silverman2294f352019-03-02 16:31:18 -0800355// Manages turning the debug light on and off periodically.
356//
357// It blinks at 1Hz with a variable duty cycle.
358class DebugLight {
359 public:
360 static constexpr aos::monotonic_clock::duration period() {
361 return std::chrono::seconds(1);
362 }
363
364 void set_next_off_time(aos::monotonic_clock::duration next_off_time) {
365 next_off_time_ = next_off_time;
366 }
367
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800368 bool Tick(aos::monotonic_clock::time_point now) {
Brian Silverman2294f352019-03-02 16:31:18 -0800369 if (last_cycle_start_ == aos::monotonic_clock::min_time) {
370 last_cycle_start_ = now;
371 current_off_point_ = last_cycle_start_ + next_off_time_;
372 } else if (now > last_cycle_start_ + period()) {
373 last_cycle_start_ += period();
374 current_off_point_ = last_cycle_start_ + next_off_time_;
375 }
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800376 return now > current_off_point_;
Brian Silverman2294f352019-03-02 16:31:18 -0800377 }
378
379 private:
380 aos::monotonic_clock::time_point last_cycle_start_ =
381 aos::monotonic_clock::min_time;
382
Brian Silvermanbac77542019-03-03 13:57:00 -0800383 aos::monotonic_clock::duration next_off_time_ =
384 std::chrono::milliseconds(100);
Brian Silverman2294f352019-03-02 16:31:18 -0800385 aos::monotonic_clock::time_point current_off_point_ =
386 aos::monotonic_clock::min_time;
387};
388
Brian Silvermana498bbb2019-03-03 17:18:04 -0800389// Returns an identifier for the processor we're running on.
390uint32_t ProcessorIdentifier() {
391 uint32_t r = 0;
392 r |= SIM_UIDH << 24;
393 r |= SIM_UIDMH << 16;
394 r |= SIM_UIDML << 8;
395 r |= SIM_UIDL << 0;
396 return r;
397}
398
Brian Silverman3240e102019-02-16 18:24:24 -0800399extern "C" {
400
401void *__stack_chk_guard = (void *)0x67111971;
402void __stack_chk_fail(void) {
403 while (true) {
404 GPIOC_PSOR = (1 << 5);
405 printf("Stack corruption detected\n");
406 delay(1000);
407 GPIOC_PCOR = (1 << 5);
408 delay(1000);
409 }
410}
411
412extern char *__brkval;
413extern uint32_t __bss_ram_start__[];
414extern uint32_t __heap_start__[];
415extern uint32_t __stack_end__[];
416
417void uart0_status_isr(void) {
418 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800419 Uarts::global_instance->cam1.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800420}
421
422void uart1_status_isr(void) {
423 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800424 Uarts::global_instance->cam0.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800425}
426
427void uart2_status_isr(void) {
428 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800429 Uarts::global_instance->cam2.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800430}
431
432void uart3_status_isr(void) {
433 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800434 Uarts::global_instance->cam3.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800435}
436
437void uart4_status_isr(void) {
438 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800439 Uarts::global_instance->cam4.HandleInterrupt(disable_interrupts);
440}
441
442void spi0_isr(void) {
443 DisableInterrupts disable_interrupts;
444 global_spi_instance->HandleInterrupt(disable_interrupts);
445}
446
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700447void porta_isr(void) { SpiQueue::global_instance->HandleInterrupt(); }
Brian Silverman3240e102019-02-16 18:24:24 -0800448
449} // extern "C"
450
451// A test program which echos characters back after adding a per-UART offset to
452// them (CAM0 adds 1, CAM1 adds 2, etc).
453__attribute__((unused)) void TestUarts() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800454 Uarts *const uarts = Uarts::global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -0800455 while (true) {
456 {
457 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800458 const auto data = uarts->cam0.Read(absl::Span<char>(buffer));
459 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800460 data[i] += 1;
461 }
462 uarts->cam0.Write(data);
463 }
464 {
465 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800466 const auto data = uarts->cam1.Read(absl::Span<char>(buffer));
467 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800468 data[i] += 2;
469 }
470 uarts->cam1.Write(data);
471 }
472 {
473 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800474 const auto data = uarts->cam2.Read(absl::Span<char>(buffer));
475 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800476 data[i] += 3;
477 }
478 uarts->cam2.Write(data);
479 }
480 {
481 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800482 const auto data = uarts->cam3.Read(absl::Span<char>(buffer));
483 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800484 data[i] += 4;
485 }
486 uarts->cam3.Write(data);
487 }
488 {
489 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800490 const auto data = uarts->cam4.Read(absl::Span<char>(buffer));
491 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800492 data[i] += 5;
493 }
494 uarts->cam4.Write(data);
495 }
496 }
497}
498
499// Tests all the I/O pins. Cycles through each one for 1 second. While active,
500// each output is turned on, and each input has its value printed.
501__attribute__((unused)) void TestIo() {
502 // Set SPI0 pins to GPIO.
503 // SPI_OUT
504 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
505 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1);
506 // SPI_CS
507 PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0;
508 PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
509 // SPI_IN
510 PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0;
511 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
512 // SPI_SCK
513 PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0;
514 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
515
Brian Silverman3240e102019-02-16 18:24:24 -0800516 auto next = aos::monotonic_clock::now();
517 static constexpr auto kTick = std::chrono::seconds(1);
518 while (true) {
519 printf("SPI_MISO\n");
520 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
521 while (aos::monotonic_clock::now() < next + kTick) {
522 }
523 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
524 next += kTick;
525
526 while (aos::monotonic_clock::now() < next + kTick) {
527 printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0));
528 }
529 next += kTick;
530
531 while (aos::monotonic_clock::now() < next + kTick) {
532 printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7));
533 }
534 next += kTick;
535
536 while (aos::monotonic_clock::now() < next + kTick) {
537 printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1));
538 }
539 next += kTick;
540
541 printf("CAM0\n");
542 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
543 while (aos::monotonic_clock::now() < next + kTick) {
544 }
545 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
546 next += kTick;
547
548 printf("CAM1\n");
549 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
550 while (aos::monotonic_clock::now() < next + kTick) {
551 }
552 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
553 next += kTick;
554
555 printf("CAM2\n");
556 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
557 while (aos::monotonic_clock::now() < next + kTick) {
558 }
559 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0;
560 next += kTick;
561
562 printf("CAM3\n");
563 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1;
564 while (aos::monotonic_clock::now() < next + kTick) {
565 }
566 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0;
567 next += kTick;
568
569 printf("CAM4\n");
570 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1;
571 while (aos::monotonic_clock::now() < next + kTick) {
572 }
573 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0;
574 next += kTick;
575
576 printf("CAM5\n");
577 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1;
578 while (aos::monotonic_clock::now() < next + kTick) {
579 }
580 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0;
581 next += kTick;
582
583 printf("CAM6\n");
584 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1;
585 while (aos::monotonic_clock::now() < next + kTick) {
586 }
587 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0;
588 next += kTick;
589
590 printf("CAM7\n");
591 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1;
592 while (aos::monotonic_clock::now() < next + kTick) {
593 }
594 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0;
595 next += kTick;
596
597 printf("CAM8\n");
598 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1;
599 while (aos::monotonic_clock::now() < next + kTick) {
600 }
601 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0;
602 next += kTick;
603
604 printf("CAM9\n");
605 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1;
606 while (aos::monotonic_clock::now() < next + kTick) {
607 }
608 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0;
609 next += kTick;
610 }
611}
612
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800613struct LightRingState {
614 DebugLight debug_light;
615 aos::monotonic_clock::time_point last_frame = aos::monotonic_clock::max_time;
616
617 bool Tick(aos::monotonic_clock::time_point now) {
618 if (last_frame == aos::monotonic_clock::max_time) {
619 last_frame = now;
620 }
621 if (now > last_frame + std::chrono::seconds(1)) {
622 debug_light.set_next_off_time(std::chrono::milliseconds(500));
623 } else {
624 debug_light.set_next_off_time(std::chrono::seconds(0));
625 }
626 return debug_light.Tick(now);
627 }
628};
629
Brian Silvermand7d01102019-02-24 16:11:21 -0800630// Does the normal work of transferring data in all directions.
631//
632// https://community.nxp.com/thread/466937#comment-983881 is a post from NXP
633// claiming that it's impossible to queue up the first byte for the slave end of
634// an SPI connection properly. Instead, we just accept there will be a garbage
635// byte and the other end ignores it.
Brian Silverman83693e42019-03-02 15:45:52 -0800636__attribute__((unused)) void TransferData(
637 frc971::motors::PrintingImplementation *printing) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800638 Uarts *const uarts = Uarts::global_instance;
639 std::array<CobsPacketizer<uart_to_teensy_size()>, 5> packetizers;
640 std::array<TransmitBuffer, 5> transmit_buffers{
641 {&uarts->cam0, &uarts->cam1, &uarts->cam2, &uarts->cam3, &uarts->cam4}};
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800642 std::array<LightRingState, 5> light_rings;
Brian Silvermand7d01102019-02-24 16:11:21 -0800643 FrameQueue frame_queue;
644 aos::monotonic_clock::time_point last_camera_send =
645 aos::monotonic_clock::min_time;
Brian Silverman83693e42019-03-02 15:45:52 -0800646 CameraCommand stdin_camera_command = CameraCommand::kNormal;
647 CameraCommand last_roborio_camera_command = CameraCommand::kNormal;
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800648 DebugLight teensy_debug_light;
Brian Silverman83693e42019-03-02 15:45:52 -0800649
Austin Schuhf7d60c42019-03-03 20:44:02 -0800650 bool verbose = false;
651
Brian Silvermand7d01102019-02-24 16:11:21 -0800652 bool first = true;
653 while (true) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800654 {
655 const auto now = aos::monotonic_clock::now();
656 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = !teensy_debug_light.Tick(now);
657 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = light_rings[0].Tick(now);
658 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = light_rings[1].Tick(now);
659 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = light_rings[2].Tick(now);
660 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = light_rings[3].Tick(now);
661 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = light_rings[4].Tick(now);
662 }
Brian Silverman2294f352019-03-02 16:31:18 -0800663
Brian Silvermand7d01102019-02-24 16:11:21 -0800664 {
665 const auto received_transfer = SpiQueue::global_instance->Tick();
666 if (received_transfer) {
667 const auto unpacked = SpiUnpackToTeensy(*received_transfer);
Brian Silverman83693e42019-03-02 15:45:52 -0800668 if (unpacked) {
669 last_roborio_camera_command = unpacked->camera_command;
670 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800671 printf("SPI decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800672 }
673 }
674 }
675
676 {
677 std::array<char, 20> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800678 packetizers[0].ParseData(uarts->cam0.Read(absl::Span<char>(buffer)));
679 packetizers[1].ParseData(uarts->cam1.Read(absl::Span<char>(buffer)));
680 packetizers[2].ParseData(uarts->cam2.Read(absl::Span<char>(buffer)));
681 packetizers[3].ParseData(uarts->cam3.Read(absl::Span<char>(buffer)));
682 packetizers[4].ParseData(uarts->cam4.Read(absl::Span<char>(buffer)));
Brian Silvermand7d01102019-02-24 16:11:21 -0800683 }
684 for (size_t i = 0; i < packetizers.size(); ++i) {
685 if (!packetizers[i].received_packet().empty()) {
686 const auto decoded =
687 UartUnpackToTeensy(packetizers[i].received_packet());
688 packetizers[i].clear_received_packet();
689 if (decoded) {
Austin Schuhf7d60c42019-03-03 20:44:02 -0800690 if (verbose) {
Brian Silverman177f0662019-03-09 15:45:02 -0800691 printf("uart frame cam %d, %d targets\n", static_cast<int>(i),
692 static_cast<int>(decoded->targets.size()));
Austin Schuhf7d60c42019-03-03 20:44:02 -0800693 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800694 frame_queue.UpdateFrame(i, *decoded);
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800695 light_rings[i].last_frame = aos::monotonic_clock::now();
696 } else {
697 printf("UART decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800698 }
699 }
700 }
701 {
702 bool made_transfer = false;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700703 const bool have_old_frames = frame_queue.HaveLatestFrames();
704 {
705 const auto new_transfer = frame_queue.MakeTransfer();
Brian Silvermand7d01102019-02-24 16:11:21 -0800706 DisableInterrupts disable_interrupts;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700707 if (!first) {
708 made_transfer =
709 !SpiQueue::global_instance->HaveTransfer(disable_interrupts);
710 }
711 // If we made a transfer just now, then new_transfer might contain
712 // duplicate targets, in which case don't use it.
713 if (!have_old_frames || !made_transfer) {
714 SpiQueue::global_instance->UpdateTransfer(new_transfer,
715 disable_interrupts);
716 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800717 }
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700718 // If we made a transfer, then make sure we aren't remembering any
719 // in-flight frames.
Brian Silvermand7d01102019-02-24 16:11:21 -0800720 if (made_transfer) {
721 frame_queue.RemoveLatestFrames();
722 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800723 }
724 {
725 const auto now = aos::monotonic_clock::now();
Brian Silvermanbac77542019-03-03 13:57:00 -0800726 CameraCommand current_camera_command = CameraCommand::kNormal;
727 if (last_roborio_camera_command != CameraCommand::kNormal) {
728 current_camera_command = last_roborio_camera_command;
729 } else {
730 current_camera_command = stdin_camera_command;
731 }
732 if (current_camera_command == CameraCommand::kUsb) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800733 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(900));
Brian Silvermanbac77542019-03-03 13:57:00 -0800734 } else if (current_camera_command == CameraCommand::kCameraPassthrough) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800735 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(500));
Brian Silvermanbac77542019-03-03 13:57:00 -0800736 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800737 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(100));
Brian Silvermanbac77542019-03-03 13:57:00 -0800738 }
739
740 if (current_camera_command == CameraCommand::kAs) {
741 for (size_t i = 0; i < transmit_buffers.size(); ++i) {
742 transmit_buffers[i].FillAs();
Brian Silverman83693e42019-03-02 15:45:52 -0800743 }
Brian Silvermanbac77542019-03-03 13:57:00 -0800744 } else {
745 if (last_camera_send + std::chrono::milliseconds(1000) < now) {
746 last_camera_send = now;
747 CameraCalibration calibration{};
748 calibration.teensy_now = aos::monotonic_clock::now();
749 calibration.realtime_now = aos::realtime_clock::min_time;
750 calibration.camera_command = current_camera_command;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800751
752 for (int i = 0; i < 5; ++i) {
753 const y2019::vision::CameraCalibration *const constants =
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800754 y2019::vision::GetCamera(y2019::vision::CameraSerialNumbers(
755 ProcessorIdentifier())[i]);
Alex Perryf3e46be2019-03-03 17:26:14 -0800756 calibration.calibration(0, 0) = constants->intrinsics.mount_angle;
757 calibration.calibration(0, 1) = constants->intrinsics.focal_length;
758 calibration.calibration(0, 2) = constants->intrinsics.barrel_mount;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800759 transmit_buffers[i].MaybeWritePacket(calibration);
760 }
Brian Silverman2294f352019-03-02 16:31:18 -0800761 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800762 }
763 for (TransmitBuffer &transmit_buffer : transmit_buffers) {
764 transmit_buffer.Tick(now);
765 }
766 }
767
Brian Silverman83693e42019-03-02 15:45:52 -0800768 {
769 const auto stdin_data = printing->ReadStdin();
770 if (!stdin_data.empty()) {
771 switch (stdin_data.back()) {
772 case 'p':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800773 printf("Sending passthrough mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800774 stdin_camera_command = CameraCommand::kCameraPassthrough;
775 break;
776 case 'u':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800777 printf("Sending USB mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800778 stdin_camera_command = CameraCommand::kUsb;
779 break;
Austin Schuh4e2629d2019-03-28 14:44:37 -0700780 case 'l':
781 printf("Log mode\n");
782 stdin_camera_command = CameraCommand::kLog;
783 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800784 case 'n':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800785 printf("Sending normal mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800786 stdin_camera_command = CameraCommand::kNormal;
787 break;
Brian Silvermanbac77542019-03-03 13:57:00 -0800788 case 'a':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800789 printf("Sending all 'a's\n");
Brian Silvermanbac77542019-03-03 13:57:00 -0800790 stdin_camera_command = CameraCommand::kAs;
791 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800792 case 'c':
793 printf("This UART board is 0x%" PRIx32 "\n", ProcessorIdentifier());
794 for (int i = 0; i < 5; ++i) {
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800795 printf(
796 "Camera slot %d's serial number is %d\n", i,
797 y2019::vision::CameraSerialNumbers(ProcessorIdentifier())[i]);
Brian Silvermana498bbb2019-03-03 17:18:04 -0800798 }
799 break;
Austin Schuhf7d60c42019-03-03 20:44:02 -0800800 case 'v':
801 printf("Toggling verbose mode\n");
802 verbose = !verbose;
803 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800804 case 'h':
805 printf("UART board commands:\n");
806 printf(" p: Send passthrough mode\n");
807 printf(" u: Send USB mode\n");
Austin Schuh4e2629d2019-03-28 14:44:37 -0700808 printf(" l: Send Log mode\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800809 printf(" n: Send normal mode\n");
810 printf(" a: Send all-'a' mode\n");
811 printf(" c: Dump camera configuration\n");
Austin Schuhf7d60c42019-03-03 20:44:02 -0800812 printf(" v: Toggle verbose print\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800813 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800814 default:
815 printf("Unrecognized character\n");
816 break;
817 }
818 }
819 }
820
Brian Silvermand7d01102019-02-24 16:11:21 -0800821 first = false;
822 }
823}
824
Brian Silverman3240e102019-02-16 18:24:24 -0800825int Main() {
826 // for background about this startup delay, please see these conversations
827 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
828 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
829 delay(400);
830
831 // Set all interrupts to the second-lowest priority to start with.
832 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
833
834 // Now set priorities for all the ones we care about. They only have meaning
835 // relative to each other, which means centralizing them here makes it a lot
836 // more manageable.
Brian Silvermand7d01102019-02-24 16:11:21 -0800837 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
838 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0x3);
839 NVIC_SET_SANE_PRIORITY(IRQ_UART1_STATUS, 0x3);
840 NVIC_SET_SANE_PRIORITY(IRQ_UART2_STATUS, 0x3);
841 NVIC_SET_SANE_PRIORITY(IRQ_UART3_STATUS, 0x3);
842 NVIC_SET_SANE_PRIORITY(IRQ_UART4_STATUS, 0x3);
843 // This one is relatively sensitive to latencies. The buffer is ~4800 clock
844 // cycles long.
845 NVIC_SET_SANE_PRIORITY(IRQ_SPI0, 0x2);
846 NVIC_SET_SANE_PRIORITY(IRQ_PORTA, 0x3);
Brian Silverman3240e102019-02-16 18:24:24 -0800847
848 // Set the LED's pin to output mode.
849 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
850 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
851
852 frc971::motors::PrintingParameters printing_parameters;
853 printing_parameters.dedicated_usb = true;
854 const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing =
855 CreatePrinting(printing_parameters);
856 printing->Initialize();
857
858 DMA.CR = M_DMA_EMLM;
859
Brian Silvermand7d01102019-02-24 16:11:21 -0800860 SIM_SCGC1 |= SIM_SCGC1_UART4;
Brian Silverman3240e102019-02-16 18:24:24 -0800861 SIM_SCGC4 |=
862 SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3;
Brian Silvermand7d01102019-02-24 16:11:21 -0800863 SIM_SCGC6 |= SIM_SCGC6_SPI0;
Brian Silverman3240e102019-02-16 18:24:24 -0800864
865 // SPI0 goes to the roboRIO.
866 // SPI0_PCS0 is SPI_CS.
Brian Silvermand7d01102019-02-24 16:11:21 -0800867 PORTD_PCR0 = PORT_PCR_MUX(2);
Brian Silverman3240e102019-02-16 18:24:24 -0800868 // SPI0_SOUT is SPI_MISO.
869 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
870 // SPI0_SIN is SPI_MOSI.
871 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2);
872 // SPI0_SCK is SPI_CLK.
873 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2);
Brian Silvermand7d01102019-02-24 16:11:21 -0800874 // SPI_CS_DRIVE
875 PERIPHERAL_BITBAND(GPIOB_PDDR, 17) = 1;
876 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
877 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(1);
878 // SPI_CS_IN
879 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 0;
880 // Set the filter width.
881 PORTA_DFWR = 31;
882 // Enable the filter.
883 PERIPHERAL_BITBAND(PORTA_DFER, 17) = 1;
884 PORTA_PCR17 =
885 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
886 // Clear the interrupt flag now that we've reconfigured it.
887 PORTA_ISFR = 1 << 17;
Brian Silverman3240e102019-02-16 18:24:24 -0800888
Brian Silverman177f0662019-03-09 15:45:02 -0800889 // For now, we have no need to dim the LEDs, so we're just going to set them
890 // all to GPIO mode for simplicity of programming.
891#if 0
Brian Silverman3240e102019-02-16 18:24:24 -0800892 // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel).
893 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
894 // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel).
895 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
896 // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel).
897 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4);
898 // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera).
899 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
900
901 // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera).
902 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3);
903 // FTM2_CH0 is LED5 (for CAM4).
904 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3);
905
906 // FTM3_CH4 is LED6 (for CAM2).
907 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3);
908 // FTM3_CH5 is LED7 (for CAM3).
909 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3);
910 // FTM3_CH6 is LED8 (for CAM1).
911 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3);
912 // FTM3_CH7 is LED9 (for CAM0).
913 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
Brian Silverman177f0662019-03-09 15:45:02 -0800914#else
915 // Set all the LED pins to GPIO.
916 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
917 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1);
918 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
919 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1);
920 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
921 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1);
922 PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1;
923 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1);
924 PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1;
925 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1);
926 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
927 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
928 PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1;
929 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
930 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
931 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
932 PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1;
933 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1);
934 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
935 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
936#endif
Brian Silverman3240e102019-02-16 18:24:24 -0800937
938 // This hardware has been deactivated, but keep this comment for now to
939 // document which pins it is on.
940#if 0
941 // This is ODROID_EN.
942 PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1;
943 PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0;
944 PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
945 // This is CAM_EN.
946 PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1;
947 PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0;
948 PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
949#endif
950 // This is 5V_PGOOD.
951 PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0;
952 PORTD_PCR6 = PORT_PCR_MUX(1);
953
954 // These go to CAM1.
Brian Silverman30adf342019-03-09 18:27:56 -0800955 // UART0_RX (peripheral) is UART1_RX (schematic) is UART1_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800956 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
957 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800958 // UART0_TX (peripheral) is UART1_TX (schematic) is UART1_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800959 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3);
960
961 // These go to CAM0.
Brian Silverman30adf342019-03-09 18:27:56 -0800962 // UART1_RX (peripheral) is UART0_RX (schematic) is UART0_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800963 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
964 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800965 // UART1_TX (peripheral) is UART0_TX (schematic) is UART0_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800966 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3);
967
968 // These go to CAM2.
Brian Silverman30adf342019-03-09 18:27:56 -0800969 // UART2_RX is UART2_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800970 PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
971 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800972 // UART2_TX is UART2_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800973 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3);
974
975 // These go to CAM3.
Brian Silverman30adf342019-03-09 18:27:56 -0800976 // UART3_RX is UART3_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800977 PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
978 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800979 // UART3_TX is UART3_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800980 PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
981
982 // These go to CAM4.
Brian Silverman30adf342019-03-09 18:27:56 -0800983 // UART4_RX is UART4_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800984 PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
985 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800986 // UART4_TX is UART4_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800987 PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3);
988
989 Uarts uarts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800990 InterruptBufferedSpi spi0{&SPI0, BUS_CLOCK_FREQUENCY};
991 global_spi_instance = &spi0;
992 SpiQueue spi_queue;
Brian Silverman3240e102019-02-16 18:24:24 -0800993
994 // Give everything a chance to get going.
995 delay(100);
996
997 printf("Ram start: %p\n", __bss_ram_start__);
998 printf("Heap start: %p\n", __heap_start__);
999 printf("Heap end: %p\n", __brkval);
1000 printf("Stack start: %p\n", __stack_end__);
1001
1002 uarts.Initialize(115200);
1003 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
1004 NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
1005 NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
1006 NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
1007 NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
Brian Silvermand7d01102019-02-24 16:11:21 -08001008 spi0.Initialize();
1009 NVIC_ENABLE_IRQ(IRQ_SPI0);
1010 NVIC_ENABLE_IRQ(IRQ_PORTA);
1011
Brian Silverman83693e42019-03-02 15:45:52 -08001012 TransferData(printing.get());
Brian Silverman3240e102019-02-16 18:24:24 -08001013
1014 while (true) {
1015 }
1016}
1017
1018extern "C" {
1019
Tyler Chatowbf0609c2021-07-31 16:13:27 -07001020int main(void) { return Main(); }
Brian Silverman3240e102019-02-16 18:24:24 -08001021
1022} // extern "C"
1023
1024} // namespace
1025} // namespace jevois
1026} // namespace frc971