blob: 95fe18605367650466e3ab22b91ea5799c48be1f [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"
Brian Silverman3240e102019-02-16 18:24:24 -08006#include "aos/time/time.h"
7#include "motors/core/kinetis.h"
8#include "motors/core/time.h"
9#include "motors/peripheral/configuration.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080010#include "motors/peripheral/spi.h"
Brian Silverman3240e102019-02-16 18:24:24 -080011#include "motors/peripheral/uart.h"
12#include "motors/print/print.h"
13#include "motors/util.h"
Brian Silvermand7d01102019-02-24 16:11:21 -080014#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;
Austin Schuh7fe04492022-01-02 13:37:21 -0800155 if (global_spi_instance
156 ->Read(absl::Span<char>(dummy_data), &disable_interrupts)
157 .size() >= 1) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800158 received_dummy_ = true;
159 }
160 all_done = false;
161 }
162 }
163 if (all_done) {
164 WaitForNextTransfer();
165 return received_transfer_;
166 }
James Kuszmaul3ae42262019-11-08 12:33:41 -0800167 return std::nullopt;
Brian Silvermand7d01102019-02-24 16:11:21 -0800168 }
169
170 void HandleInterrupt() {
171 DisableInterrupts disable_interrupts;
172 if (waiting_for_disable_) {
173 if (!PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
174 PORTA_PCR17 =
175 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
176 // Clear the interrupt flag now that we've reconfigured it.
177 PORTA_ISFR = 1 << 17;
178 waiting_for_disable_ = false;
179 } else {
180 // Clear the interrupt flag. It shouldn't trigger again immediately
181 // because the pin is still asserted.
182 PORTA_ISFR = 1 << 17;
183 }
184 return;
185 }
186 if (waiting_for_enable_) {
187 if (PERIPHERAL_BITBAND(GPIOA_PDIR, 17)) {
188 global_spi_instance->ClearQueues(disable_interrupts);
189 // Tell the SPI peripheral its CS is asserted.
190 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 0;
191 // Disable interrupts on the enable pin. We'll re-enable once we finish
192 // the transfer.
193 PORTA_PCR17 = PORT_PCR_MUX(1);
194 // Clear the interrupt flag now that we've reconfigured it.
195 PORTA_ISFR = 1 << 17;
196 if (have_transfer_) {
197 global_spi_instance->Write(transfer_, &disable_interrupts);
198 have_transfer_ = false;
199 } else {
200 printf("Writing dummy SPI frame\n");
201 // If we don't have anything, just write 0s to avoid getting the
202 // hardware confused.
203 global_spi_instance->Write(SpiTransfer{}, &disable_interrupts);
204 }
205 // Queue up a dummy byte at the end. This won't actually be sent,
206 // because the first byte we do send will be garbage, but it will
207 // synchronize our queues so we receive all the useful data bytes.
208 global_spi_instance->Write(std::array<char, 1>(), &disable_interrupts);
209 waiting_for_enable_ = false;
210 receive_start_ = aos::monotonic_clock::now();
211 cs_deassert_time_ = aos::monotonic_clock::max_time;
212 // To make debugging easier.
213 received_transfer_.fill(0);
214 } else {
215 // Clear the interrupt flag. It shouldn't trigger again immediately
216 // because the pin is still asserted.
217 PORTA_ISFR = 1 << 17;
218 }
219 return;
220 }
221 // We shouldn't ever get here. Clear all the flags and hope they don't get
222 // re-asserted immediately.
223 PORTA_ISFR = UINT32_C(0xFFFFFFFF);
224 }
225
226 void UpdateTransfer(const SpiTransfer &transfer, const DisableInterrupts &) {
227 have_transfer_ = true;
228 transfer_ = transfer;
229 }
230
231 // Returns whether a transfer is currently queued. This will be true between a
232 // call to UpdateTransfer and that transfer actually being moved out to the
233 // hardware.
234 bool HaveTransfer(const DisableInterrupts &) const { return have_transfer_; }
235
236 static SpiQueue *global_instance;
237
238 private:
239 void WaitForNextTransfer() {
Austin Schuhb72be802022-01-02 12:26:28 -0800240 to_receive_ = absl::Span<char>(received_transfer_);
Brian Silvermand7d01102019-02-24 16:11:21 -0800241 received_dummy_ = false;
242 {
243 DisableInterrupts disable_interrupts;
244 waiting_for_enable_ = true;
245 waiting_for_disable_ = true;
246 PORTA_PCR17 =
247 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0x8) /* Interrupt when logic 0 */;
248 // Clear the interrupt flag now that we've reconfigured it.
249 PORTA_ISFR = 1 << 17;
250 }
251 // Tell the SPI peripheral its CS is de-asserted.
252 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
253 }
254
255 bool TransferTimedOut(aos::monotonic_clock::time_point now) {
256 DisableInterrupts disable_interrupts;
257 // TODO: Revise this timeout.
258 return now - std::chrono::milliseconds(50) > receive_start_;
259 }
260
261 bool DeassertHappened(aos::monotonic_clock::time_point now) {
262 DisableInterrupts disable_interrupts;
263 return now - std::chrono::microseconds(50) > cs_deassert_time_;
264 }
265
266 bool waiting_for_enable_ = true;
267 bool waiting_for_disable_ = false;
268 bool have_transfer_ = false;
269 SpiTransfer transfer_;
270 bool received_dummy_ = false;
271 SpiTransfer received_transfer_;
Austin Schuhb72be802022-01-02 12:26:28 -0800272 absl::Span<char> to_receive_{received_transfer_};
Brian Silvermand7d01102019-02-24 16:11:21 -0800273 aos::monotonic_clock::time_point receive_start_;
274 aos::monotonic_clock::time_point cs_deassert_time_;
275};
276
277SpiQueue *SpiQueue::global_instance = nullptr;
278
279// All methods here must be fully synchronized by the caller.
280class FrameQueue {
281 public:
282 FrameQueue() = default;
283 FrameQueue(const FrameQueue &) = delete;
284 FrameQueue &operator=(const FrameQueue &) = delete;
285
Brian Silvermanc41fb862019-03-02 21:14:46 -0800286 void UpdateFrame(int camera, const CameraFrame &frame) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800287 frames_[camera].targets = frame.targets;
288 frames_[camera].capture_time = aos::monotonic_clock::now() - frame.age;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800289 frames_[camera].camera_index = camera;
Brian Silvermand7d01102019-02-24 16:11:21 -0800290 const aos::SizedArray<int, 3> old_last_frames = last_frames_;
291 last_frames_.clear();
292 for (int index : old_last_frames) {
293 if (index != camera) {
294 last_frames_.push_back(index);
295 }
296 }
297 }
298
299 // Creates and returns a transfer with all the current information.
300 //
301 // This does not actually record these frames as transferred until
302 // RemoveLatestFrames() is called.
303 SpiTransfer MakeTransfer();
304
305 // Records the frames represented in the result of the latest MakeTransfer()
306 // call as being transferred, so they will not be represented in subsequent
307 // MakeTransfer() calls.
308 void RemoveLatestFrames() {
309 for (int index : last_frames_) {
310 frames_[index].capture_time = aos::monotonic_clock::min_time;
311 }
312 last_frames_.clear();
313 }
314
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700315 bool HaveLatestFrames() const { return !last_frames_.empty(); }
316
Brian Silvermand7d01102019-02-24 16:11:21 -0800317 private:
318 struct FrameData {
319 aos::SizedArray<Target, 3> targets;
320 aos::monotonic_clock::time_point capture_time =
321 aos::monotonic_clock::min_time;
Brian Silvermanc41fb862019-03-02 21:14:46 -0800322 int camera_index;
Brian Silvermand7d01102019-02-24 16:11:21 -0800323 };
324
325 std::array<FrameData, 5> frames_;
326 // The indices into frames_ which we returned in the last MakeTransfer() call.
327 aos::SizedArray<int, 3> last_frames_;
328};
329
330SpiTransfer FrameQueue::MakeTransfer() {
331 aos::SizedArray<int, 5> oldest_indices;
332 for (size_t i = 0; i < frames_.size(); ++i) {
333 if (frames_[i].capture_time != aos::monotonic_clock::min_time) {
334 oldest_indices.push_back(i);
335 }
336 }
337 std::sort(oldest_indices.begin(), oldest_indices.end(), [this](int a, int b) {
338 return frames_[a].capture_time < frames_[b].capture_time;
339 });
340
341 TeensyToRoborio message;
342 last_frames_.clear();
343 for (int i = 0; i < std::min<int>(oldest_indices.size(), 3); ++i) {
344 const int index = oldest_indices[i];
345 const FrameData &frame = frames_[index];
346 const auto age = aos::monotonic_clock::now() - frame.capture_time;
Austin Schuhb72be802022-01-02 12:26:28 -0800347 const auto rounded_age = std::chrono::round<camera_duration>(age);
Brian Silvermanc41fb862019-03-02 21:14:46 -0800348 message.frames.push_back({frame.targets, rounded_age, frame.camera_index});
Brian Silvermand7d01102019-02-24 16:11:21 -0800349 last_frames_.push_back(index);
350 }
351 return SpiPackToRoborio(message);
352}
Brian Silverman3240e102019-02-16 18:24:24 -0800353
Brian Silverman2294f352019-03-02 16:31:18 -0800354// Manages turning the debug light on and off periodically.
355//
356// It blinks at 1Hz with a variable duty cycle.
357class DebugLight {
358 public:
359 static constexpr aos::monotonic_clock::duration period() {
360 return std::chrono::seconds(1);
361 }
362
363 void set_next_off_time(aos::monotonic_clock::duration next_off_time) {
364 next_off_time_ = next_off_time;
365 }
366
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800367 bool Tick(aos::monotonic_clock::time_point now) {
Brian Silverman2294f352019-03-02 16:31:18 -0800368 if (last_cycle_start_ == aos::monotonic_clock::min_time) {
369 last_cycle_start_ = now;
370 current_off_point_ = last_cycle_start_ + next_off_time_;
371 } else if (now > last_cycle_start_ + period()) {
372 last_cycle_start_ += period();
373 current_off_point_ = last_cycle_start_ + next_off_time_;
374 }
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800375 return now > current_off_point_;
Brian Silverman2294f352019-03-02 16:31:18 -0800376 }
377
378 private:
379 aos::monotonic_clock::time_point last_cycle_start_ =
380 aos::monotonic_clock::min_time;
381
Brian Silvermanbac77542019-03-03 13:57:00 -0800382 aos::monotonic_clock::duration next_off_time_ =
383 std::chrono::milliseconds(100);
Brian Silverman2294f352019-03-02 16:31:18 -0800384 aos::monotonic_clock::time_point current_off_point_ =
385 aos::monotonic_clock::min_time;
386};
387
Brian Silvermana498bbb2019-03-03 17:18:04 -0800388// Returns an identifier for the processor we're running on.
389uint32_t ProcessorIdentifier() {
390 uint32_t r = 0;
391 r |= SIM_UIDH << 24;
392 r |= SIM_UIDMH << 16;
393 r |= SIM_UIDML << 8;
394 r |= SIM_UIDL << 0;
395 return r;
396}
397
Brian Silverman3240e102019-02-16 18:24:24 -0800398extern "C" {
399
400void *__stack_chk_guard = (void *)0x67111971;
401void __stack_chk_fail(void) {
402 while (true) {
403 GPIOC_PSOR = (1 << 5);
404 printf("Stack corruption detected\n");
405 delay(1000);
406 GPIOC_PCOR = (1 << 5);
407 delay(1000);
408 }
409}
410
411extern char *__brkval;
412extern uint32_t __bss_ram_start__[];
413extern uint32_t __heap_start__[];
414extern uint32_t __stack_end__[];
415
416void uart0_status_isr(void) {
417 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800418 Uarts::global_instance->cam1.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800419}
420
421void uart1_status_isr(void) {
422 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800423 Uarts::global_instance->cam0.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800424}
425
426void uart2_status_isr(void) {
427 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800428 Uarts::global_instance->cam2.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800429}
430
431void uart3_status_isr(void) {
432 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800433 Uarts::global_instance->cam3.HandleInterrupt(disable_interrupts);
Brian Silverman3240e102019-02-16 18:24:24 -0800434}
435
436void uart4_status_isr(void) {
437 DisableInterrupts disable_interrupts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800438 Uarts::global_instance->cam4.HandleInterrupt(disable_interrupts);
439}
440
441void spi0_isr(void) {
442 DisableInterrupts disable_interrupts;
443 global_spi_instance->HandleInterrupt(disable_interrupts);
444}
445
Tyler Chatowbf0609c2021-07-31 16:13:27 -0700446void porta_isr(void) { SpiQueue::global_instance->HandleInterrupt(); }
Brian Silverman3240e102019-02-16 18:24:24 -0800447
448} // extern "C"
449
450// A test program which echos characters back after adding a per-UART offset to
451// them (CAM0 adds 1, CAM1 adds 2, etc).
452__attribute__((unused)) void TestUarts() {
Brian Silvermand7d01102019-02-24 16:11:21 -0800453 Uarts *const uarts = Uarts::global_instance;
Brian Silverman3240e102019-02-16 18:24:24 -0800454 while (true) {
455 {
456 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800457 const auto data = uarts->cam0.Read(absl::Span<char>(buffer));
458 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800459 data[i] += 1;
460 }
461 uarts->cam0.Write(data);
462 }
463 {
464 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800465 const auto data = uarts->cam1.Read(absl::Span<char>(buffer));
466 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800467 data[i] += 2;
468 }
469 uarts->cam1.Write(data);
470 }
471 {
472 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800473 const auto data = uarts->cam2.Read(absl::Span<char>(buffer));
474 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800475 data[i] += 3;
476 }
477 uarts->cam2.Write(data);
478 }
479 {
480 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800481 const auto data = uarts->cam3.Read(absl::Span<char>(buffer));
482 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800483 data[i] += 4;
484 }
485 uarts->cam3.Write(data);
486 }
487 {
488 std::array<char, 10> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800489 const auto data = uarts->cam4.Read(absl::Span<char>(buffer));
490 for (size_t i = 0; i < data.size(); ++i) {
Brian Silverman3240e102019-02-16 18:24:24 -0800491 data[i] += 5;
492 }
493 uarts->cam4.Write(data);
494 }
495 }
496}
497
498// Tests all the I/O pins. Cycles through each one for 1 second. While active,
499// each output is turned on, and each input has its value printed.
500__attribute__((unused)) void TestIo() {
501 // Set SPI0 pins to GPIO.
502 // SPI_OUT
503 PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1;
504 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1);
505 // SPI_CS
506 PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0;
507 PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
508 // SPI_IN
509 PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0;
510 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
511 // SPI_SCK
512 PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0;
513 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
514
Brian Silverman3240e102019-02-16 18:24:24 -0800515 auto next = aos::monotonic_clock::now();
516 static constexpr auto kTick = std::chrono::seconds(1);
517 while (true) {
518 printf("SPI_MISO\n");
519 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1;
520 while (aos::monotonic_clock::now() < next + kTick) {
521 }
522 PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0;
523 next += kTick;
524
525 while (aos::monotonic_clock::now() < next + kTick) {
526 printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0));
527 }
528 next += kTick;
529
530 while (aos::monotonic_clock::now() < next + kTick) {
531 printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7));
532 }
533 next += kTick;
534
535 while (aos::monotonic_clock::now() < next + kTick) {
536 printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1));
537 }
538 next += kTick;
539
540 printf("CAM0\n");
541 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1;
542 while (aos::monotonic_clock::now() < next + kTick) {
543 }
544 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0;
545 next += kTick;
546
547 printf("CAM1\n");
548 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1;
549 while (aos::monotonic_clock::now() < next + kTick) {
550 }
551 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0;
552 next += kTick;
553
554 printf("CAM2\n");
555 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1;
556 while (aos::monotonic_clock::now() < next + kTick) {
557 }
558 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0;
559 next += kTick;
560
561 printf("CAM3\n");
562 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1;
563 while (aos::monotonic_clock::now() < next + kTick) {
564 }
565 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0;
566 next += kTick;
567
568 printf("CAM4\n");
569 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1;
570 while (aos::monotonic_clock::now() < next + kTick) {
571 }
572 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0;
573 next += kTick;
574
575 printf("CAM5\n");
576 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1;
577 while (aos::monotonic_clock::now() < next + kTick) {
578 }
579 PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0;
580 next += kTick;
581
582 printf("CAM6\n");
583 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1;
584 while (aos::monotonic_clock::now() < next + kTick) {
585 }
586 PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0;
587 next += kTick;
588
589 printf("CAM7\n");
590 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1;
591 while (aos::monotonic_clock::now() < next + kTick) {
592 }
593 PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0;
594 next += kTick;
595
596 printf("CAM8\n");
597 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1;
598 while (aos::monotonic_clock::now() < next + kTick) {
599 }
600 PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0;
601 next += kTick;
602
603 printf("CAM9\n");
604 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1;
605 while (aos::monotonic_clock::now() < next + kTick) {
606 }
607 PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0;
608 next += kTick;
609 }
610}
611
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800612struct LightRingState {
613 DebugLight debug_light;
614 aos::monotonic_clock::time_point last_frame = aos::monotonic_clock::max_time;
615
616 bool Tick(aos::monotonic_clock::time_point now) {
617 if (last_frame == aos::monotonic_clock::max_time) {
618 last_frame = now;
619 }
620 if (now > last_frame + std::chrono::seconds(1)) {
621 debug_light.set_next_off_time(std::chrono::milliseconds(500));
622 } else {
623 debug_light.set_next_off_time(std::chrono::seconds(0));
624 }
625 return debug_light.Tick(now);
626 }
627};
628
Brian Silvermand7d01102019-02-24 16:11:21 -0800629// Does the normal work of transferring data in all directions.
630//
631// https://community.nxp.com/thread/466937#comment-983881 is a post from NXP
632// claiming that it's impossible to queue up the first byte for the slave end of
633// an SPI connection properly. Instead, we just accept there will be a garbage
634// byte and the other end ignores it.
Brian Silverman83693e42019-03-02 15:45:52 -0800635__attribute__((unused)) void TransferData(
636 frc971::motors::PrintingImplementation *printing) {
Brian Silvermand7d01102019-02-24 16:11:21 -0800637 Uarts *const uarts = Uarts::global_instance;
638 std::array<CobsPacketizer<uart_to_teensy_size()>, 5> packetizers;
639 std::array<TransmitBuffer, 5> transmit_buffers{
640 {&uarts->cam0, &uarts->cam1, &uarts->cam2, &uarts->cam3, &uarts->cam4}};
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800641 std::array<LightRingState, 5> light_rings;
Brian Silvermand7d01102019-02-24 16:11:21 -0800642 FrameQueue frame_queue;
643 aos::monotonic_clock::time_point last_camera_send =
644 aos::monotonic_clock::min_time;
Brian Silverman83693e42019-03-02 15:45:52 -0800645 CameraCommand stdin_camera_command = CameraCommand::kNormal;
646 CameraCommand last_roborio_camera_command = CameraCommand::kNormal;
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800647 DebugLight teensy_debug_light;
Brian Silverman83693e42019-03-02 15:45:52 -0800648
Austin Schuhf7d60c42019-03-03 20:44:02 -0800649 bool verbose = false;
650
Brian Silvermand7d01102019-02-24 16:11:21 -0800651 bool first = true;
652 while (true) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800653 {
654 const auto now = aos::monotonic_clock::now();
655 PERIPHERAL_BITBAND(GPIOC_PDOR, 5) = !teensy_debug_light.Tick(now);
656 PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = light_rings[0].Tick(now);
657 PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = light_rings[1].Tick(now);
658 PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = light_rings[2].Tick(now);
659 PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = light_rings[3].Tick(now);
660 PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = light_rings[4].Tick(now);
661 }
Brian Silverman2294f352019-03-02 16:31:18 -0800662
Brian Silvermand7d01102019-02-24 16:11:21 -0800663 {
664 const auto received_transfer = SpiQueue::global_instance->Tick();
665 if (received_transfer) {
666 const auto unpacked = SpiUnpackToTeensy(*received_transfer);
Brian Silverman83693e42019-03-02 15:45:52 -0800667 if (unpacked) {
668 last_roborio_camera_command = unpacked->camera_command;
669 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800670 printf("SPI decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800671 }
672 }
673 }
674
675 {
676 std::array<char, 20> buffer;
Austin Schuh7fe04492022-01-02 13:37:21 -0800677 packetizers[0].ParseData(uarts->cam0.Read(absl::Span<char>(buffer)));
678 packetizers[1].ParseData(uarts->cam1.Read(absl::Span<char>(buffer)));
679 packetizers[2].ParseData(uarts->cam2.Read(absl::Span<char>(buffer)));
680 packetizers[3].ParseData(uarts->cam3.Read(absl::Span<char>(buffer)));
681 packetizers[4].ParseData(uarts->cam4.Read(absl::Span<char>(buffer)));
Brian Silvermand7d01102019-02-24 16:11:21 -0800682 }
683 for (size_t i = 0; i < packetizers.size(); ++i) {
684 if (!packetizers[i].received_packet().empty()) {
685 const auto decoded =
686 UartUnpackToTeensy(packetizers[i].received_packet());
687 packetizers[i].clear_received_packet();
688 if (decoded) {
Austin Schuhf7d60c42019-03-03 20:44:02 -0800689 if (verbose) {
Brian Silverman177f0662019-03-09 15:45:02 -0800690 printf("uart frame cam %d, %d targets\n", static_cast<int>(i),
691 static_cast<int>(decoded->targets.size()));
Austin Schuhf7d60c42019-03-03 20:44:02 -0800692 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800693 frame_queue.UpdateFrame(i, *decoded);
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800694 light_rings[i].last_frame = aos::monotonic_clock::now();
695 } else {
696 printf("UART decode error\n");
Brian Silvermand7d01102019-02-24 16:11:21 -0800697 }
698 }
699 }
700 {
701 bool made_transfer = false;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700702 const bool have_old_frames = frame_queue.HaveLatestFrames();
703 {
704 const auto new_transfer = frame_queue.MakeTransfer();
Brian Silvermand7d01102019-02-24 16:11:21 -0800705 DisableInterrupts disable_interrupts;
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700706 if (!first) {
707 made_transfer =
708 !SpiQueue::global_instance->HaveTransfer(disable_interrupts);
709 }
710 // If we made a transfer just now, then new_transfer might contain
711 // duplicate targets, in which case don't use it.
712 if (!have_old_frames || !made_transfer) {
713 SpiQueue::global_instance->UpdateTransfer(new_transfer,
714 disable_interrupts);
715 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800716 }
Brian Silvermanb5db4ec2019-04-03 21:29:30 -0700717 // If we made a transfer, then make sure we aren't remembering any
718 // in-flight frames.
Brian Silvermand7d01102019-02-24 16:11:21 -0800719 if (made_transfer) {
720 frame_queue.RemoveLatestFrames();
721 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800722 }
723 {
724 const auto now = aos::monotonic_clock::now();
Brian Silvermanbac77542019-03-03 13:57:00 -0800725 CameraCommand current_camera_command = CameraCommand::kNormal;
726 if (last_roborio_camera_command != CameraCommand::kNormal) {
727 current_camera_command = last_roborio_camera_command;
728 } else {
729 current_camera_command = stdin_camera_command;
730 }
731 if (current_camera_command == CameraCommand::kUsb) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800732 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(900));
Brian Silvermanbac77542019-03-03 13:57:00 -0800733 } else if (current_camera_command == CameraCommand::kCameraPassthrough) {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800734 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(500));
Brian Silvermanbac77542019-03-03 13:57:00 -0800735 } else {
Brian Silvermanc2fb02a2019-03-03 18:02:00 -0800736 teensy_debug_light.set_next_off_time(std::chrono::milliseconds(100));
Brian Silvermanbac77542019-03-03 13:57:00 -0800737 }
738
739 if (current_camera_command == CameraCommand::kAs) {
740 for (size_t i = 0; i < transmit_buffers.size(); ++i) {
741 transmit_buffers[i].FillAs();
Brian Silverman83693e42019-03-02 15:45:52 -0800742 }
Brian Silvermanbac77542019-03-03 13:57:00 -0800743 } else {
744 if (last_camera_send + std::chrono::milliseconds(1000) < now) {
745 last_camera_send = now;
746 CameraCalibration calibration{};
747 calibration.teensy_now = aos::monotonic_clock::now();
748 calibration.realtime_now = aos::realtime_clock::min_time;
749 calibration.camera_command = current_camera_command;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800750
751 for (int i = 0; i < 5; ++i) {
752 const y2019::vision::CameraCalibration *const constants =
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800753 y2019::vision::GetCamera(y2019::vision::CameraSerialNumbers(
754 ProcessorIdentifier())[i]);
Alex Perryf3e46be2019-03-03 17:26:14 -0800755 calibration.calibration(0, 0) = constants->intrinsics.mount_angle;
756 calibration.calibration(0, 1) = constants->intrinsics.focal_length;
757 calibration.calibration(0, 2) = constants->intrinsics.barrel_mount;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800758 transmit_buffers[i].MaybeWritePacket(calibration);
759 }
Brian Silverman2294f352019-03-02 16:31:18 -0800760 }
Brian Silvermand7d01102019-02-24 16:11:21 -0800761 }
762 for (TransmitBuffer &transmit_buffer : transmit_buffers) {
763 transmit_buffer.Tick(now);
764 }
765 }
766
Brian Silverman83693e42019-03-02 15:45:52 -0800767 {
768 const auto stdin_data = printing->ReadStdin();
769 if (!stdin_data.empty()) {
770 switch (stdin_data.back()) {
771 case 'p':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800772 printf("Sending passthrough mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800773 stdin_camera_command = CameraCommand::kCameraPassthrough;
774 break;
775 case 'u':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800776 printf("Sending USB mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800777 stdin_camera_command = CameraCommand::kUsb;
778 break;
Austin Schuh4e2629d2019-03-28 14:44:37 -0700779 case 'l':
780 printf("Log mode\n");
781 stdin_camera_command = CameraCommand::kLog;
782 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800783 case 'n':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800784 printf("Sending normal mode\n");
Brian Silverman83693e42019-03-02 15:45:52 -0800785 stdin_camera_command = CameraCommand::kNormal;
786 break;
Brian Silvermanbac77542019-03-03 13:57:00 -0800787 case 'a':
Brian Silvermana498bbb2019-03-03 17:18:04 -0800788 printf("Sending all 'a's\n");
Brian Silvermanbac77542019-03-03 13:57:00 -0800789 stdin_camera_command = CameraCommand::kAs;
790 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800791 case 'c':
792 printf("This UART board is 0x%" PRIx32 "\n", ProcessorIdentifier());
793 for (int i = 0; i < 5; ++i) {
James Kuszmaule2c71ea2019-03-04 08:14:21 -0800794 printf(
795 "Camera slot %d's serial number is %d\n", i,
796 y2019::vision::CameraSerialNumbers(ProcessorIdentifier())[i]);
Brian Silvermana498bbb2019-03-03 17:18:04 -0800797 }
798 break;
Austin Schuhf7d60c42019-03-03 20:44:02 -0800799 case 'v':
800 printf("Toggling verbose mode\n");
801 verbose = !verbose;
802 break;
Brian Silvermana498bbb2019-03-03 17:18:04 -0800803 case 'h':
804 printf("UART board commands:\n");
805 printf(" p: Send passthrough mode\n");
806 printf(" u: Send USB mode\n");
Austin Schuh4e2629d2019-03-28 14:44:37 -0700807 printf(" l: Send Log mode\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800808 printf(" n: Send normal mode\n");
809 printf(" a: Send all-'a' mode\n");
810 printf(" c: Dump camera configuration\n");
Austin Schuhf7d60c42019-03-03 20:44:02 -0800811 printf(" v: Toggle verbose print\n");
Brian Silvermana498bbb2019-03-03 17:18:04 -0800812 break;
Brian Silverman83693e42019-03-02 15:45:52 -0800813 default:
814 printf("Unrecognized character\n");
815 break;
816 }
817 }
818 }
819
Brian Silvermand7d01102019-02-24 16:11:21 -0800820 first = false;
821 }
822}
823
Brian Silverman3240e102019-02-16 18:24:24 -0800824int Main() {
825 // for background about this startup delay, please see these conversations
826 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
827 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
828 delay(400);
829
830 // Set all interrupts to the second-lowest priority to start with.
831 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
832
833 // Now set priorities for all the ones we care about. They only have meaning
834 // relative to each other, which means centralizing them here makes it a lot
835 // more manageable.
Brian Silvermand7d01102019-02-24 16:11:21 -0800836 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
837 NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0x3);
838 NVIC_SET_SANE_PRIORITY(IRQ_UART1_STATUS, 0x3);
839 NVIC_SET_SANE_PRIORITY(IRQ_UART2_STATUS, 0x3);
840 NVIC_SET_SANE_PRIORITY(IRQ_UART3_STATUS, 0x3);
841 NVIC_SET_SANE_PRIORITY(IRQ_UART4_STATUS, 0x3);
842 // This one is relatively sensitive to latencies. The buffer is ~4800 clock
843 // cycles long.
844 NVIC_SET_SANE_PRIORITY(IRQ_SPI0, 0x2);
845 NVIC_SET_SANE_PRIORITY(IRQ_PORTA, 0x3);
Brian Silverman3240e102019-02-16 18:24:24 -0800846
847 // Set the LED's pin to output mode.
848 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
849 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
850
851 frc971::motors::PrintingParameters printing_parameters;
852 printing_parameters.dedicated_usb = true;
853 const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing =
854 CreatePrinting(printing_parameters);
855 printing->Initialize();
856
857 DMA.CR = M_DMA_EMLM;
858
Brian Silvermand7d01102019-02-24 16:11:21 -0800859 SIM_SCGC1 |= SIM_SCGC1_UART4;
Brian Silverman3240e102019-02-16 18:24:24 -0800860 SIM_SCGC4 |=
861 SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3;
Brian Silvermand7d01102019-02-24 16:11:21 -0800862 SIM_SCGC6 |= SIM_SCGC6_SPI0;
Brian Silverman3240e102019-02-16 18:24:24 -0800863
864 // SPI0 goes to the roboRIO.
865 // SPI0_PCS0 is SPI_CS.
Brian Silvermand7d01102019-02-24 16:11:21 -0800866 PORTD_PCR0 = PORT_PCR_MUX(2);
Brian Silverman3240e102019-02-16 18:24:24 -0800867 // SPI0_SOUT is SPI_MISO.
868 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
869 // SPI0_SIN is SPI_MOSI.
870 PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2);
871 // SPI0_SCK is SPI_CLK.
872 PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2);
Brian Silvermand7d01102019-02-24 16:11:21 -0800873 // SPI_CS_DRIVE
874 PERIPHERAL_BITBAND(GPIOB_PDDR, 17) = 1;
875 PERIPHERAL_BITBAND(GPIOB_PDOR, 17) = 1;
876 PORTB_PCR17 = PORT_PCR_DSE | PORT_PCR_MUX(1);
877 // SPI_CS_IN
878 PERIPHERAL_BITBAND(GPIOA_PDDR, 17) = 0;
879 // Set the filter width.
880 PORTA_DFWR = 31;
881 // Enable the filter.
882 PERIPHERAL_BITBAND(PORTA_DFER, 17) = 1;
883 PORTA_PCR17 =
884 PORT_PCR_MUX(1) | PORT_PCR_IRQC(0xC) /* Interrupt when logic 1 */;
885 // Clear the interrupt flag now that we've reconfigured it.
886 PORTA_ISFR = 1 << 17;
Brian Silverman3240e102019-02-16 18:24:24 -0800887
Brian Silverman177f0662019-03-09 15:45:02 -0800888 // For now, we have no need to dim the LEDs, so we're just going to set them
889 // all to GPIO mode for simplicity of programming.
890#if 0
Brian Silverman3240e102019-02-16 18:24:24 -0800891 // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel).
892 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
893 // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel).
894 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
895 // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel).
896 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4);
897 // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera).
898 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
899
900 // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera).
901 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3);
902 // FTM2_CH0 is LED5 (for CAM4).
903 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3);
904
905 // FTM3_CH4 is LED6 (for CAM2).
906 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3);
907 // FTM3_CH5 is LED7 (for CAM3).
908 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3);
909 // FTM3_CH6 is LED8 (for CAM1).
910 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3);
911 // FTM3_CH7 is LED9 (for CAM0).
912 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
Brian Silverman177f0662019-03-09 15:45:02 -0800913#else
914 // Set all the LED pins to GPIO.
915 PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1;
916 PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1);
917 PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1;
918 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1);
919 PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1;
920 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1);
921 PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1;
922 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1);
923 PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1;
924 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1);
925 PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1;
926 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1);
927 PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1;
928 PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1);
929 PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1;
930 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1);
931 PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1;
932 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1);
933 PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1;
934 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
935#endif
Brian Silverman3240e102019-02-16 18:24:24 -0800936
937 // This hardware has been deactivated, but keep this comment for now to
938 // document which pins it is on.
939#if 0
940 // This is ODROID_EN.
941 PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1;
942 PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0;
943 PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
944 // This is CAM_EN.
945 PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1;
946 PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0;
947 PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1);
948#endif
949 // This is 5V_PGOOD.
950 PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0;
951 PORTD_PCR6 = PORT_PCR_MUX(1);
952
953 // These go to CAM1.
Brian Silverman30adf342019-03-09 18:27:56 -0800954 // UART0_RX (peripheral) is UART1_RX (schematic) is UART1_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800955 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
956 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800957 // UART0_TX (peripheral) is UART1_TX (schematic) is UART1_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800958 PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3);
959
960 // These go to CAM0.
Brian Silverman30adf342019-03-09 18:27:56 -0800961 // UART1_RX (peripheral) is UART0_RX (schematic) is UART0_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800962 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
963 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800964 // UART1_TX (peripheral) is UART0_TX (schematic) is UART0_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800965 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3);
966
967 // These go to CAM2.
Brian Silverman30adf342019-03-09 18:27:56 -0800968 // UART2_RX is UART2_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800969 PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
970 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800971 // UART2_TX is UART2_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800972 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3);
973
974 // These go to CAM3.
Brian Silverman30adf342019-03-09 18:27:56 -0800975 // UART3_RX is UART3_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800976 PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
977 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800978 // UART3_TX is UART3_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800979 PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3);
980
981 // These go to CAM4.
Brian Silverman30adf342019-03-09 18:27:56 -0800982 // UART4_RX is UART4_TX_RAW (label TX).
Brian Silvermand7d01102019-02-24 16:11:21 -0800983 PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3) | PORT_PCR_PE /* Do a pull */ |
984 0 /* !PS to pull down */;
Brian Silverman30adf342019-03-09 18:27:56 -0800985 // UART4_TX is UART4_RX_RAW (label RX).
Brian Silverman3240e102019-02-16 18:24:24 -0800986 PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3);
987
988 Uarts uarts;
Brian Silvermand7d01102019-02-24 16:11:21 -0800989 InterruptBufferedSpi spi0{&SPI0, BUS_CLOCK_FREQUENCY};
990 global_spi_instance = &spi0;
991 SpiQueue spi_queue;
Brian Silverman3240e102019-02-16 18:24:24 -0800992
993 // Give everything a chance to get going.
994 delay(100);
995
996 printf("Ram start: %p\n", __bss_ram_start__);
997 printf("Heap start: %p\n", __heap_start__);
998 printf("Heap end: %p\n", __brkval);
999 printf("Stack start: %p\n", __stack_end__);
1000
1001 uarts.Initialize(115200);
1002 NVIC_ENABLE_IRQ(IRQ_UART0_STATUS);
1003 NVIC_ENABLE_IRQ(IRQ_UART1_STATUS);
1004 NVIC_ENABLE_IRQ(IRQ_UART2_STATUS);
1005 NVIC_ENABLE_IRQ(IRQ_UART3_STATUS);
1006 NVIC_ENABLE_IRQ(IRQ_UART4_STATUS);
Brian Silvermand7d01102019-02-24 16:11:21 -08001007 spi0.Initialize();
1008 NVIC_ENABLE_IRQ(IRQ_SPI0);
1009 NVIC_ENABLE_IRQ(IRQ_PORTA);
1010
Brian Silverman83693e42019-03-02 15:45:52 -08001011 TransferData(printing.get());
Brian Silverman3240e102019-02-16 18:24:24 -08001012
1013 while (true) {
1014 }
1015}
1016
1017extern "C" {
1018
Tyler Chatowbf0609c2021-07-31 16:13:27 -07001019int main(void) { return Main(); }
Brian Silverman3240e102019-02-16 18:24:24 -08001020
1021} // extern "C"
1022
1023} // namespace
1024} // namespace jevois
1025} // namespace frc971