blob: 541fabe880d7ee3ccccd393e619404f97acbbfe8 [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
Brian Silverman3240e102019-02-16 18:24:24 -08005#include "aos/time/time.h"
6#include "motors/core/kinetis.h"
7#include "motors/core/time.h"
8#include "motors/peripheral/configuration.h"
Brian Silvermand7d01102019-02-24 16:11:21 -08009#include "motors/peripheral/spi.h"
Brian Silverman3240e102019-02-16 18:24:24 -080010#include "motors/peripheral/uart.h"
11#include "motors/print/print.h"
12#include "motors/util.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080013#include "third_party/GSL/include/gsl/gsl"
14#include "y2019/jevois/cobs.h"
15#include "y2019/jevois/spi.h"
16#include "y2019/jevois/uart.h"
Brian Silvermana498bbb2019-03-03 17:18:04 -080017#include "y2019/vision/constants.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080018
Brian Silvermand7d01102019-02-24 16:11:21 -080019using frc971::teensy::InterruptBufferedSpi;
Tyler Chatowbf0609c2021-07-31 16:13:27 -070020using frc971::teensy::InterruptBufferedUart;
Brian Silvermand7d01102019-02-24 16:11:21 -080021
22// All indices here refer to the ports as numbered on the PCB.
Brian Silverman3240e102019-02-16 18:24:24 -080023
24namespace frc971 {
25namespace jevois {
26namespace {
27
Brian Silvermand7d01102019-02-24 16:11:21 -080028// Holds all of our hardware UARTs. There is exactly one global instance for
29// interrupt handlers to access.
Brian Silverman3240e102019-02-16 18:24:24 -080030struct Uarts {
31 Uarts() {
32 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080033 global_instance = this;
Brian Silverman3240e102019-02-16 18:24:24 -080034 }
35 ~Uarts() {
36 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -080037 global_instance = nullptr;
Brian Silverman3240e102019-02-16 18:24:24 -080038 }
Brian Silvermand7d01102019-02-24 16:11:21 -080039 Uarts(const Uarts &) = delete;
40 Uarts &operator=(const Uarts &) = delete;
Brian Silverman3240e102019-02-16 18:24:24 -080041
42 void Initialize(int baud_rate) {
43 cam0.Initialize(baud_rate);
44 cam1.Initialize(baud_rate);
45 cam2.Initialize(baud_rate);
46 cam3.Initialize(baud_rate);
47 cam4.Initialize(baud_rate);
48 }
49
Brian Silvermand7d01102019-02-24 16:11:21 -080050 InterruptBufferedUart cam0{&UART1, F_CPU};
51 InterruptBufferedUart cam1{&UART0, F_CPU};
52 InterruptBufferedUart cam2{&UART2, BUS_CLOCK_FREQUENCY};
53 InterruptBufferedUart cam3{&UART3, BUS_CLOCK_FREQUENCY};
54 InterruptBufferedUart cam4{&UART4, BUS_CLOCK_FREQUENCY};
Brian Silverman3240e102019-02-16 18:24:24 -080055
Brian Silvermand7d01102019-02-24 16:11:21 -080056 static Uarts *global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -080057};
58
Brian Silvermand7d01102019-02-24 16:11:21 -080059Uarts *Uarts::global_instance = nullptr;
60
61// Manages the transmit buffer to a single camera.
62//
63// We have to add delays between sending each byte in order for the camera to
64// successfully receive them.
65struct TransmitBuffer {
66 TransmitBuffer(InterruptBufferedUart *camera_in) : camera(camera_in) {}
67 InterruptBufferedUart *const camera;
68
69 frc971::teensy::UartBuffer<1024> buffer;
70 aos::monotonic_clock::time_point last_send = aos::monotonic_clock::min_time;
71
72 // Sends a byte to the camera if it's time.
73 void Tick(aos::monotonic_clock::time_point now) {
74 if (buffer.empty()) {
75 return;
76 }
77 if (now < last_send + std::chrono::milliseconds(1)) {
78 return;
79 }
80 last_send = now;
81 camera->Write(std::array<char, 1>{{buffer.PopSingle()}});
82 }
83
84 // Queues up another packet to send, only if the previous one has finished.
85 void MaybeWritePacket(const CameraCalibration &calibration) {
86 if (!buffer.empty()) {
87 return;
88 }
89 const auto serialized = UartPackToCamera(calibration);
90 buffer.PushSingle(0);
91 if (buffer.PushSpan(serialized) == static_cast<int>(serialized.size())) {
92 buffer.PushSingle(0);
93 }
94 }
Brian Silvermanbac77542019-03-03 13:57:00 -080095
96 void FillAs() {
97 while (!buffer.full()) {
98 buffer.PushSingle('a');
99 }
100 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800101};
102
103InterruptBufferedSpi *global_spi_instance = nullptr;
104
105// Manages queueing a transfer to send via SPI.
106class SpiQueue {
107 public:
108 SpiQueue() {
109 DisableInterrupts disable_interrupts;
110 global_instance = this;
111 }
112 ~SpiQueue() {
113 DisableInterrupts disable_interrupts;
114 global_instance = nullptr;
115 }
116 SpiQueue(const SpiQueue &) = delete;
117 SpiQueue &operator=(const SpiQueue &) = delete;
118
Austin Schuhb72be802022-01-02 12:26:28 -0800119 std::optional<absl::Span<const char>> Tick() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800120 {
121 DisableInterrupts disable_interrupts;
122 if (waiting_for_enable_ || waiting_for_disable_) {
James Kuszmaul3ae42262019-11-08 12:33:41 -0800123 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800124 }
125 }
126 const auto now = aos::monotonic_clock::now();
127 if (TransferTimedOut(now)) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700128 printf("SPI timeout with %d left\n",
129 static_cast<int>(to_receive_.size()));
Brian Silvermand7d01102019-02-24 16:11:21 -0800130 WaitForNextTransfer();
James Kuszmaul3ae42262019-11-08 12:33:41 -0800131 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800132 }
133 {
134 DisableInterrupts disable_interrupts;
135 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17) &&
136 cs_deassert_time_ == aos::monotonic_clock::max_time) {
137 cs_deassert_time_ = now;
138 }
139 }
140 if (DeassertHappened(now)) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700141 printf("CS deasserted with %d left\n",
142 static_cast<int>(to_receive_.size()));
Brian Silvermand7d01102019-02-24 16:11:21 -0800143 WaitForNextTransfer();
James Kuszmaul3ae42262019-11-08 12:33:41 -0800144 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800145 }
146 bool all_done;
147 {
148 DisableInterrupts disable_interrupts;
149 if (received_dummy_) {
150 to_receive_ = to_receive_.subspan(
151 global_spi_instance->Read(to_receive_, &disable_interrupts).size());
152 all_done = to_receive_.empty();
153 } else {
154 std::array<char, 1> dummy_data;
155 if (global_spi_instance->Read(dummy_data, &disable_interrupts).size() >=
156 1) {
157 received_dummy_ = true;
158 }
159 all_done = false;
160 }
161 }
162 if (all_done) {
163 WaitForNextTransfer();
164 return received_transfer_;
165 }
James Kuszmaul3ae42262019-11-08 12:33:41 -0800166 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800167 }
168
169 void HandleInterrupt() {
170 DisableInterrupts disable_interrupts;
171 if (waiting_for_disable_) {
172 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
173 PORTA_PCR17 =
174 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
175 // Clear the interrupt flag now that we've reconfigured it.
176 PORTA_ISFR = 1 << 17;
177 waiting_for_disable_ = false;
178 } else {
179 // Clear the interrupt flag. It shouldn't trigger again immediately
180 // because the pin is still asserted.
181 PORTA_ISFR = 1 << 17;
182 }
183 return;
184 }
185 if (waiting_for_enable_) {
186 if (PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
187 global_spi_instance->ClearQueues(disable_interrupts);
188 // Tell the SPI peripheral its CS is asserted.
189 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 0;
190 // Disable interrupts on the enable pin. We'll re-enable once we finish
191 // the transfer.
192 PORTA_PCR17 = PORT_PCR_MUX(1);
193 // Clear the interrupt flag now that we've reconfigured it.
194 PORTA_ISFR = 1 << 17;
195 if (have_transfer_) {
196 global_spi_instance->Write(transfer_, &disable_interrupts);
197 have_transfer_ = false;
198 } else {
199 printf("Writing dummy SPI frame\n");
200 // If we don't have anything, just write 0s to avoid getting the
201 // hardware confused.
202 global_spi_instance->Write(SpiTransfer{}, &disable_interrupts);
203 }
204 // Queue up a dummy byte at the end. This won't actually be sent,
205 // because the first byte we do send will be garbage, but it will
206 // synchronize our queues so we receive all the useful data bytes.
207 global_spi_instance->Write(std::array<char, 1>(), &disable_interrupts);
208 waiting_for_enable_ = false;
209 receive_start_ = aos::monotonic_clock::now();
210 cs_deassert_time_ = aos::monotonic_clock::max_time;
211 // To make debugging easier.
212 received_transfer_.fill(0);
213 } else {
214 // Clear the interrupt flag. It shouldn't trigger again immediately
215 // because the pin is still asserted.
216 PORTA_ISFR = 1 << 17;
217 }
218 return;
219 }
220 // We shouldn't ever get here. Clear all the flags and hope they don't get
221 // re-asserted immediately.
222 PORTA_ISFR = UINT32_C(0xFFFFFFFF);
223 }
224
225 void UpdateTransfer(const SpiTransfer &transfer, const DisableInterrupts &) {
226 have_transfer_ = true;
227 transfer_ = transfer;
228 }
229
230 // Returns whether a transfer is currently queued. This will be true between a
231 // call to UpdateTransfer and that transfer actually being moved out to the
232 // hardware.
233 bool HaveTransfer(const DisableInterrupts &) const { return have_transfer_; }
234
235 static SpiQueue *global_instance;
236
237 private:
238 void WaitForNextTransfer() {
Austin Schuhb72be802022-01-02 12:26:28 -0800239 to_receive_ = absl::Span<char>(received_transfer_);
Brian Silvermand7d01102019-02-24 16:11:21 -0800240 received_dummy_ = false;
241 {
242 DisableInterrupts disable_interrupts;
243 waiting_for_enable_ = true;
244 waiting_for_disable_ = true;
245 PORTA_PCR17 =
246 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0x8) /* Interrupt when logic 0 */;
247 // Clear the interrupt flag now that we've reconfigured it.
248 PORTA_ISFR = 1 << 17;
249 }
250 // Tell the SPI peripheral its CS is de-asserted.
251 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
252 }
253
254 bool TransferTimedOut(aos::monotonic_clock::time_point now) {
255 DisableInterrupts disable_interrupts;
256 // TODO: Revise this timeout.
257 return now - std::chrono::milliseconds(50) > receive_start_;
258 }
259
260 bool DeassertHappened(aos::monotonic_clock::time_point now) {
261 DisableInterrupts disable_interrupts;
262 return now - std::chrono::microseconds(50) > cs_deassert_time_;
263 }
264
265 bool waiting_for_enable_ = true;
266 bool waiting_for_disable_ = false;
267 bool have_transfer_ = false;
268 SpiTransfer transfer_;
269 bool received_dummy_ = false;
270 SpiTransfer received_transfer_;
Austin Schuhb72be802022-01-02 12:26:28 -0800271 absl::Span<char> to_receive_{received_transfer_};
Brian Silvermand7d01102019-02-24 16:11:21 -0800272 aos::monotonic_clock::time_point receive_start_;
273 aos::monotonic_clock::time_point cs_deassert_time_;
274};
275
276SpiQueue *SpiQueue::global_instance = nullptr;
277
278// All methods here must be fully synchronized by the caller.
279class FrameQueue {
280 public:
281 FrameQueue() = default;
282 FrameQueue(const FrameQueue &) = delete;
283 FrameQueue &operator=(const FrameQueue &) = delete;
284
Brian Silvermanc41fb862019-03-02 21:14:46 -0800285 void UpdateFrame(int camera, const CameraFrame &frame) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800286 frames_[camera].targets = frame.targets;
287 frames_[camera].capture_time = aos::monotonic_clock::now() - frame.age;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800288 frames_[camera].camera_index = camera;
Brian Silvermand7d01102019-02-24 16:11:21 -0800289 const aos::SizedArray<int, 3> old_last_frames = last_frames_;
290 last_frames_.clear();
291 for (int index : old_last_frames) {
292 if (index != camera) {
293 last_frames_.push_back(index);
294 }
295 }
296 }
297
298 // Creates and returns a transfer with all the current information.
299 //
300 // This does not actually record these frames as transferred until
301 // RemoveLatestFrames() is called.
302 SpiTransfer MakeTransfer();
303
304 // Records the frames represented in the result of the latest MakeTransfer()
305 // call as being transferred, so they will not be represented in subsequent
306 // MakeTransfer() calls.
307 void RemoveLatestFrames() {
308 for (int index : last_frames_) {
309 frames_[index].capture_time = aos::monotonic_clock::min_time;
310 }
311 last_frames_.clear();
312 }
313
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700314 bool HaveLatestFrames() const { return !last_frames_.empty(); }
315
Brian Silvermand7d01102019-02-24 16:11:21 -0800316 private:
317 struct FrameData {
318 aos::SizedArray<Target, 3> targets;
319 aos::monotonic_clock::time_point capture_time =
320 aos::monotonic_clock::min_time;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800321 int camera_index;
Brian Silvermand7d01102019-02-24 16:11:21 -0800322 };
323
324 std::array<FrameData, 5> frames_;
325 // The indices into frames_ which we returned in the last MakeTransfer() call.
326 aos::SizedArray<int, 3> last_frames_;
327};
328
329SpiTransfer FrameQueue::MakeTransfer() {
330 aos::SizedArray<int, 5> oldest_indices;
331 for (size_t i = 0; i < frames_.size(); ++i) {
332 if (frames_[i].capture_time != aos::monotonic_clock::min_time) {
333 oldest_indices.push_back(i);
334 }
335 }
336 std::sort(oldest_indices.begin(), oldest_indices.end(), [this](int a, int b) {
337 return frames_[a].capture_time < frames_[b].capture_time;
338 });
339
340 TeensyToRoborio message;
341 last_frames_.clear();
342 for (int i = 0; i < std::min<int>(oldest_indices.size(), 3); ++i) {
343 const int index = oldest_indices[i];
344 const FrameData &frame = frames_[index];
345 const auto age = aos::monotonic_clock::now() - frame.capture_time;
Austin Schuhb72be802022-01-02 12:26:28 -0800346 const auto rounded_age = std::chrono::round<camera_duration>(age);
Brian Silvermanc41fb862019-03-02 21:14:46 -0800347 message.frames.push_back({frame.targets, rounded_age, frame.camera_index});
Brian Silvermand7d01102019-02-24 16:11:21 -0800348 last_frames_.push_back(index);
349 }
350 return SpiPackToRoborio(message);
351}
Brian Silverman3240e102019-02-16 18:24:24 -0800352
Brian Silverman2294f352019-03-02 16:31:18 -0800353// Manages turning the debug light on and off periodically.
354//
355// It blinks at 1Hz with a variable duty cycle.
356class DebugLight {
357 public:
358 static constexpr aos::monotonic_clock::duration period() {
359 return std::chrono::seconds(1);
360 }
361
362 void set_next_off_time(aos::monotonic_clock::duration next_off_time) {
363 next_off_time_ = next_off_time;
364 }
365
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800366 bool Tick(aos::monotonic_clock::time_point now) {
Brian Silverman2294f352019-03-02 16:31:18 -0800367 if (last_cycle_start_ == aos::monotonic_clock::min_time) {
368 last_cycle_start_ = now;
369 current_off_point_ = last_cycle_start_ + next_off_time_;
370 } else if (now > last_cycle_start_ + period()) {
371 last_cycle_start_ += period();
372 current_off_point_ = last_cycle_start_ + next_off_time_;
373 }
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800374 return now > current_off_point_;
Brian Silverman2294f352019-03-02 16:31:18 -0800375 }
376
377 private:
378 aos::monotonic_clock::time_point last_cycle_start_ =
379 aos::monotonic_clock::min_time;
380
Brian Silvermanbac77542019-03-03 13:57:00 -0800381 aos::monotonic_clock::duration next_off_time_ =
382 std::chrono::milliseconds(100);
Brian Silverman2294f352019-03-02 16:31:18 -0800383 aos::monotonic_clock::time_point current_off_point_ =
384 aos::monotonic_clock::min_time;
385};
386
Brian Silvermana498bbb2019-03-03 17:18:04 -0800387// Returns an identifier for the processor we're running on.
388uint32_t ProcessorIdentifier() {
389 uint32_t r = 0;
390 r |= SIM_UIDH << 24;
391 r |= SIM_UIDMH << 16;
392 r |= SIM_UIDML << 8;
393 r |= SIM_UIDL << 0;
394 return r;
395}
396
Brian Silverman3240e102019-02-16 18:24:24 -0800397extern "C" {
398
399void *__stack_chk_guard = (void *)0x67111971;
400void __stack_chk_fail(void) {
401 while (true) {
402 GPIOC_PSOR = (1 << 5);
403 printf("Stack corruption detected\n");
404 delay(1000);
405 GPIOC_PCOR = (1 << 5);
406 delay(1000);
407 }
408}
409
410extern char *__brkval;
411extern uint32_t __bss_ram_start__[];
412extern uint32_t __heap_start__[];
413extern uint32_t __stack_end__[];
414
415void uart0_status_isr(void) {
416 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800417 Uarts::global_instance->cam1.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800418}
419
420void uart1_status_isr(void) {
421 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800422 Uarts::global_instance->cam0.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800423}
424
425void uart2_status_isr(void) {
426 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800427 Uarts::global_instance->cam2.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800428}
429
430void uart3_status_isr(void) {
431 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800432 Uarts::global_instance->cam3.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800433}
434
435void uart4_status_isr(void) {
436 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800437 Uarts::global_instance->cam4.HandleInterrupt(disable_interrupts);
438}
439
440void spi0_isr(void) {
441 DisableInterrupts disable_interrupts;
442 global_spi_instance->HandleInterrupt(disable_interrupts);
443}
444
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700445void porta_isr(void) { SpiQueue::global_instance->HandleInterrupt(); }
Brian Silverman3240e102019-02-16 18:24:24 -0800446
447} // extern "C"
448
449// A test program which echos characters back after adding a per-UART offset to
450// them (CAM0 adds 1, CAM1 adds 2, etc).
451__attribute__((unused)) void TestUarts() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800452 Uarts *const uarts = Uarts::global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -0800453 while (true) {
454 {
455 std::array<char, 10> buffer;
456 const auto data = uarts->cam0.Read(buffer);
457 for (int i = 0; i < data.size(); ++i) {
458 data[i] += 1;
459 }
460 uarts->cam0.Write(data);
461 }
462 {
463 std::array<char, 10> buffer;
464 const auto data = uarts->cam1.Read(buffer);
465 for (int i = 0; i < data.size(); ++i) {
466 data[i] += 2;
467 }
468 uarts->cam1.Write(data);
469 }
470 {
471 std::array<char, 10> buffer;
472 const auto data = uarts->cam2.Read(buffer);
473 for (int i = 0; i < data.size(); ++i) {
474 data[i] += 3;
475 }
476 uarts->cam2.Write(data);
477 }
478 {
479 std::array<char, 10> buffer;
480 const auto data = uarts->cam3.Read(buffer);
481 for (int i = 0; i < data.size(); ++i) {
482 data[i] += 4;
483 }
484 uarts->cam3.Write(data);
485 }
486 {
487 std::array<char, 10> buffer;
488 const auto data = uarts->cam4.Read(buffer);
489 for (int i = 0; i < data.size(); ++i) {
490 data[i] += 5;
491 }
492 uarts->cam4.Write(data);
493 }
494 }
495}
496
497// Tests all the I/O pins. Cycles through each one for 1 second. While active,
498// each output is turned on, and each input has its value printed.
499__attribute__((unused)) void TestIo() {
500 // Set SPI0 pins to GPIO.
501 // SPI_OUT
502 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
503 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1);
504 // SPI_CS
505 PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0;
506 PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
507 // SPI_IN
508 PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0;
509 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
510 // SPI_SCK
511 PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0;
512 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
513
Brian Silverman3240e102019-02-16 18:24:24 -0800514 auto next = aos::monotonic_clock::now();
515 static constexpr auto kTick = std::chrono::seconds(1);
516 while (true) {
517 printf("SPI_MISO\n");
518 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
519 while (aos::monotonic_clock::now() < next + kTick) {
520 }
521 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
522 next += kTick;
523
524 while (aos::monotonic_clock::now() < next + kTick) {
525 printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0));
526 }
527 next += kTick;
528
529 while (aos::monotonic_clock::now() < next + kTick) {
530 printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7));
531 }
532 next += kTick;
533
534 while (aos::monotonic_clock::now() < next + kTick) {
535 printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1));
536 }
537 next += kTick;
538
539 printf("CAM0\n");
540 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
541 while (aos::monotonic_clock::now() < next + kTick) {
542 }
543 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
544 next += kTick;
545
546 printf("CAM1\n");
547 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
548 while (aos::monotonic_clock::now() < next + kTick) {
549 }
550 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
551 next += kTick;
552
553 printf("CAM2\n");
554 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
555 while (aos::monotonic_clock::now() < next + kTick) {
556 }
557 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0;
558 next += kTick;
559
560 printf("CAM3\n");
561 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1;
562 while (aos::monotonic_clock::now() < next + kTick) {
563 }
564 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0;
565 next += kTick;
566
567 printf("CAM4\n");
568 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1;
569 while (aos::monotonic_clock::now() < next + kTick) {
570 }
571 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0;
572 next += kTick;
573
574 printf("CAM5\n");
575 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1;
576 while (aos::monotonic_clock::now() < next + kTick) {
577 }
578 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0;
579 next += kTick;
580
581 printf("CAM6\n");
582 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1;
583 while (aos::monotonic_clock::now() < next + kTick) {
584 }
585 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0;
586 next += kTick;
587
588 printf("CAM7\n");
589 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1;
590 while (aos::monotonic_clock::now() < next + kTick) {
591 }
592 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0;
593 next += kTick;
594
595 printf("CAM8\n");
596 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1;
597 while (aos::monotonic_clock::now() < next + kTick) {
598 }
599 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0;
600 next += kTick;
601
602 printf("CAM9\n");
603 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1;
604 while (aos::monotonic_clock::now() < next + kTick) {
605 }
606 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0;
607 next += kTick;
608 }
609}
610
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800611struct LightRingState {
612 DebugLight debug_light;
613 aos::monotonic_clock::time_point last_frame = aos::monotonic_clock::max_time;
614
615 bool Tick(aos::monotonic_clock::time_point now) {
616 if (last_frame == aos::monotonic_clock::max_time) {
617 last_frame = now;
618 }
619 if (now > last_frame + std::chrono::seconds(1)) {
620 debug_light.set_next_off_time(std::chrono::milliseconds(500));
621 } else {
622 debug_light.set_next_off_time(std::chrono::seconds(0));
623 }
624 return debug_light.Tick(now);
625 }
626};
627
Brian Silvermand7d01102019-02-24 16:11:21 -0800628// Does the normal work of transferring data in all directions.
629//
630// https://community.nxp.com/thread/466937#comment-983881 is a post from NXP
631// claiming that it's impossible to queue up the first byte for the slave end of
632// an SPI connection properly. Instead, we just accept there will be a garbage
633// byte and the other end ignores it.
Brian Silverman83693e42019-03-02 15:45:52 -0800634__attribute__((unused)) void TransferData(
635 frc971::motors::PrintingImplementation *printing) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800636 Uarts *const uarts = Uarts::global_instance;
637 std::array<CobsPacketizer<uart_to_teensy_size()>, 5> packetizers;
638 std::array<TransmitBuffer, 5> transmit_buffers{
639 {&uarts->cam0, &uarts->cam1, &uarts->cam2, &uarts->cam3, &uarts->cam4}};
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800640 std::array<LightRingState, 5> light_rings;
Brian Silvermand7d01102019-02-24 16:11:21 -0800641 FrameQueue frame_queue;
642 aos::monotonic_clock::time_point last_camera_send =
643 aos::monotonic_clock::min_time;
Brian Silverman83693e42019-03-02 15:45:52 -0800644 CameraCommand stdin_camera_command = CameraCommand::kNormal;
645 CameraCommand last_roborio_camera_command = CameraCommand::kNormal;
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800646 DebugLight teensy_debug_light;
Brian Silverman83693e42019-03-02 15:45:52 -0800647
Austin Schuhf7d60c42019-03-03 20:44:02 -0800648 bool verbose = false;
649
Brian Silvermand7d01102019-02-24 16:11:21 -0800650 bool first = true;
651 while (true) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800652 {
653 const auto now = aos::monotonic_clock::now();
654 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = !teensy_debug_light.Tick(now);
655 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = light_rings[0].Tick(now);
656 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = light_rings[1].Tick(now);
657 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = light_rings[2].Tick(now);
658 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = light_rings[3].Tick(now);
659 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = light_rings[4].Tick(now);
660 }
Brian Silverman2294f352019-03-02 16:31:18 -0800661
Brian Silvermand7d01102019-02-24 16:11:21 -0800662 {
663 const auto received_transfer = SpiQueue::global_instance->Tick();
664 if (received_transfer) {
665 const auto unpacked = SpiUnpackToTeensy(*received_transfer);
Brian Silverman83693e42019-03-02 15:45:52 -0800666 if (unpacked) {
667 last_roborio_camera_command = unpacked->camera_command;
668 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800669 printf("SPI decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800670 }
671 }
672 }
673
674 {
675 std::array<char, 20> buffer;
676 packetizers[0].ParseData(uarts->cam0.Read(buffer));
677 packetizers[1].ParseData(uarts->cam1.Read(buffer));
678 packetizers[2].ParseData(uarts->cam2.Read(buffer));
679 packetizers[3].ParseData(uarts->cam3.Read(buffer));
680 packetizers[4].ParseData(uarts->cam4.Read(buffer));
681 }
682 for (size_t i = 0; i < packetizers.size(); ++i) {
683 if (!packetizers[i].received_packet().empty()) {
684 const auto decoded =
685 UartUnpackToTeensy(packetizers[i].received_packet());
686 packetizers[i].clear_received_packet();
687 if (decoded) {
Austin Schuhf7d60c42019-03-03 20:44:02 -0800688 if (verbose) {
Brian Silverman177f0662019-03-09 15:45:02 -0800689 printf("uart frame cam %d, %d targets\n", static_cast<int>(i),
690 static_cast<int>(decoded->targets.size()));
Austin Schuhf7d60c42019-03-03 20:44:02 -0800691 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800692 frame_queue.UpdateFrame(i, *decoded);
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800693 light_rings[i].last_frame = aos::monotonic_clock::now();
694 } else {
695 printf("UART decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800696 }
697 }
698 }
699 {
700 bool made_transfer = false;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700701 const bool have_old_frames = frame_queue.HaveLatestFrames();
702 {
703 const auto new_transfer = frame_queue.MakeTransfer();
Brian Silvermand7d01102019-02-24 16:11:21 -0800704 DisableInterrupts disable_interrupts;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700705 if (!first) {
706 made_transfer =
707 !SpiQueue::global_instance->HaveTransfer(disable_interrupts);
708 }
709 // If we made a transfer just now, then new_transfer might contain
710 // duplicate targets, in which case don't use it.
711 if (!have_old_frames || !made_transfer) {
712 SpiQueue::global_instance->UpdateTransfer(new_transfer,
713 disable_interrupts);
714 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800715 }
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700716 // If we made a transfer, then make sure we aren't remembering any
717 // in-flight frames.
Brian Silvermand7d01102019-02-24 16:11:21 -0800718 if (made_transfer) {
719 frame_queue.RemoveLatestFrames();
720 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800721 }
722 {
723 const auto now = aos::monotonic_clock::now();
Brian Silvermanbac77542019-03-03 13:57:00 -0800724 CameraCommand current_camera_command = CameraCommand::kNormal;
725 if (last_roborio_camera_command != CameraCommand::kNormal) {
726 current_camera_command = last_roborio_camera_command;
727 } else {
728 current_camera_command = stdin_camera_command;
729 }
730 if (current_camera_command == CameraCommand::kUsb) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800731 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(900));
Brian Silvermanbac77542019-03-03 13:57:00 -0800732 } else if (current_camera_command == CameraCommand::kCameraPassthrough) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800733 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(500));
Brian Silvermanbac77542019-03-03 13:57:00 -0800734 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800735 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(100));
Brian Silvermanbac77542019-03-03 13:57:00 -0800736 }
737
738 if (current_camera_command == CameraCommand::kAs) {
739 for (size_t i = 0; i < transmit_buffers.size(); ++i) {
740 transmit_buffers[i].FillAs();
Brian Silverman83693e42019-03-02 15:45:52 -0800741 }
Brian Silvermanbac77542019-03-03 13:57:00 -0800742 } else {
743 if (last_camera_send + std::chrono::milliseconds(1000) < now) {
744 last_camera_send = now;
745 CameraCalibration calibration{};
746 calibration.teensy_now = aos::monotonic_clock::now();
747 calibration.realtime_now = aos::realtime_clock::min_time;
748 calibration.camera_command = current_camera_command;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800749
750 for (int i = 0; i < 5; ++i) {
751 const y2019::vision::CameraCalibration *const constants =
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800752 y2019::vision::GetCamera(y2019::vision::CameraSerialNumbers(
753 ProcessorIdentifier())[i]);
Alex Perryf3e46be2019-03-03 17:26:14 -0800754 calibration.calibration(0, 0) = constants->intrinsics.mount_angle;
755 calibration.calibration(0, 1) = constants->intrinsics.focal_length;
756 calibration.calibration(0, 2) = constants->intrinsics.barrel_mount;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800757 transmit_buffers[i].MaybeWritePacket(calibration);
758 }
Brian Silverman2294f352019-03-02 16:31:18 -0800759 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800760 }
761 for (TransmitBuffer &transmit_buffer : transmit_buffers) {
762 transmit_buffer.Tick(now);
763 }
764 }
765
Brian Silverman83693e42019-03-02 15:45:52 -0800766 {
767 const auto stdin_data = printing->ReadStdin();
768 if (!stdin_data.empty()) {
769 switch (stdin_data.back()) {
770 case 'p':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800771 printf("Sending passthrough mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800772 stdin_camera_command = CameraCommand::kCameraPassthrough;
773 break;
774 case 'u':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800775 printf("Sending USB mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800776 stdin_camera_command = CameraCommand::kUsb;
777 break;
Austin Schuh4e2629d2019-03-28 14:44:37 -0700778 case 'l':
779 printf("Log mode\n");
780 stdin_camera_command = CameraCommand::kLog;
781 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800782 case 'n':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800783 printf("Sending normal mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800784 stdin_camera_command = CameraCommand::kNormal;
785 break;
Brian Silvermanbac77542019-03-03 13:57:00 -0800786 case 'a':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800787 printf("Sending all 'a's\n");
Brian Silvermanbac77542019-03-03 13:57:00 -0800788 stdin_camera_command = CameraCommand::kAs;
789 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800790 case 'c':
791 printf("This UART board is 0x%" PRIx32 "\n", ProcessorIdentifier());
792 for (int i = 0; i < 5; ++i) {
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800793 printf(
794 "Camera slot %d's serial number is %d\n", i,
795 y2019::vision::CameraSerialNumbers(ProcessorIdentifier())[i]);
Brian Silvermana498bbb2019-03-03 17:18:04 -0800796 }
797 break;
Austin Schuhf7d60c42019-03-03 20:44:02 -0800798 case 'v':
799 printf("Toggling verbose mode\n");
800 verbose = !verbose;
801 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800802 case 'h':
803 printf("UART board commands:\n");
804 printf(" p: Send passthrough mode\n");
805 printf(" u: Send USB mode\n");
Austin Schuh4e2629d2019-03-28 14:44:37 -0700806 printf(" l: Send Log mode\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800807 printf(" n: Send normal mode\n");
808 printf(" a: Send all-'a' mode\n");
809 printf(" c: Dump camera configuration\n");
Austin Schuhf7d60c42019-03-03 20:44:02 -0800810 printf(" v: Toggle verbose print\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800811 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800812 default:
813 printf("Unrecognized character\n");
814 break;
815 }
816 }
817 }
818
Brian Silvermand7d01102019-02-24 16:11:21 -0800819 first = false;
820 }
821}
822
Brian Silverman3240e102019-02-16 18:24:24 -0800823int Main() {
824 // for background about this startup delay, please see these conversations
825 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
826 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
827 delay(400);
828
829 // Set all interrupts to the second-lowest priority to start with.
830 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
831
832 // Now set priorities for all the ones we care about. They only have meaning
833 // relative to each other, which means centralizing them here makes it a lot
834 // more manageable.
Brian Silvermand7d01102019-02-24 16:11:21 -0800835 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
836 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0x3);
837 NVIC_SET_SANE_PRIORITY(IRQ_UART1_STATUS, 0x3);
838 NVIC_SET_SANE_PRIORITY(IRQ_UART2_STATUS, 0x3);
839 NVIC_SET_SANE_PRIORITY(IRQ_UART3_STATUS, 0x3);
840 NVIC_SET_SANE_PRIORITY(IRQ_UART4_STATUS, 0x3);
841 // This one is relatively sensitive to latencies. The buffer is ~4800 clock
842 // cycles long.
843 NVIC_SET_SANE_PRIORITY(IRQ_SPI0, 0x2);
844 NVIC_SET_SANE_PRIORITY(IRQ_PORTA, 0x3);
Brian Silverman3240e102019-02-16 18:24:24 -0800845
846 // Set the LED's pin to output mode.
847 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
848 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
849
850 frc971::motors::PrintingParameters printing_parameters;
851 printing_parameters.dedicated_usb = true;
852 const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing =
853 CreatePrinting(printing_parameters);
854 printing->Initialize();
855
856 DMA.CR = M_DMA_EMLM;
857
Brian Silvermand7d01102019-02-24 16:11:21 -0800858 SIM_SCGC1 |= SIM_SCGC1_UART4;
Brian Silverman3240e102019-02-16 18:24:24 -0800859 SIM_SCGC4 |=
860 SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3;
Brian Silvermand7d01102019-02-24 16:11:21 -0800861 SIM_SCGC6 |= SIM_SCGC6_SPI0;
Brian Silverman3240e102019-02-16 18:24:24 -0800862
863 // SPI0 goes to the roboRIO.
864 // SPI0_PCS0 is SPI_CS.
Brian Silvermand7d01102019-02-24 16:11:21 -0800865 PORTD_PCR0 = PORT_PCR_MUX(2);
Brian Silverman3240e102019-02-16 18:24:24 -0800866 // SPI0_SOUT is SPI_MISO.
867 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
868 // SPI0_SIN is SPI_MOSI.
869 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2);
870 // SPI0_SCK is SPI_CLK.
871 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2);
Brian Silvermand7d01102019-02-24 16:11:21 -0800872 // SPI_CS_DRIVE
873 PERIPHERAL_BITBAND(GPIOB_PDDR, 17) = 1;
874 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
875 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(1);
876 // SPI_CS_IN
877 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 0;
878 // Set the filter width.
879 PORTA_DFWR = 31;
880 // Enable the filter.
881 PERIPHERAL_BITBAND(PORTA_DFER, 17) = 1;
882 PORTA_PCR17 =
883 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
884 // Clear the interrupt flag now that we've reconfigured it.
885 PORTA_ISFR = 1 << 17;
Brian Silverman3240e102019-02-16 18:24:24 -0800886
Brian Silverman177f0662019-03-09 15:45:02 -0800887 // For now, we have no need to dim the LEDs, so we're just going to set them
888 // all to GPIO mode for simplicity of programming.
889#if 0
Brian Silverman3240e102019-02-16 18:24:24 -0800890 // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel).
891 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
892 // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel).
893 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
894 // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel).
895 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4);
896 // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera).
897 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
898
899 // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera).
900 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3);
901 // FTM2_CH0 is LED5 (for CAM4).
902 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3);
903
904 // FTM3_CH4 is LED6 (for CAM2).
905 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3);
906 // FTM3_CH5 is LED7 (for CAM3).
907 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3);
908 // FTM3_CH6 is LED8 (for CAM1).
909 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3);
910 // FTM3_CH7 is LED9 (for CAM0).
911 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
Brian Silverman177f0662019-03-09 15:45:02 -0800912#else
913 // Set all the LED pins to GPIO.
914 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
915 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1);
916 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
917 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1);
918 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
919 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1);
920 PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1;
921 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1);
922 PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1;
923 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1);
924 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
925 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
926 PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1;
927 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
928 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
929 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
930 PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1;
931 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1);
932 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
933 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
934#endif
Brian Silverman3240e102019-02-16 18:24:24 -0800935
936 // This hardware has been deactivated, but keep this comment for now to
937 // document which pins it is on.
938#if 0
939 // This is ODROID_EN.
940 PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1;
941 PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0;
942 PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
943 // This is CAM_EN.
944 PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1;
945 PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0;
946 PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
947#endif
948 // This is 5V_PGOOD.
949 PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0;
950 PORTD_PCR6 = PORT_PCR_MUX(1);
951
952 // These go to CAM1.
Brian Silverman30adf342019-03-09 18:27:56 -0800953 // UART0_RX (peripheral) is UART1_RX (schematic) is UART1_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800954 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
955 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800956 // UART0_TX (peripheral) is UART1_TX (schematic) is UART1_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800957 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3);
958
959 // These go to CAM0.
Brian Silverman30adf342019-03-09 18:27:56 -0800960 // UART1_RX (peripheral) is UART0_RX (schematic) is UART0_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800961 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
962 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800963 // UART1_TX (peripheral) is UART0_TX (schematic) is UART0_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800964 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3);
965
966 // These go to CAM2.
Brian Silverman30adf342019-03-09 18:27:56 -0800967 // UART2_RX is UART2_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800968 PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
969 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800970 // UART2_TX is UART2_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800971 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3);
972
973 // These go to CAM3.
Brian Silverman30adf342019-03-09 18:27:56 -0800974 // UART3_RX is UART3_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800975 PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
976 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800977 // UART3_TX is UART3_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800978 PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
979
980 // These go to CAM4.
Brian Silverman30adf342019-03-09 18:27:56 -0800981 // UART4_RX is UART4_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800982 PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
983 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800984 // UART4_TX is UART4_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800985 PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3);
986
987 Uarts uarts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800988 InterruptBufferedSpi spi0{&SPI0, BUS_CLOCK_FREQUENCY};
989 global_spi_instance = &spi0;
990 SpiQueue spi_queue;
Brian Silverman3240e102019-02-16 18:24:24 -0800991
992 // Give everything a chance to get going.
993 delay(100);
994
995 printf("Ram start: %p\n", __bss_ram_start__);
996 printf("Heap start: %p\n", __heap_start__);
997 printf("Heap end: %p\n", __brkval);
998 printf("Stack start: %p\n", __stack_end__);
999
1000 uarts.Initialize(115200);
1001 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
1002 NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
1003 NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
1004 NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
1005 NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
Brian Silvermand7d01102019-02-24 16:11:21 -08001006 spi0.Initialize();
1007 NVIC_ENABLE_IRQ(IRQ_SPI0);
1008 NVIC_ENABLE_IRQ(IRQ_PORTA);
1009
Brian Silverman83693e42019-03-02 15:45:52 -08001010 TransferData(printing.get());
Brian Silverman3240e102019-02-16 18:24:24 -08001011
1012 while (true) {
1013 }
1014}
1015
1016extern "C" {
1017
Tyler Chatowbf0609c2021-07-31 16:13:27 -07001018int main(void) { return Main(); }
Brian Silverman3240e102019-02-16 18:24:24 -08001019
1020} // extern "C"
1021
1022} // namespace
1023} // namespace jevois
1024} // namespace frc971