Brian Silverman | 3240e10 | 2019-02-16 18:24:24 -0800 | [diff] [blame] | 1 | #include "aos/time/time.h" |
| 2 | #include "motors/core/kinetis.h" |
| 3 | #include "motors/core/time.h" |
| 4 | #include "motors/peripheral/configuration.h" |
| 5 | #include "motors/peripheral/uart.h" |
| 6 | #include "motors/print/print.h" |
| 7 | #include "motors/util.h" |
| 8 | |
| 9 | namespace frc971 { |
| 10 | namespace jevois { |
| 11 | namespace { |
| 12 | |
| 13 | struct Uarts { |
| 14 | Uarts() { |
| 15 | DisableInterrupts disable_interrupts; |
| 16 | instance = this; |
| 17 | } |
| 18 | ~Uarts() { |
| 19 | DisableInterrupts disable_interrupts; |
| 20 | instance = nullptr; |
| 21 | } |
| 22 | |
| 23 | void Initialize(int baud_rate) { |
| 24 | cam0.Initialize(baud_rate); |
| 25 | cam1.Initialize(baud_rate); |
| 26 | cam2.Initialize(baud_rate); |
| 27 | cam3.Initialize(baud_rate); |
| 28 | cam4.Initialize(baud_rate); |
| 29 | } |
| 30 | |
| 31 | frc971::teensy::InterruptBufferedUart cam0{&UART1, F_CPU}; |
| 32 | frc971::teensy::InterruptBufferedUart cam1{&UART0, F_CPU}; |
| 33 | frc971::teensy::InterruptBufferedUart cam2{&UART2, BUS_CLOCK_FREQUENCY}; |
| 34 | frc971::teensy::InterruptBufferedUart cam3{&UART3, BUS_CLOCK_FREQUENCY}; |
| 35 | frc971::teensy::InterruptBufferedUart cam4{&UART4, BUS_CLOCK_FREQUENCY}; |
| 36 | |
| 37 | static Uarts *instance; |
| 38 | }; |
| 39 | |
| 40 | Uarts *Uarts::instance = nullptr; |
| 41 | |
| 42 | extern "C" { |
| 43 | |
| 44 | void *__stack_chk_guard = (void *)0x67111971; |
| 45 | void __stack_chk_fail(void) { |
| 46 | while (true) { |
| 47 | GPIOC_PSOR = (1 << 5); |
| 48 | printf("Stack corruption detected\n"); |
| 49 | delay(1000); |
| 50 | GPIOC_PCOR = (1 << 5); |
| 51 | delay(1000); |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | extern char *__brkval; |
| 56 | extern uint32_t __bss_ram_start__[]; |
| 57 | extern uint32_t __heap_start__[]; |
| 58 | extern uint32_t __stack_end__[]; |
| 59 | |
| 60 | void uart0_status_isr(void) { |
| 61 | DisableInterrupts disable_interrupts; |
| 62 | Uarts::instance->cam1.HandleInterrupt(disable_interrupts); |
| 63 | } |
| 64 | |
| 65 | void uart1_status_isr(void) { |
| 66 | DisableInterrupts disable_interrupts; |
| 67 | Uarts::instance->cam0.HandleInterrupt(disable_interrupts); |
| 68 | } |
| 69 | |
| 70 | void uart2_status_isr(void) { |
| 71 | DisableInterrupts disable_interrupts; |
| 72 | Uarts::instance->cam2.HandleInterrupt(disable_interrupts); |
| 73 | } |
| 74 | |
| 75 | void uart3_status_isr(void) { |
| 76 | DisableInterrupts disable_interrupts; |
| 77 | Uarts::instance->cam3.HandleInterrupt(disable_interrupts); |
| 78 | } |
| 79 | |
| 80 | void uart4_status_isr(void) { |
| 81 | DisableInterrupts disable_interrupts; |
| 82 | Uarts::instance->cam4.HandleInterrupt(disable_interrupts); |
| 83 | } |
| 84 | |
| 85 | } // extern "C" |
| 86 | |
| 87 | // A test program which echos characters back after adding a per-UART offset to |
| 88 | // them (CAM0 adds 1, CAM1 adds 2, etc). |
| 89 | __attribute__((unused)) void TestUarts() { |
| 90 | Uarts *const uarts = Uarts::instance; |
| 91 | while (true) { |
| 92 | { |
| 93 | std::array<char, 10> buffer; |
| 94 | const auto data = uarts->cam0.Read(buffer); |
| 95 | for (int i = 0; i < data.size(); ++i) { |
| 96 | data[i] += 1; |
| 97 | } |
| 98 | uarts->cam0.Write(data); |
| 99 | } |
| 100 | { |
| 101 | std::array<char, 10> buffer; |
| 102 | const auto data = uarts->cam1.Read(buffer); |
| 103 | for (int i = 0; i < data.size(); ++i) { |
| 104 | data[i] += 2; |
| 105 | } |
| 106 | uarts->cam1.Write(data); |
| 107 | } |
| 108 | { |
| 109 | std::array<char, 10> buffer; |
| 110 | const auto data = uarts->cam2.Read(buffer); |
| 111 | for (int i = 0; i < data.size(); ++i) { |
| 112 | data[i] += 3; |
| 113 | } |
| 114 | uarts->cam2.Write(data); |
| 115 | } |
| 116 | { |
| 117 | std::array<char, 10> buffer; |
| 118 | const auto data = uarts->cam3.Read(buffer); |
| 119 | for (int i = 0; i < data.size(); ++i) { |
| 120 | data[i] += 4; |
| 121 | } |
| 122 | uarts->cam3.Write(data); |
| 123 | } |
| 124 | { |
| 125 | std::array<char, 10> buffer; |
| 126 | const auto data = uarts->cam4.Read(buffer); |
| 127 | for (int i = 0; i < data.size(); ++i) { |
| 128 | data[i] += 5; |
| 129 | } |
| 130 | uarts->cam4.Write(data); |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // Tests all the I/O pins. Cycles through each one for 1 second. While active, |
| 136 | // each output is turned on, and each input has its value printed. |
| 137 | __attribute__((unused)) void TestIo() { |
| 138 | // Set SPI0 pins to GPIO. |
| 139 | // SPI_OUT |
| 140 | PERIPHERAL_BITBAND(GPIOC_PDDR, 6) = 1; |
| 141 | PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 142 | // SPI_CS |
| 143 | PERIPHERAL_BITBAND(GPIOD_PDDR, 0) = 0; |
| 144 | PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 145 | // SPI_IN |
| 146 | PERIPHERAL_BITBAND(GPIOC_PDDR, 7) = 0; |
| 147 | PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 148 | // SPI_SCK |
| 149 | PERIPHERAL_BITBAND(GPIOD_PDDR, 1) = 0; |
| 150 | PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 151 | |
| 152 | // Set LED pins to GPIO. |
| 153 | PERIPHERAL_BITBAND(GPIOC_PDDR, 11) = 1; |
| 154 | PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 155 | PERIPHERAL_BITBAND(GPIOC_PDDR, 10) = 1; |
| 156 | PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 157 | PERIPHERAL_BITBAND(GPIOC_PDDR, 8) = 1; |
| 158 | PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 159 | PERIPHERAL_BITBAND(GPIOC_PDDR, 9) = 1; |
| 160 | PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 161 | PERIPHERAL_BITBAND(GPIOB_PDDR, 18) = 1; |
| 162 | PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 163 | PERIPHERAL_BITBAND(GPIOC_PDDR, 2) = 1; |
| 164 | PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 165 | PERIPHERAL_BITBAND(GPIOD_PDDR, 7) = 1; |
| 166 | PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 167 | PERIPHERAL_BITBAND(GPIOC_PDDR, 1) = 1; |
| 168 | PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 169 | PERIPHERAL_BITBAND(GPIOB_PDDR, 19) = 1; |
| 170 | PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 171 | PERIPHERAL_BITBAND(GPIOD_PDDR, 5) = 1; |
| 172 | PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 173 | |
| 174 | auto next = aos::monotonic_clock::now(); |
| 175 | static constexpr auto kTick = std::chrono::seconds(1); |
| 176 | while (true) { |
| 177 | printf("SPI_MISO\n"); |
| 178 | PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 1; |
| 179 | while (aos::monotonic_clock::now() < next + kTick) { |
| 180 | } |
| 181 | PERIPHERAL_BITBAND(GPIOC_PDOR, 6) = 0; |
| 182 | next += kTick; |
| 183 | |
| 184 | while (aos::monotonic_clock::now() < next + kTick) { |
| 185 | printf("SPI_CS %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 0)); |
| 186 | } |
| 187 | next += kTick; |
| 188 | |
| 189 | while (aos::monotonic_clock::now() < next + kTick) { |
| 190 | printf("SPI_MOSI %d\n", (int)PERIPHERAL_BITBAND(GPIOC_PDIR, 7)); |
| 191 | } |
| 192 | next += kTick; |
| 193 | |
| 194 | while (aos::monotonic_clock::now() < next + kTick) { |
| 195 | printf("SPI_CLK %d\n", (int)PERIPHERAL_BITBAND(GPIOD_PDIR, 1)); |
| 196 | } |
| 197 | next += kTick; |
| 198 | |
| 199 | printf("CAM0\n"); |
| 200 | PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 1; |
| 201 | while (aos::monotonic_clock::now() < next + kTick) { |
| 202 | } |
| 203 | PERIPHERAL_BITBAND(GPIOC_PDOR, 11) = 0; |
| 204 | next += kTick; |
| 205 | |
| 206 | printf("CAM1\n"); |
| 207 | PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 1; |
| 208 | while (aos::monotonic_clock::now() < next + kTick) { |
| 209 | } |
| 210 | PERIPHERAL_BITBAND(GPIOC_PDOR, 10) = 0; |
| 211 | next += kTick; |
| 212 | |
| 213 | printf("CAM2\n"); |
| 214 | PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 1; |
| 215 | while (aos::monotonic_clock::now() < next + kTick) { |
| 216 | } |
| 217 | PERIPHERAL_BITBAND(GPIOC_PDOR, 8) = 0; |
| 218 | next += kTick; |
| 219 | |
| 220 | printf("CAM3\n"); |
| 221 | PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 1; |
| 222 | while (aos::monotonic_clock::now() < next + kTick) { |
| 223 | } |
| 224 | PERIPHERAL_BITBAND(GPIOC_PDOR, 9) = 0; |
| 225 | next += kTick; |
| 226 | |
| 227 | printf("CAM4\n"); |
| 228 | PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 1; |
| 229 | while (aos::monotonic_clock::now() < next + kTick) { |
| 230 | } |
| 231 | PERIPHERAL_BITBAND(GPIOB_PDOR, 18) = 0; |
| 232 | next += kTick; |
| 233 | |
| 234 | printf("CAM5\n"); |
| 235 | PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 1; |
| 236 | while (aos::monotonic_clock::now() < next + kTick) { |
| 237 | } |
| 238 | PERIPHERAL_BITBAND(GPIOC_PDOR, 2) = 0; |
| 239 | next += kTick; |
| 240 | |
| 241 | printf("CAM6\n"); |
| 242 | PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 1; |
| 243 | while (aos::monotonic_clock::now() < next + kTick) { |
| 244 | } |
| 245 | PERIPHERAL_BITBAND(GPIOD_PDOR, 7) = 0; |
| 246 | next += kTick; |
| 247 | |
| 248 | printf("CAM7\n"); |
| 249 | PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 1; |
| 250 | while (aos::monotonic_clock::now() < next + kTick) { |
| 251 | } |
| 252 | PERIPHERAL_BITBAND(GPIOC_PDOR, 1) = 0; |
| 253 | next += kTick; |
| 254 | |
| 255 | printf("CAM8\n"); |
| 256 | PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 1; |
| 257 | while (aos::monotonic_clock::now() < next + kTick) { |
| 258 | } |
| 259 | PERIPHERAL_BITBAND(GPIOB_PDOR, 19) = 0; |
| 260 | next += kTick; |
| 261 | |
| 262 | printf("CAM9\n"); |
| 263 | PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 1; |
| 264 | while (aos::monotonic_clock::now() < next + kTick) { |
| 265 | } |
| 266 | PERIPHERAL_BITBAND(GPIOD_PDOR, 5) = 0; |
| 267 | next += kTick; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | int Main() { |
| 272 | // for background about this startup delay, please see these conversations |
| 273 | // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980 |
| 274 | // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273 |
| 275 | delay(400); |
| 276 | |
| 277 | // Set all interrupts to the second-lowest priority to start with. |
| 278 | for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD); |
| 279 | |
| 280 | // Now set priorities for all the ones we care about. They only have meaning |
| 281 | // relative to each other, which means centralizing them here makes it a lot |
| 282 | // more manageable. |
| 283 | NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3); |
| 284 | NVIC_SET_SANE_PRIORITY(IRQ_UART0_STATUS, 0xE); |
| 285 | |
| 286 | // Set the LED's pin to output mode. |
| 287 | PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1; |
| 288 | PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 289 | |
| 290 | frc971::motors::PrintingParameters printing_parameters; |
| 291 | printing_parameters.dedicated_usb = true; |
| 292 | const ::std::unique_ptr<frc971::motors::PrintingImplementation> printing = |
| 293 | CreatePrinting(printing_parameters); |
| 294 | printing->Initialize(); |
| 295 | |
| 296 | DMA.CR = M_DMA_EMLM; |
| 297 | |
| 298 | SIM_SCGC4 |= |
| 299 | SIM_SCGC4_UART0 | SIM_SCGC4_UART1 | SIM_SCGC4_UART2 | SIM_SCGC4_UART3; |
| 300 | SIM_SCGC1 |= SIM_SCGC1_UART4; |
| 301 | |
| 302 | // SPI0 goes to the roboRIO. |
| 303 | // SPI0_PCS0 is SPI_CS. |
| 304 | PORTD_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(2); |
| 305 | // SPI0_SOUT is SPI_MISO. |
| 306 | PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2); |
| 307 | // SPI0_SIN is SPI_MOSI. |
| 308 | PORTC_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(2); |
| 309 | // SPI0_SCK is SPI_CLK. |
| 310 | PORTD_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(2); |
| 311 | |
| 312 | // FTM0_CH0 is LED0 (7 in silkscreen, a beacon channel). |
| 313 | PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4); |
| 314 | // FTM0_CH1 is LED1 (5 in silkscreen, a beacon channel). |
| 315 | PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4); |
| 316 | // FTM0_CH7 is LED2 (6 in silkscreen, a beacon channel). |
| 317 | PORTD_PCR7 = PORT_PCR_DSE | PORT_PCR_MUX(4); |
| 318 | // FTM0_CH5 is LED3 (9 in silkscreen, a vision camera). |
| 319 | PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4); |
| 320 | |
| 321 | // FTM2_CH1 is LED4 (8 in silkscreen, a vision camera). |
| 322 | PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 323 | // FTM2_CH0 is LED5 (for CAM4). |
| 324 | PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 325 | |
| 326 | // FTM3_CH4 is LED6 (for CAM2). |
| 327 | PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 328 | // FTM3_CH5 is LED7 (for CAM3). |
| 329 | PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 330 | // FTM3_CH6 is LED8 (for CAM1). |
| 331 | PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 332 | // FTM3_CH7 is LED9 (for CAM0). |
| 333 | PORTC_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 334 | |
| 335 | // This hardware has been deactivated, but keep this comment for now to |
| 336 | // document which pins it is on. |
| 337 | #if 0 |
| 338 | // This is ODROID_EN. |
| 339 | PERIPHERAL_BITBAND(GPIOC_PDDR, 0) = 1; |
| 340 | PERIPHERAL_BITBAND(GPIOC_PDOR, 0) = 0; |
| 341 | PORTC_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 342 | // This is CAM_EN. |
| 343 | PERIPHERAL_BITBAND(GPIOB_PDDR, 0) = 1; |
| 344 | PERIPHERAL_BITBAND(GPIOB_PDOR, 0) = 0; |
| 345 | PORTB_PCR0 = PORT_PCR_DSE | PORT_PCR_MUX(1); |
| 346 | #endif |
| 347 | // This is 5V_PGOOD. |
| 348 | PERIPHERAL_BITBAND(GPIOD_PDDR, 6) = 0; |
| 349 | PORTD_PCR6 = PORT_PCR_MUX(1); |
| 350 | |
| 351 | // These go to CAM1. |
| 352 | // UART0_RX (peripheral) is UART1_RX (schematic). |
| 353 | PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 354 | // UART0_TX (peripheral) is UART1_TX (schematic). |
| 355 | PORTA_PCR14 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 356 | |
| 357 | // These go to CAM0. |
| 358 | // UART1_RX (peripheral) is UART0_RX (schematic). |
| 359 | PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 360 | // UART1_TX (peripheral) is UART0_TX (schematic). |
| 361 | PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 362 | |
| 363 | // These go to CAM2. |
| 364 | // UART2_RX |
| 365 | PORTD_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 366 | // UART2_TX |
| 367 | PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 368 | |
| 369 | // These go to CAM3. |
| 370 | // UART3_RX |
| 371 | PORTB_PCR10 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 372 | // UART3_TX |
| 373 | PORTB_PCR11 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 374 | |
| 375 | // These go to CAM4. |
| 376 | // UART4_RX |
| 377 | PORTE_PCR25 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 378 | // UART4_TX |
| 379 | PORTE_PCR24 = PORT_PCR_DSE | PORT_PCR_MUX(3); |
| 380 | |
| 381 | Uarts uarts; |
| 382 | |
| 383 | // Give everything a chance to get going. |
| 384 | delay(100); |
| 385 | |
| 386 | printf("Ram start: %p\n", __bss_ram_start__); |
| 387 | printf("Heap start: %p\n", __heap_start__); |
| 388 | printf("Heap end: %p\n", __brkval); |
| 389 | printf("Stack start: %p\n", __stack_end__); |
| 390 | |
| 391 | uarts.Initialize(115200); |
| 392 | NVIC_ENABLE_IRQ(IRQ_UART0_STATUS); |
| 393 | NVIC_ENABLE_IRQ(IRQ_UART1_STATUS); |
| 394 | NVIC_ENABLE_IRQ(IRQ_UART2_STATUS); |
| 395 | NVIC_ENABLE_IRQ(IRQ_UART3_STATUS); |
| 396 | NVIC_ENABLE_IRQ(IRQ_UART4_STATUS); |
| 397 | |
| 398 | while (true) { |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | extern "C" { |
| 403 | |
| 404 | int main(void) { |
| 405 | return Main(); |
| 406 | } |
| 407 | |
| 408 | } // extern "C" |
| 409 | |
| 410 | } // namespace |
| 411 | } // namespace jevois |
| 412 | } // namespace frc971 |