blob: 3ac0337d801f1f52e60cfe9624f047a8e2a5d781 [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 Silverman8b638692017-06-26 23:10:26 -07007#include "motors/core/time.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07008#include "motors/motor.h"
9#include "motors/motor_controls.h"
10#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 {
16namespace salsa {
Brian Silverman8d3816a2017-07-03 18:52:15 -070017namespace {
18
19::std::atomic<Motor *> global_motor{nullptr};
Brian Silverman8b638692017-06-26 23:10:26 -070020
21extern "C" {
Brian Silverman8d3816a2017-07-03 18:52:15 -070022
Brian Silverman8b638692017-06-26 23:10:26 -070023void *__stack_chk_guard = (void *)0x67111971;
Brian Silverman8d3816a2017-07-03 18:52:15 -070024void __stack_chk_fail(void) {
25 while (true) {
26 GPIOC_PSOR = (1 << 5);
27 printf("Stack corruption detected\n");
28 delay(1000);
29 GPIOC_PCOR = (1 << 5);
30 delay(1000);
31 }
32}
33
Brian Silverman8b638692017-06-26 23:10:26 -070034extern void usb_init();
35int _write(int file, char *ptr, int len) {
36 (void)file;
37 return usb_serial_write(0, ptr, len);
38}
39
40void __stack_chk_fail(void);
41
42extern char *__brkval;
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -040043extern uint32_t __bss_ram_start__[];
44extern uint32_t __heap_start__[];
45extern uint32_t __stack_end__[];
Brian Silverman8b638692017-06-26 23:10:26 -070046
Brian Silverman8d3816a2017-07-03 18:52:15 -070047void ftm0_isr(void) {
Brian Silverman19ea60f2018-01-03 21:43:15 -080048 MediumAdcReadings adc_readings;
49 {
50 DisableInterrupts disable_interrupts;
51 adc_readings = AdcReadMedium(disable_interrupts);
52 }
53 ReadingsToBalance to_balance{{0, 0, 0}, {0, 0, 0}};
54 {
55 for (int reading = 0; reading < 2; ++reading) {
56 for (int phase = 0; phase < 3; ++phase) {
57 to_balance.Add(phase, adc_readings.motor_currents[phase][reading]);
58 }
59 }
60 }
61 const BalancedReadings balanced = BalanceReadings(to_balance);
62
63 global_motor.load(::std::memory_order_relaxed)->HandleInterrupt(
64 balanced,
65 global_motor.load(::std::memory_order_relaxed)->wrapped_encoder());
Brian Silverman8d3816a2017-07-03 18:52:15 -070066}
67
Brian Silverman8b638692017-06-26 23:10:26 -070068} // extern "C"
Brian Silverman19ea60f2018-01-03 21:43:15 -080069
70void ConfigurePwmFtm(BigFTM *pwm_ftm) {
71 // Put them all into combine active-high mode, and all the low ones staying on
72 // all the time by default.
73 pwm_ftm->C0SC = FTM_CSC_ELSA;
74 pwm_ftm->C0V = 0;
75 pwm_ftm->C1SC = FTM_CSC_ELSA;
76 pwm_ftm->C1V = 0;
77 pwm_ftm->C2SC = FTM_CSC_ELSA;
78 pwm_ftm->C2V = 0;
79 pwm_ftm->C3SC = FTM_CSC_ELSA;
80 pwm_ftm->C3V = 0;
81 pwm_ftm->C4SC = FTM_CSC_ELSA;
82 pwm_ftm->C4V = 0;
83 pwm_ftm->C5SC = FTM_CSC_ELSA;
84 pwm_ftm->C5V = 0;
85
86 pwm_ftm->COMBINE = FTM_COMBINE_SYNCEN3 /* Synchronize updates usefully */ |
87 FTM_COMBINE_DTEN3 /* Enable deadtime */ |
88 FTM_COMBINE_COMP3 /* Make them complementary */ |
89 FTM_COMBINE_COMBINE3 /* Combine the channels */ |
90 FTM_COMBINE_SYNCEN2 /* Synchronize updates usefully */ |
91 FTM_COMBINE_DTEN2 /* Enable deadtime */ |
92 FTM_COMBINE_COMP2 /* Make them complementary */ |
93 FTM_COMBINE_COMBINE2 /* Combine the channels */ |
94 FTM_COMBINE_SYNCEN1 /* Synchronize updates usefully */ |
95 FTM_COMBINE_DTEN1 /* Enable deadtime */ |
96 FTM_COMBINE_COMP1 /* Make them complementary */ |
97 FTM_COMBINE_COMBINE1 /* Combine the channels */ |
98 FTM_COMBINE_SYNCEN0 /* Synchronize updates usefully */ |
99 FTM_COMBINE_DTEN0 /* Enable deadtime */ |
100 FTM_COMBINE_COMP0 /* Make them complementary */ |
101 FTM_COMBINE_COMBINE0 /* Combine the channels */;
102
103 // Set the deadtime.
104 pwm_ftm->DEADTIME =
105 FTM_DEADTIME_DTPS(0) /* Prescaler of 1 */ | FTM_DEADTIME_DTVAL(9);
106}
107
108// Zeros the encoder. This involves blocking for an arbitrary length of time
109// with interrupts disabled.
110void ZeroMotor() {
111#if 0
112 while (true) {
113 if (GPIO_BITBAND(GPIOE_PDIR, 24)) {
114 encoder_ftm_->CNT = 0;
115 break;
116 }
117 }
118#else
119 uint32_t scratch;
120 __disable_irq();
121 // Stuff all of this in an inline assembly statement so we can make sure the
122 // compiler doesn't decide sticking constant loads etc in the middle of
123 // the loop is a good idea, because that increases the latency of recognizing
124 // the index pulse edge which makes velocity affect the zeroing accuracy.
125 __asm__ __volatile__(
126 // A label to restart the loop.
127 "0:\n"
128 // Load the current PDIR value for the pin we care about.
129 "ldr %[scratch], [%[pdir_word]]\n"
130 // Terminate the loop if it's non-0.
131 "cbnz %[scratch], 1f\n"
132 // Go back around again.
133 "b 0b\n"
134 // A label to finish the loop.
135 "1:\n"
136 // Reset the count once we're down here. It doesn't actually matter what
137 // value we store because writing anything resets it to CNTIN (ie 0).
138 "str %[scratch], [%[cnt]]\n"
139 : [scratch] "=&l"(scratch)
140 : [pdir_word] "l"(&GPIO_BITBAND(GPIOE_PDIR, 24)),
141 [cnt] "l"(&FTM1->CNT));
142 __enable_irq();
143#endif
144}
145
Brian Silverman8d3816a2017-07-03 18:52:15 -0700146} // namespace
Brian Silverman8b638692017-06-26 23:10:26 -0700147
148extern "C" int main(void) {
149 // for background about this startup delay, please see these conversations
150 // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
151 // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
152 delay(400);
153
154 // Set all interrupts to the second-lowest priority to start with.
155 for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
156
157 // Now set priorities for all the ones we care about. They only have meaning
158 // relative to each other, which means centralizing them here makes it a lot
159 // more manageable.
160 NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700161 NVIC_SET_SANE_PRIORITY(IRQ_FTM0, 0x3);
Brian Silverman8b638692017-06-26 23:10:26 -0700162
163 // Set the LED's pin to output mode.
164 GPIO_BITBAND(GPIOC_PDDR, 5) = 1;
165 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
166
Brian Silverman8d3816a2017-07-03 18:52:15 -0700167 GPIO_BITBAND(GPIOA_PDDR, 15) = 1;
168 PORTA_PCR15 = PORT_PCR_DSE | PORT_PCR_MUX(1);
169
Brian Silverman19ea60f2018-01-03 21:43:15 -0800170 // Set up the CAN pins.
171 PORTB_PCR18 = PORT_PCR_DSE | PORT_PCR_MUX(2);
172 PORTB_PCR19 = PORT_PCR_DSE | PORT_PCR_MUX(2);
173
Brian Silverman8d3816a2017-07-03 18:52:15 -0700174 DMA_CR = DMA_CR_EMLM;
Brian Silverman8b638692017-06-26 23:10:26 -0700175 usb_serial_init();
176 usb_descriptor_set_product_id(0x0490);
177 usb_init();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800178 AdcInitMedium();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700179 MathInit();
180 delay(1000);
Brian Silverman7c7170e2018-01-13 17:41:21 -0800181 can_init(0, 1);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700182
Brian Silverman19ea60f2018-01-03 21:43:15 -0800183 GPIOD_PCOR = 1 << 3;
184 GPIO_BITBAND(GPIOD_PDDR, 3) = 1;
185 PORTD_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(1);
186 delay(1000);
187 GPIOD_PSOR = 1 << 3;
188 delay(1000);
189 GPIOD_PCOR = 1 << 3;
190 delay(1000);
191
Brian Silverman8d3816a2017-07-03 18:52:15 -0700192 MotorControlsImplementation controls;
193
194 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800195
196 // Index pin
197 PORTE_PCR24 = PORT_PCR_MUX(1);
198 // FTM1_QD_PH{A,B}
199 PORTB_PCR0 = PORT_PCR_MUX(6);
200 PORTB_PCR1 = PORT_PCR_MUX(6);
201
202 // FTM0_CH[0-5]
203 PORTC_PCR1 = PORT_PCR_DSE | PORT_PCR_MUX(4);
204 PORTC_PCR2 = PORT_PCR_DSE | PORT_PCR_MUX(4);
205 PORTC_PCR3 = PORT_PCR_DSE | PORT_PCR_MUX(4);
206 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
207 PORTD_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(4);
208 PORTD_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(4);
209
210 Motor motor(FTM0, FTM1, &controls, {&FTM0->C0V, &FTM0->C2V, &FTM0->C4V});
211 motor.set_encoder_offset(810);
212 motor.set_deadtime_compensation(9);
213 ConfigurePwmFtm(FTM0);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700214 motor.Init();
215 global_motor.store(&motor, ::std::memory_order_relaxed);
216 // Output triggers to things like the PDBs on initialization.
217 FTM0_EXTTRIG = FTM_EXTTRIG_INITTRIGEN;
218 // Don't let any memory accesses sneak past here, because we actually
219 // need everything to be starting up.
220 __asm__("" :: : "memory");
Brian Silverman8b638692017-06-26 23:10:26 -0700221
222 // Give everything a chance to get going.
223 delay(100);
224
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400225 printf("Ram start: %p\n", __bss_ram_start__);
226 printf("Heap start: %p\n", __heap_start__);
Brian Silverman8b638692017-06-26 23:10:26 -0700227 printf("Heap end: %p\n", __brkval);
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400228 printf("Stack start: %p\n", __stack_end__);
Brian Silverman8b638692017-06-26 23:10:26 -0700229
Brian Silverman8d3816a2017-07-03 18:52:15 -0700230 printf("Going silent to zero motors...\n");
231 // Give the print a chance to make it out.
232 delay(1000);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800233 ZeroMotor();
Brian Silverman8d3816a2017-07-03 18:52:15 -0700234
235 printf("Zeroed motor!\n");
236 // Give stuff a chance to recover from interrupts-disabled.
237 delay(100);
238 motor.Start();
Brian Silverman19ea60f2018-01-03 21:43:15 -0800239 NVIC_ENABLE_IRQ(IRQ_FTM0);
240 GPIOC_PSOR = 1 << 5;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700241
Brian Silverman19ea60f2018-01-03 21:43:15 -0800242 float current_command = 0;
243 while (true) {
244 unsigned char command_data[8];
245 int command_length;
Brian Silverman7c7170e2018-01-13 17:41:21 -0800246 can_receive_command(command_data, &command_length, 0);
Brian Silverman19ea60f2018-01-03 21:43:15 -0800247 if (command_length == 4) {
248 uint32_t result = command_data[0] << 24 | command_data[1] << 16 |
249 command_data[2] << 8 | command_data[3];
250 float current = static_cast<float>(result) / 1000.0f;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700251
Brian Silverman19ea60f2018-01-03 21:43:15 -0800252 static bool high_gear = false;
253 if (controls.estimated_velocity() < -2015) {
254 high_gear = true;
255 }
256 if (current < 1) {
257 high_gear = false;
258 }
259 if (!high_gear) {
260 current = current_command * -120.0f / 120.0f;
261 } else {
262 current = current_command * 115.0f / 120.0f;
263 }
264 motor.SetGoalCurrent(current);
265 current_command = current;
266 }
267 }
Brian Silvermanf1ad1bc2017-09-23 13:08:36 -0400268
Brian Silverman8b638692017-06-26 23:10:26 -0700269 return 0;
270}
271
Brian Silverman8b638692017-06-26 23:10:26 -0700272} // namespace salsa
273} // namespace frc971