blob: b754715185cbe9ebf8f985045895e14299f872f0 [file] [log] [blame]
Brian Silverman8b638692017-06-26 23:10:26 -07001#include <stdio.h>
2
Brian Silverman8d3816a2017-07-03 18:52:15 -07003#include <atomic>
4
Brian Silverman36d06492018-05-12 11:52:35 -07005#include "motors/big/motor_controls.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07006#include "motors/core/kinetis.h"
Brian Silverman8b638692017-06-26 23:10:26 -07007#include "motors/core/time.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07008#include "motors/motor.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07009#include "motors/peripheral/adc.h"
10#include "motors/peripheral/can.h"
Brian Silverman8b638692017-06-26 23:10:26 -070011#include "motors/usb/usb_serial.h"
12#include "motors/util.h"
13
Stephan Pleinesf63bde82024-01-13 15:59:33 -080014namespace frc971::motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -070015namespace {
16
Brian Silverman9ed2cf12018-05-12 13:06:38 -070017struct MediumAdcReadings {
18 uint16_t motor_currents[3][2];
19 uint16_t motor_current_ref;
20 uint16_t input_voltage;
21};
22
23void AdcInitMedium() {
24 AdcInitCommon();
25
26 // M_CH2V ADC0_SE14
27 PORTC_PCR0 = PORT_PCR_MUX(0);
28
29 // M_CH0V ADC0_SE13
30 PORTB_PCR3 = PORT_PCR_MUX(0);
31
32 // M_CH1V ADC0_SE12
33 PORTB_PCR2 = PORT_PCR_MUX(0);
34
35 // M_CH0F ADC1_SE14
36 PORTB_PCR10 = PORT_PCR_MUX(0);
37
38 // M_CH1F ADC1_SE15
39 PORTB_PCR11 = PORT_PCR_MUX(0);
40
41 // M_VREF ADC0_SE18
42 PORTE_PCR25 = PORT_PCR_MUX(0);
43
44 // VIN ADC1_SE5B
45 PORTC_PCR9 = PORT_PCR_MUX(0);
46
47 // M_CH2F ADC1_SE17
48 PORTA_PCR17 = PORT_PCR_MUX(0);
49}
50
51MediumAdcReadings AdcReadMedium(const DisableInterrupts &) {
52 MediumAdcReadings r;
53
54 ADC1_SC1A = 14;
55 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
56 }
57 ADC1_SC1A = 15;
58 r.motor_currents[0][0] = ADC1_RA;
59 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
60 }
61 ADC1_SC1A = 17;
62 ADC0_SC1A = 18;
63 r.motor_currents[1][0] = ADC1_RA;
64 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
65 }
66 ADC1_SC1A = 5;
67 r.motor_currents[2][0] = ADC1_RA;
68 while (!(ADC0_SC1A & ADC_SC1_COCO)) {
69 }
70 r.motor_current_ref = ADC0_RA;
71 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
72 }
73 ADC1_SC1A = 14;
74 r.input_voltage = ADC1_RA;
75 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
76 }
77 ADC1_SC1A = 15;
78 r.motor_currents[0][1] = ADC1_RA;
79 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
80 }
81 ADC1_SC1A = 17;
82 r.motor_currents[1][1] = ADC1_RA;
83 while (!(ADC1_SC1A & ADC_SC1_COCO)) {
84 }
85 r.motor_currents[2][1] = ADC1_RA;
86
87 return r;
88}
89
Brian Silverman8d3816a2017-07-03 18:52:15 -070090::std::atomic<Motor *> global_motor{nullptr};
Brian Silverman8b638692017-06-26 23:10:26 -070091
92extern "C" {
Brian Silverman8d3816a2017-07-03 18:52:15 -070093
Brian Silverman8b638692017-06-26 23:10:26 -070094void *__stack_chk_guard = (void *)0x67111971;
Brian Silverman8d3816a2017-07-03 18:52:15 -070095void __stack_chk_fail(void) {
96 while (true) {
97 GPIOC_PSOR = (1 << 5);
98 printf("Stack corruption detected\n");
99 delay(1000);
100 GPIOC_PCOR = (1 << 5);
101 delay(1000);
102 }
103}
104
Brian Silverman8b638692017-06-26 23:10:26 -0700105extern void usb_init();
106int _write(int file, char *ptr, int len) {
107 (void)file;
108 return usb_serial_write(0, ptr, len);
109}
110
111void __stack_chk_fail(void);
112
113extern char *__brkval;
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400114extern uint32_t __bss_ram_start__[];
115extern uint32_t __heap_start__[];
116extern uint32_t __stack_end__[];
Brian Silverman8b638692017-06-26 23:10:26 -0700117
Brian Silverman8d3816a2017-07-03 18:52:15 -0700118void ftm0_isr(void) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800119 MediumAdcReadings adc_readings;
120 {
121 DisableInterrupts disable_interrupts;
122 adc_readings = AdcReadMedium(disable_interrupts);
123 }
124 ReadingsToBalance to_balance{{0, 0, 0}, {0, 0, 0}};
125 {
126 for (int reading = 0; reading < 2; ++reading) {
127 for (int phase = 0; phase < 3; ++phase) {
128 to_balance.Add(phase, adc_readings.motor_currents[phase][reading]);
129 }
130 }
131 }
132 const BalancedReadings balanced = BalanceReadings(to_balance);
133
Philipp Schrader790cb542023-07-05 21:06:52 -0700134 global_motor.load(::std::memory_order_relaxed)
135 ->CurrentInterrupt(
136 balanced,
137 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder());
Brian Silverman8d3816a2017-07-03 18:52:15 -0700138}
139
Brian Silverman8b638692017-06-26 23:10:26 -0700140} // extern "C"
Brian Silverman19ea60f2018-01-03 21:43:15 -0800141
142void ConfigurePwmFtm(BigFTM *pwm_ftm) {
143 // Put them all into combine active-high mode, and all the low ones staying on
144 // all the time by default.
145 pwm_ftm->C0SC = FTM_CSC_ELSA;
146 pwm_ftm->C0V = 0;
147 pwm_ftm->C1SC = FTM_CSC_ELSA;
148 pwm_ftm->C1V = 0;
149 pwm_ftm->C2SC = FTM_CSC_ELSA;
150 pwm_ftm->C2V = 0;
151 pwm_ftm->C3SC = FTM_CSC_ELSA;
152 pwm_ftm->C3V = 0;
153 pwm_ftm->C4SC = FTM_CSC_ELSA;
154 pwm_ftm->C4V = 0;
155 pwm_ftm->C5SC = FTM_CSC_ELSA;
156 pwm_ftm->C5V = 0;
157
158 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
159 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
160 FTM_COMBINE_COMP3 /* Make them complementary */ |
161 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
162 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
163 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
164 FTM_COMBINE_COMP2 /* Make them complementary */ |
165 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
166 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
167 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
168 FTM_COMBINE_COMP1 /* Make them complementary */ |
169 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
170 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
171 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
172 FTM_COMBINE_COMP0 /* Make them complementary */ |
173 FTM_COMBINE_COMBINE0 /* Combine the channels */;
174
175 // Set the deadtime.
176 pwm_ftm->DEADTIME =
177 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
178}
179
180// Zeros the encoder. This involves blocking for an arbitrary length of time
181// with interrupts disabled.
182void ZeroMotor() {
183#if 0
184 while (true) {
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500185 if (PERIPHERAL_BITBAND(GPIOE_PDIR, 24)) {
Brian Silverman19ea60f2018-01-03 21:43:15 -0800186 encoder_ftm_->CNT = 0;
187 break;
188 }
189 }
190#else
191 uint32_t scratch;
192 __disable_irq();
193 // Stuff all of this in an inline assembly statement so we can make sure the
194 // compiler doesn't decide sticking constant loads etc in the middle of
195 // the loop is a good idea, because that increases the latency of recognizing
196 // the index pulse edge which makes velocity affect the zeroing accuracy.
197 __asm__ __volatile__(
198 // A label to restart the loop.
199 "0:\n"
200 // Load the current PDIR value for the pin we care about.
201 "ldr %[scratch], [%[pdir_word]]\n"
202 // Terminate the loop if it's non-0.
203 "cbnz %[scratch], 1f\n"
204 // Go back around again.
205 "b 0b\n"
206 // A label to finish the loop.
207 "1:\n"
208 // Reset the count once we're down here. It doesn't actually matter what
209 // value we store because writing anything resets it to CNTIN (ie 0).
210 "str %[scratch], [%[cnt]]\n"
211 : [scratch] "=&l"(scratch)
Philipp Schrader790cb542023-07-05 21:06:52 -0700212 : [pdir_word] "l"(&PERIPHERAL_BITBAND(GPIOE_PDIR, 24)), [cnt] "l"(
213 &FTM1->CNT));
Brian Silverman19ea60f2018-01-03 21:43:15 -0800214 __enable_irq();
215#endif
216}
217
Brian Silverman8d3816a2017-07-03 18:52:15 -0700218} // namespace
Brian Silverman8b638692017-06-26 23:10:26 -0700219
220extern "C" int main(void) {
221 // for background about this startup delay, please see these conversations
222 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
223 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
224 delay(400);
225
226 // Set all interrupts to the second-lowest priority to start with.
227 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
228
229 // Now set priorities for all the ones we care about. They only have meaning
230 // relative to each other, which means centralizing them here makes it a lot
231 // more manageable.
232 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700233 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
Brian Silverman8b638692017-06-26 23:10:26 -0700234
235 // Set the LED's pin to output mode.
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500236 PERIPHERAL_BITBAND(GPIOC_PDDR, 5) = 1;
Brian Silverman8b638692017-06-26 23:10:26 -0700237 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
238
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500239 PERIPHERAL_BITBAND(GPIOA_PDDR, 15) = 1;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700240 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
241
Brian Silverman19ea60f2018-01-03 21:43:15 -0800242 // Set up the CAN pins.
243 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(2);
244 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
245
Brian Silverman45564a82018-09-02 16:35:22 -0700246 DMA.CR = M_DMA_EMLM;
Brian Silverman8b638692017-06-26 23:10:26 -0700247 usb_serial_init();
248 usb_descriptor_set_product_id(0x0490);
249 usb_init();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800250 AdcInitMedium();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700251 MathInit();
252 delay(1000);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800253 can_init(0, 1);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700254
Brian Silverman19ea60f2018-01-03 21:43:15 -0800255 GPIOD_PCOR = 1 << 3;
Brian Silverman33eb5fa2018-02-11 18:36:19 -0500256 PERIPHERAL_BITBAND(GPIOD_PDDR, 3) = 1;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800257 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
258 delay(1000);
259 GPIOD_PSOR = 1 << 3;
260 delay(1000);
261 GPIOD_PCOR = 1 << 3;
262 delay(1000);
263
Brian Silverman8d3816a2017-07-03 18:52:15 -0700264 MotorControlsImplementation controls;
265
266 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800267
268 // Index pin
269 PORTE_PCR24 = PORT_PCR_MUX(1);
270 // FTM1_QD_PH{A,B}
271 PORTB_PCR0 = PORT_PCR_MUX(6);
272 PORTB_PCR1 = PORT_PCR_MUX(6);
273
274 // FTM0_CH[0-5]
275 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
276 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
277 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
278 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
279 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
280 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
281
282 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
283 motor.set_encoder_offset(810);
284 motor.set_deadtime_compensation(9);
285 ConfigurePwmFtm(FTM0);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700286 motor.Init();
287 global_motor.store(&motor, ::std::memory_order_relaxed);
288 // Output triggers to things like the PDBs on initialization.
289 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
290 // Don't let any memory accesses sneak past here, because we actually
291 // need everything to be starting up.
Philipp Schrader790cb542023-07-05 21:06:52 -0700292 __asm__("" ::: "memory");
Brian Silverman8b638692017-06-26 23:10:26 -0700293
294 // Give everything a chance to get going.
295 delay(100);
296
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400297 printf("Ram start: %p\n", __bss_ram_start__);
298 printf("Heap start: %p\n", __heap_start__);
Brian Silverman8b638692017-06-26 23:10:26 -0700299 printf("Heap end: %p\n", __brkval);
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400300 printf("Stack start: %p\n", __stack_end__);
Brian Silverman8b638692017-06-26 23:10:26 -0700301
Brian Silverman8d3816a2017-07-03 18:52:15 -0700302 printf("Going silent to zero motors...\n");
303 // Give the print a chance to make it out.
304 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800305 ZeroMotor();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700306
307 printf("Zeroed motor!\n");
308 // Give stuff a chance to recover from interrupts-disabled.
309 delay(100);
310 motor.Start();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800311 NVIC_ENABLE_IRQ(IRQ_FTM0);
312 GPIOC_PSOR = 1 << 5;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700313
Brian Silverman19ea60f2018-01-03 21:43:15 -0800314 float current_command = 0;
315 while (true) {
316 unsigned char command_data[8];
317 int command_length;
Brian Silverman54dd2fe2018-03-16 23:44:31 -0700318 can_receive(command_data, &command_length, 0);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800319 if (command_length == 4) {
320 uint32_t result = command_data[0] << 24 | command_data[1] << 16 |
321 command_data[2] << 8 | command_data[3];
322 float current = static_cast<float>(result) / 1000.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700323
Brian Silverman19ea60f2018-01-03 21:43:15 -0800324 static bool high_gear = false;
325 if (controls.estimated_velocity() < -2015) {
326 high_gear = true;
327 }
328 if (current < 1) {
329 high_gear = false;
330 }
331 if (!high_gear) {
332 current = current_command * -120.0f / 120.0f;
333 } else {
334 current = current_command * 115.0f / 120.0f;
335 }
336 motor.SetGoalCurrent(current);
337 current_command = current;
338 }
339 }
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400340
Brian Silverman8b638692017-06-26 23:10:26 -0700341 return 0;
342}
343
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800344} // namespace frc971::motors