blob: 80263cb9da05dd2239c3ba5b2559128e614e78f7 [file] [log] [blame]
Brian Silverman8b638692017-06-26 23:10:26 -07001#include "motors/core/kinetis.h"
2
3#include <stdio.h>
4
Brian Silverman8d3816a2017-07-03 18:52:15 -07005#include <atomic>
6
Brian Silverman36d06492018-05-12 11:52:35 -07007#include "motors/big/motor_controls.h"
Brian Silverman8b638692017-06-26 23:10:26 -07008#include "motors/core/time.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07009#include "motors/motor.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -070010#include "motors/peripheral/adc.h"
11#include "motors/peripheral/can.h"
Brian Silverman8b638692017-06-26 23:10:26 -070012#include "motors/usb/usb_serial.h"
13#include "motors/util.h"
14
15namespace frc971 {
Brian Silvermana96c1a42018-05-12 12:11:31 -070016namespace motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -070017namespace {
18
Brian Silverman9ed2cf12018-05-12 13:06:38 -070019struct MediumAdcReadings {
20 uint16_t motor_currents[3][2];
21 uint16_t motor_current_ref;
22 uint16_t input_voltage;
23};
24
25void AdcInitMedium() {
26 AdcInitCommon();
27
28 // M_CH2V ADC0_SE14
29 PORTC_PCR0 = PORT_PCR_MUX(0);
30
31 // M_CH0V ADC0_SE13
32 PORTB_PCR3 = PORT_PCR_MUX(0);
33
34 // M_CH1V ADC0_SE12
35 PORTB_PCR2 = PORT_PCR_MUX(0);
36
37 // M_CH0F ADC1_SE14
38 PORTB_PCR10 = PORT_PCR_MUX(0);
39
40 // M_CH1F ADC1_SE15
41 PORTB_PCR11 = PORT_PCR_MUX(0);
42
43 // M_VREF ADC0_SE18
44 PORTE_PCR25 = PORT_PCR_MUX(0);
45
46 // VIN ADC1_SE5B
47 PORTC_PCR9 = PORT_PCR_MUX(0);
48
49 // M_CH2F ADC1_SE17
50 PORTA_PCR17 = PORT_PCR_MUX(0);
51}
52
53MediumAdcReadings AdcReadMedium(const DisableInterrupts &) {
54 MediumAdcReadings r;
55
56 ADC1_SC1A = 14;
57 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
58 }
59 ADC1_SC1A = 15;
60 r.motor_currents[0][0] = ADC1_RA;
61 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
62 }
63 ADC1_SC1A = 17;
64 ADC0_SC1A = 18;
65 r.motor_currents[1][0] = ADC1_RA;
66 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
67 }
68 ADC1_SC1A = 5;
69 r.motor_currents[2][0] = ADC1_RA;
70 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
71 }
72 r.motor_current_ref = ADC0_RA;
73 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
74 }
75 ADC1_SC1A = 14;
76 r.input_voltage = ADC1_RA;
77 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
78 }
79 ADC1_SC1A = 15;
80 r.motor_currents[0][1] = ADC1_RA;
81 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
82 }
83 ADC1_SC1A = 17;
84 r.motor_currents[1][1] = ADC1_RA;
85 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
86 }
87 r.motor_currents[2][1] = ADC1_RA;
88
89 return r;
90}
91
Brian Silverman8d3816a2017-07-03 18:52:15 -070092::std::atomic<Motor *> global_motor{nullptr};
Brian Silverman8b638692017-06-26 23:10:26 -070093
94extern "C" {
Brian Silverman8d3816a2017-07-03 18:52:15 -070095
Brian Silverman8b638692017-06-26 23:10:26 -070096void *__stack_chk_guard = (void *)0x67111971;
Brian Silverman8d3816a2017-07-03 18:52:15 -070097void __stack_chk_fail(void) {
98 while (true) {
99 GPIOC_PSOR = (1 << 5);
100 printf("Stack corruption detected\n");
101 delay(1000);
102 GPIOC_PCOR = (1 << 5);
103 delay(1000);
104 }
105}
106
Brian Silverman8b638692017-06-26 23:10:26 -0700107extern void usb_init();
108int _write(int file, char *ptr, int len) {
109 (void)file;
110 return usb_serial_write(0, ptr, len);
111}
112
113void __stack_chk_fail(void);
114
115extern char *__brkval;
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400116extern uint32_t __bss_ram_start__[];
117extern uint32_t __heap_start__[];
118extern uint32_t __stack_end__[];
Brian Silverman8b638692017-06-26 23:10:26 -0700119
Brian Silverman8d3816a2017-07-03 18:52:15 -0700120void ftm0_isr(void) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800121 MediumAdcReadings adc_readings;
122 {
123 DisableInterrupts disable_interrupts;
124 adc_readings = AdcReadMedium(disable_interrupts);
125 }
126 ReadingsToBalance to_balance{{0, 0, 0}, {0, 0, 0}};
127 {
128 for (int reading = 0; reading < 2; ++reading) {
129 for (int phase = 0; phase < 3; ++phase) {
130 to_balance.Add(phase, adc_readings.motor_currents[phase][reading]);
131 }
132 }
133 }
134 const BalancedReadings balanced = BalanceReadings(to_balance);
135
136 global_motor.load(::std::memory_order_relaxed)->HandleInterrupt(
137 balanced,
138 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder());
Brian Silverman8d3816a2017-07-03 18:52:15 -0700139}
140
Brian Silverman8b638692017-06-26 23:10:26 -0700141} // extern "C"
Brian Silverman19ea60f2018-01-03 21:43:15 -0800142
143void ConfigurePwmFtm(BigFTM *pwm_ftm) {
144 // Put them all into combine active-high mode, and all the low ones staying on
145 // all the time by default.
146 pwm_ftm->C0SC = FTM_CSC_ELSA;
147 pwm_ftm->C0V = 0;
148 pwm_ftm->C1SC = FTM_CSC_ELSA;
149 pwm_ftm->C1V = 0;
150 pwm_ftm->C2SC = FTM_CSC_ELSA;
151 pwm_ftm->C2V = 0;
152 pwm_ftm->C3SC = FTM_CSC_ELSA;
153 pwm_ftm->C3V = 0;
154 pwm_ftm->C4SC = FTM_CSC_ELSA;
155 pwm_ftm->C4V = 0;
156 pwm_ftm->C5SC = FTM_CSC_ELSA;
157 pwm_ftm->C5V = 0;
158
159 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
160 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
161 FTM_COMBINE_COMP3 /* Make them complementary */ |
162 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
163 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
164 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
165 FTM_COMBINE_COMP2 /* Make them complementary */ |
166 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
167 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
168 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
169 FTM_COMBINE_COMP1 /* Make them complementary */ |
170 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
171 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
172 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
173 FTM_COMBINE_COMP0 /* Make them complementary */ |
174 FTM_COMBINE_COMBINE0 /* Combine the channels */;
175
176 // Set the deadtime.
177 pwm_ftm->DEADTIME =
178 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
179}
180
181// Zeros the encoder. This involves blocking for an arbitrary length of time
182// with interrupts disabled.
183void ZeroMotor() {
184#if 0
185 while (true) {
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500186 if (PERIPHERAL_BITBAND(GPIOE_PDIR, 24)) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800187 encoder_ftm_->CNT = 0;
188 break;
189 }
190 }
191#else
192 uint32_t scratch;
193 __disable_irq();
194 // Stuff all of this in an inline assembly statement so we can make sure the
195 // compiler doesn't decide sticking constant loads etc in the middle of
196 // the loop is a good idea, because that increases the latency of recognizing
197 // the index pulse edge which makes velocity affect the zeroing accuracy.
198 __asm__ __volatile__(
199 // A label to restart the loop.
200 "0:\n"
201 // Load the current PDIR value for the pin we care about.
202 "ldr %[scratch], [%[pdir_word]]\n"
203 // Terminate the loop if it's non-0.
204 "cbnz %[scratch], 1f\n"
205 // Go back around again.
206 "b 0b\n"
207 // A label to finish the loop.
208 "1:\n"
209 // Reset the count once we're down here. It doesn't actually matter what
210 // value we store because writing anything resets it to CNTIN (ie 0).
211 "str %[scratch], [%[cnt]]\n"
212 : [scratch] "=&l"(scratch)
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500213 : [pdir_word] "l"(&PERIPHERAL_BITBAND(GPIOE_PDIR, 24)),
Brian Silverman19ea60f2018-01-03 21:43:15 -0800214 [cnt] "l"(&FTM1->CNT));
215 __enable_irq();
216#endif
217}
218
Brian Silverman8d3816a2017-07-03 18:52:15 -0700219} // namespace
Brian Silverman8b638692017-06-26 23:10:26 -0700220
221extern "C" int main(void) {
222 // for background about this startup delay, please see these conversations
223 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
224 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
225 delay(400);
226
227 // Set all interrupts to the second-lowest priority to start with.
228 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
229
230 // Now set priorities for all the ones we care about. They only have meaning
231 // relative to each other, which means centralizing them here makes it a lot
232 // more manageable.
233 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700234 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
Brian Silverman8b638692017-06-26 23:10:26 -0700235
236 // Set the LED's pin to output mode.
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500237 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
Brian Silverman8b638692017-06-26 23:10:26 -0700238 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
239
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500240 PERIPHERAL_BITBAND(GPIOA_PDDR, 15) = 1;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700241 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
242
Brian Silverman19ea60f2018-01-03 21:43:15 -0800243 // Set up the CAN pins.
244 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(2);
245 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
246
Brian Silverman8d3816a2017-07-03 18:52:15 -0700247 DMA_CR = DMA_CR_EMLM;
Brian Silverman8b638692017-06-26 23:10:26 -0700248 usb_serial_init();
249 usb_descriptor_set_product_id(0x0490);
250 usb_init();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800251 AdcInitMedium();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700252 MathInit();
253 delay(1000);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800254 can_init(0, 1);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700255
Brian Silverman19ea60f2018-01-03 21:43:15 -0800256 GPIOD_PCOR = 1 << 3;
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500257 PERIPHERAL_BITBAND(GPIOD_PDDR, 3) = 1;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800258 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
259 delay(1000);
260 GPIOD_PSOR = 1 << 3;
261 delay(1000);
262 GPIOD_PCOR = 1 << 3;
263 delay(1000);
264
Brian Silverman8d3816a2017-07-03 18:52:15 -0700265 MotorControlsImplementation controls;
266
267 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800268
269 // Index pin
270 PORTE_PCR24 = PORT_PCR_MUX(1);
271 // FTM1_QD_PH{A,B}
272 PORTB_PCR0 = PORT_PCR_MUX(6);
273 PORTB_PCR1 = PORT_PCR_MUX(6);
274
275 // FTM0_CH[0-5]
276 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
277 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
278 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
279 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
280 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
281 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
282
283 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
284 motor.set_encoder_offset(810);
285 motor.set_deadtime_compensation(9);
286 ConfigurePwmFtm(FTM0);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700287 motor.Init();
288 global_motor.store(&motor, ::std::memory_order_relaxed);
289 // Output triggers to things like the PDBs on initialization.
290 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
291 // Don't let any memory accesses sneak past here, because we actually
292 // need everything to be starting up.
293 __asm__("" :: : "memory");
Brian Silverman8b638692017-06-26 23:10:26 -0700294
295 // Give everything a chance to get going.
296 delay(100);
297
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400298 printf("Ram start: %p\n", __bss_ram_start__);
299 printf("Heap start: %p\n", __heap_start__);
Brian Silverman8b638692017-06-26 23:10:26 -0700300 printf("Heap end: %p\n", __brkval);
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400301 printf("Stack start: %p\n", __stack_end__);
Brian Silverman8b638692017-06-26 23:10:26 -0700302
Brian Silverman8d3816a2017-07-03 18:52:15 -0700303 printf("Going silent to zero motors...\n");
304 // Give the print a chance to make it out.
305 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800306 ZeroMotor();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700307
308 printf("Zeroed motor!\n");
309 // Give stuff a chance to recover from interrupts-disabled.
310 delay(100);
311 motor.Start();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800312 NVIC_ENABLE_IRQ(IRQ_FTM0);
313 GPIOC_PSOR = 1 << 5;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700314
Brian Silverman19ea60f2018-01-03 21:43:15 -0800315 float current_command = 0;
316 while (true) {
317 unsigned char command_data[8];
318 int command_length;
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700319 can_receive(command_data, &command_length, 0);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800320 if (command_length == 4) {
321 uint32_t result = command_data[0] << 24 | command_data[1] << 16 |
322 command_data[2] << 8 | command_data[3];
323 float current = static_cast<float>(result) / 1000.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700324
Brian Silverman19ea60f2018-01-03 21:43:15 -0800325 static bool high_gear = false;
326 if (controls.estimated_velocity() < -2015) {
327 high_gear = true;
328 }
329 if (current < 1) {
330 high_gear = false;
331 }
332 if (!high_gear) {
333 current = current_command * -120.0f / 120.0f;
334 } else {
335 current = current_command * 115.0f / 120.0f;
336 }
337 motor.SetGoalCurrent(current);
338 current_command = current;
339 }
340 }
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400341
Brian Silverman8b638692017-06-26 23:10:26 -0700342 return 0;
343}
344
Brian Silvermana96c1a42018-05-12 12:11:31 -0700345} // namespace motors
Brian Silverman8b638692017-06-26 23:10:26 -0700346} // namespace frc971