blob: 89ca8646928c9cf3c9c0f70a197ca1955f3b29bc [file] [log] [blame]
Brian Silverman259c4432018-01-15 14:34:21 -08001// This file has the main for the Teensy on the button board.
2
3#include <stdio.h>
4#include <inttypes.h>
5#include <atomic>
6
7#include "motors/core/time.h"
8#include "motors/core/kinetis.h"
9#include "motors/peripheral/adc.h"
10#include "motors/peripheral/can.h"
11#include "motors/usb/usb.h"
12#include "motors/usb/cdc.h"
13#include "motors/usb/hid.h"
14#include "motors/util.h"
15
16namespace frc971 {
17namespace motors {
18namespace {
19
20::std::atomic<teensy::AcmTty *> global_stdout{nullptr};
21
22// The HID report descriptor we use.
23constexpr char kReportDescriptor[] = {
24 0x05, 0x01, // Usage Page (Generic Desktop),
25 0x09, 0x04, // Usage (Joystick),
26 0xA1, 0x01, // Collection (Application),
27 0x75, 0x08, // Report Size (8),
28 0x95, 0x04, // Report Count (4),
29 0x15, 0x00, // Logical Minimum (0),
30 0x26, 0xFF, 0x00, // Logical Maximum (255),
31 0x35, 0x00, // Physical Minimum (0),
32 0x46, 0xFF, 0x00, // Physical Maximum (255),
33 0x09, 0x30, // Usage (X),
34 0x09, 0x31, // Usage (Y),
35 0x09, 0x32, // Usage (Z),
36 0x09, 0x33, // Usage (Rz),
37 0x81, 0x02, // Input (Variable),
38 0x75, 0x01, // Report Size (1),
39 0x95, 0x14, // Report Count (20),
40 0x25, 0x01, // Logical Maximum (1),
41 0x45, 0x01, // Physical Maximum (1),
42 0x05, 0x09, // Usage Page (Button),
43 0x19, 0x01, // Usage Minimum (01),
44 0x29, 0x14, // Usage Maximum (20),
45 0x81, 0x02, // Input (Variable),
46 0x95, 0x04, // Report Count (4),
47 0x81, 0x03, // Input (Constant, Variable),
48 0xC0 // End Collection
49};
50
51constexpr uint16_t report_size() { return 1 * 4 + 3; }
52
53void SendJoystickData(teensy::HidFunction *joystick) {
54 uint32_t start = micros();
55 while (true) {
56 salsa::JoystickAdcReadings adc;
57 char report[report_size()];
58 {
59 DisableInterrupts disable_interrupts;
60 adc = salsa::AdcReadJoystick(disable_interrupts);
61 }
62
63 FTM0->C1V = adc.analog0 / 4;
64 FTM0->C0V = adc.analog1 / 4;
65 FTM0->C4V = adc.analog2 / 4;
66 FTM0->C3V = adc.analog3 / 4;
67 FTM0->PWMLOAD = FTM_PWMLOAD_LDOK;
68 report[0] = adc.analog0 / 16;
69 report[1] = adc.analog1 / 16;
70 report[2] = adc.analog2 / 16;
71 report[3] = adc.analog3 / 16;
72
73 report[4] = (GPIO_BITBAND(GPIOD_PDIR, 5) << 0) |
74 (GPIO_BITBAND(GPIOD_PDIR, 6) << 1) |
Brian Silverman772a3482018-02-05 23:54:00 -050075 (GPIO_BITBAND(GPIOB_PDIR, 0) << 2) |
Brian Silverman259c4432018-01-15 14:34:21 -080076 (GPIO_BITBAND(GPIOB_PDIR, 1) << 3) |
77 (GPIO_BITBAND(GPIOA_PDIR, 14) << 4) |
78 (GPIO_BITBAND(GPIOE_PDIR, 26) << 5) |
79 (GPIO_BITBAND(GPIOA_PDIR, 16) << 6) |
80 (GPIO_BITBAND(GPIOA_PDIR, 15) << 7);
81
82 report[5] = (GPIO_BITBAND(GPIOE_PDIR, 25) << 0) |
83 (GPIO_BITBAND(GPIOE_PDIR, 24) << 1) |
84 (GPIO_BITBAND(GPIOC_PDIR, 3) << 2) |
85 (GPIO_BITBAND(GPIOC_PDIR, 7) << 3) |
86 (GPIO_BITBAND(GPIOD_PDIR, 3) << 4) |
87 (GPIO_BITBAND(GPIOD_PDIR, 2) << 5) |
88 (GPIO_BITBAND(GPIOD_PDIR, 7) << 6) |
89 (GPIO_BITBAND(GPIOA_PDIR, 13) << 7);
90
91 report[6] = (GPIO_BITBAND(GPIOA_PDIR, 12) << 0) |
92 (GPIO_BITBAND(GPIOD_PDIR, 0) << 1) |
93 (GPIO_BITBAND(GPIOB_PDIR, 17) << 2) |
94 (GPIO_BITBAND(GPIOB_PDIR, 16) << 3);
95
96 {
97 DisableInterrupts disable_interrupts;
98 joystick->UpdateReport(report, sizeof(report), disable_interrupts);
99 }
100
101 start = delay_from(start, 1);
102 }
103}
104
105void SetupLedFtm(BigFTM *ftm) {
106 // PWMSYNC doesn't matter because we set SYNCMODE down below.
107 ftm->MODE = FTM_MODE_WPDIS;
108 ftm->MODE = FTM_MODE_WPDIS | FTM_MODE_FTMEN;
109 ftm->SC = FTM_SC_CLKS(0) /* Disable counting for now */;
110
111 // Use center-aligned high-true for all the channels.
112 ftm->C0SC = FTM_CSC_ELSB;
113 ftm->C0V = 0;
114 ftm->C1SC = FTM_CSC_ELSB;
115 ftm->C1V = 0;
116 ftm->C2SC = FTM_CSC_ELSB;
117 ftm->C2V = 0;
118 ftm->C3SC = FTM_CSC_ELSB;
119 ftm->C3V = 0;
120 ftm->C4SC = FTM_CSC_ELSB;
121 ftm->C4V = 0;
122 ftm->C5SC = FTM_CSC_ELSB;
123 ftm->C5V = 0;
124 ftm->C6SC = FTM_CSC_ELSB;
125 ftm->C6V = 0;
126 ftm->C7SC = FTM_CSC_ELSB;
127 ftm->C7V = 0;
128
129 ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
130 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
131 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
132 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */;
133
134 ftm->CNTIN = 0;
135 ftm->CNT = 0;
136 ftm->MOD = 1024;
137 ftm->OUTINIT = 0;
138 ftm->POL = 0;
139 ftm->SYNCONF =
140 FTM_SYNCONF_HWWRBUF /* Hardware trigger flushes switching points */ |
141 FTM_SYNCONF_SWWRBUF /* Software trigger flushes switching points */ |
142 FTM_SYNCONF_SWRSTCNT /* Software trigger resets the count */ |
143 FTM_SYNCONF_SYNCMODE /* Use the new synchronization mode */;
144 // Don't want any intermediate loading points.
145 ftm->PWMLOAD = 0;
146
147 ftm->SYNC = FTM_SYNC_SWSYNC /* Flush everything out right now */;
148 // Wait for the software synchronization to finish.
149 while (ftm->SYNC & FTM_SYNC_SWSYNC) {
150 }
151 ftm->SC = FTM_SC_CPWMS /* Center-aligned PWM */ |
152 FTM_SC_CLKS(1) /* Use the system clock */ |
153 FTM_SC_PS(60) /* Prescaler */;
154
155 ftm->MODE &= ~FTM_MODE_WPDIS;
156}
157
158} // namespace
159
160extern "C" {
161
162void *__stack_chk_guard = (void *)0x67111971;
163
164int _write(int /*file*/, char *ptr, int len) {
165 teensy::AcmTty *const tty = global_stdout.load(::std::memory_order_acquire);
166 if (tty != nullptr) {
167 return tty->Write(ptr, len);
168 }
169 return 0;
170}
171
172void __stack_chk_fail(void);
173
174} // extern "C"
175
176extern "C" int main(void) {
177 // for background about this startup delay, please see these conversations
178 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
179 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
180 delay(400);
181
182 // Set all interrupts to the second-lowest priority to start with.
183 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
184
185 // Now set priorities for all the ones we care about. They only have meaning
186 // relative to each other, which means centralizing them here makes it a lot
187 // more manageable.
188 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
189
190 // Set all the LED pins to output, slew rate controlled, high drive strength.
191 // Builtin
192 GPIO_BITBAND(GPIOC_PDOR, 5) = 1;
193 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_SRE | PORT_PCR_MUX(1);
194 GPIO_BITBAND(GPIOC_PDDR, 5) = 1;
195 // LED0 FTM0_CH1
196 GPIO_BITBAND(GPIOC_PDOR, 2) = 0;
197 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(4);
198 GPIO_BITBAND(GPIOC_PDDR, 2) = 1;
199 // LED1 FTM0_CH0
200 GPIO_BITBAND(GPIOC_PDOR, 1) = 0;
201 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(4);
202 GPIO_BITBAND(GPIOC_PDDR, 1) = 1;
203 // LED2 FTM0_CH4
204 GPIO_BITBAND(GPIOD_PDOR, 4) = 0;
205 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(4);
206 GPIO_BITBAND(GPIOD_PDDR, 4) = 1;
207 // LED3 FTM0_CH3
208 GPIO_BITBAND(GPIOC_PDOR, 4) = 0;
209 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(4);
210 GPIO_BITBAND(GPIOC_PDDR, 4) = 1;
211 // LED4 FTM3_CH4 yellow
212 GPIO_BITBAND(GPIOC_PDOR, 8) = 0;
213 PORTC_PCR8 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(1);
214 GPIO_BITBAND(GPIOC_PDDR, 8) = 1;
215 // LED5 FTM3_CH5 green
216 GPIO_BITBAND(GPIOC_PDOR, 9) = 0;
217 PORTC_PCR9 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(1);
218 GPIO_BITBAND(GPIOC_PDDR, 9) = 1;
219 // LED6 FTM3_CH6 red
220 GPIO_BITBAND(GPIOC_PDOR, 10) = 0;
221 PORTC_PCR10 = PORT_PCR_DSE | PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_MUX(1);
222 GPIO_BITBAND(GPIOC_PDDR, 10) = 1;
223
224 // Set up the CAN pins.
225 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(2);
226 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
227
228 // Set up the buttons. The LEDs pull them up to 5V, so the Teensy needs to not
229 // be set to pull up.
230 // BTN0
231 PORTD_PCR5 = PORT_PCR_MUX(1);
232 // BTN1
233 PORTD_PCR6 = PORT_PCR_MUX(1);
234 // BTN2
Brian Silverman772a3482018-02-05 23:54:00 -0500235 PORTB_PCR0 = PORT_PCR_MUX(1);
Brian Silverman259c4432018-01-15 14:34:21 -0800236 // BTN3
237 PORTB_PCR1 = PORT_PCR_MUX(1);
238 // BTN4
239 PORTA_PCR14 = PORT_PCR_MUX(1);
240 // BTN5
241 PORTE_PCR26 = PORT_PCR_MUX(1);
242 // BTN6
243 PORTA_PCR16 = PORT_PCR_MUX(1);
244 // BTN7
245 PORTA_PCR15 = PORT_PCR_MUX(1);
246 // BTN8
247 PORTE_PCR25 = PORT_PCR_MUX(1);
248 // BTN9
249 PORTE_PCR24 = PORT_PCR_MUX(1);
250 // BTN10
251 PORTC_PCR3 = PORT_PCR_MUX(1);
252 // BTN11
253 PORTC_PCR7 = PORT_PCR_MUX(1);
254 // BTN12
255 PORTD_PCR3 = PORT_PCR_MUX(1);
256 // BTN13
257 PORTD_PCR2 = PORT_PCR_MUX(1);
258 // BTN14
259 PORTD_PCR7 = PORT_PCR_MUX(1);
260 // BTN15
261 PORTA_PCR13 = PORT_PCR_MUX(1);
262 // BTN16
263 PORTA_PCR12 = PORT_PCR_MUX(1);
264 // BTN17
265 PORTD_PCR0 = PORT_PCR_MUX(1);
266 // BTN18
267 PORTB_PCR17 = PORT_PCR_MUX(1);
268 // BTN19
269 PORTB_PCR16 = PORT_PCR_MUX(1);
270
271 delay(100);
272
273 teensy::UsbDevice usb_device(0, 0x16c0, 0x0492);
274 usb_device.SetManufacturer("FRC 971 Spartan Robotics");
275 usb_device.SetProduct("Spartan Joystick Board");
276 teensy::HidFunction joystick(&usb_device, report_size());
277 joystick.set_report_descriptor(
278 ::std::string(kReportDescriptor, sizeof(kReportDescriptor)));
279 teensy::AcmTty tty1(&usb_device);
280 global_stdout.store(&tty1, ::std::memory_order_release);
281 usb_device.Initialize();
282
283 can_init(0, 1);
284 salsa::AdcInitJoystick();
285 SetupLedFtm(FTM0);
286 SetupLedFtm(FTM3);
287
288 // Leave the LEDs on for a bit longer.
289 delay(300);
290 printf("Done starting up\n");
291
292 // Done starting up, now turn all the LEDs off.
293 GPIO_BITBAND(GPIOC_PDOR, 5) = 0;
294 GPIO_BITBAND(GPIOC_PDOR, 2) = 1;
295 GPIO_BITBAND(GPIOC_PDOR, 1) = 1;
296 GPIO_BITBAND(GPIOD_PDOR, 4) = 1;
297 GPIO_BITBAND(GPIOC_PDOR, 4) = 1;
298 GPIO_BITBAND(GPIOC_PDOR, 8) = 1;
299 GPIO_BITBAND(GPIOC_PDOR, 9) = 1;
300 GPIO_BITBAND(GPIOC_PDOR, 10) = 1;
301
302 SendJoystickData(&joystick);
303
304 return 0;
305}
306
307void __stack_chk_fail(void) {
308 while (true) {
309 GPIOC_PSOR = (1 << 5);
310 printf("Stack corruption detected\n");
311 delay(1000);
312 GPIOC_PCOR = (1 << 5);
313 delay(1000);
314 }
315}
316
317} // namespace motors
318} // namespace frc971