blob: 0df1c4cba32cbc4e9c64669de5768d39120c346b [file] [log] [blame]
brians0ab60bb2013-01-31 02:21:51 +00001/*
2 FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.
3
4 This file is part of the FreeRTOS distribution.
5
6 FreeRTOS is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License (version 2) as published by the
8 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
9 ***NOTE*** The exception to the GPL is included to allow you to distribute
10 a combined work that includes FreeRTOS without being obliged to provide the
11 source code for proprietary components outside of the FreeRTOS kernel.
12 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details. You should have received a copy of the GNU General Public
16 License and the FreeRTOS license exception along with FreeRTOS; if not it
17 can be viewed here: http://www.freertos.org/a00114.html and also obtained
18 by writing to Richard Barry, contact details for whom are available on the
19 FreeRTOS WEB site.
20
21*/
22
23/* Standard includes. */
24#include "stdio.h"
25
26/* Scheduler includes. */
27#include "FreeRTOS.h"
28#include "queue.h"
29#include "task.h"
30
31/* Demo app includes. */
32#include "flash.h"
33#include "partest.h"
brians0ab60bb2013-01-31 02:21:51 +000034#include "spi.h"
35#include "LPCUSB/usbapi.h"
36
Brian Silvermanf92396c2013-09-12 20:13:13 -070037#include "analog.h"
38#include "digital.h"
39#include "encoder.h"
Brian Silvermancb332812013-10-08 13:33:11 -070040#include "CAN.h"
Brian Silvermanf92396c2013-09-12 20:13:13 -070041
brians0ab60bb2013-01-31 02:21:51 +000042int64_t gyro_angle = 0;
43
brians0ab60bb2013-01-31 02:21:51 +000044/*
Brian Silvermancb332812013-10-08 13:33:11 -070045 * Configure the hardware.
brians0ab60bb2013-01-31 02:21:51 +000046 */
47static void prvSetupHardware(void);
48
49/*
50 * The task that handles the USB stack.
51 */
52extern void vUSBTask(void *pvParameters);
53
54extern int VCOM_getchar(void);
55
56int VCOM_putchar(int c);
57
58inline int32_t encoder()
59{
Brian Silvermancb332812013-10-08 13:33:11 -070060 return (int32_t)QEI->QEIPOS;
brians0ab60bb2013-01-31 02:21:51 +000061}
62
63static portTASK_FUNCTION(vPrintPeriodic, pvParameters)
64{
Brian Silvermancb332812013-10-08 13:33:11 -070065 portTickType xLastFlashTime;
brians0ab60bb2013-01-31 02:21:51 +000066
Brian Silvermancb332812013-10-08 13:33:11 -070067 /* We need to initialise xLastFlashTime prior to the first call to
68 vTaskDelayUntil(). */
69 xLastFlashTime = xTaskGetTickCount();
brians0ab60bb2013-01-31 02:21:51 +000070
Brian Silvermanf92396c2013-09-12 20:13:13 -070071 digital_init();
72
Brian Silvermancb332812013-10-08 13:33:11 -070073 analog_init();
brians0ab60bb2013-01-31 02:21:51 +000074
Brian Silvermancb332812013-10-08 13:33:11 -070075 encoder_init();
brians0ab60bb2013-01-31 02:21:51 +000076
Brian Silvermancb332812013-10-08 13:33:11 -070077 // Wait 100 ms for it to boot.
78 vTaskDelayUntil(&xLastFlashTime, 100 / portTICK_RATE_MS);
79 spi_init();
brians0ab60bb2013-01-31 02:21:51 +000080
Brian Silvermancb332812013-10-08 13:33:11 -070081 // Enable USB. The PC has probably disconnected it now.
82 USBHwAllowConnect();
brians0ab60bb2013-01-31 02:21:51 +000083
Brian Silvermancb332812013-10-08 13:33:11 -070084 // TODO(aschuh): Write this into a gyro calibration function, and check all the outputs.
85 vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
86 enable_gyro_csel();
87 printf("SPI Gyro Second Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
88 disable_gyro_csel();
brians0ab60bb2013-01-31 02:21:51 +000089
Brian Silvermancb332812013-10-08 13:33:11 -070090 vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
91 enable_gyro_csel();
92 printf("SPI Gyro Third Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
93 disable_gyro_csel();
brians0ab60bb2013-01-31 02:21:51 +000094
Brian Silvermancb332812013-10-08 13:33:11 -070095 vTaskDelayUntil(&xLastFlashTime, 10 / portTICK_RATE_MS);
96 enable_gyro_csel();
97 printf("SPI Gyro Fourth Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
98 disable_gyro_csel();
99 const int hz = 200;
100 const int flash_hz = 10;
101 const int startup_cycles = hz * 2;
102 const int zeroing_cycles = hz * 6;
103 int32_t zero_bias = 0;
104 int32_t startup_cycles_left = startup_cycles;
105 int32_t zeroing_cycles_left = zeroing_cycles;
106 int32_t full_units_offset = 0;
107 int32_t remainder_offset = 0;
108 int32_t remainder_sum = 0;
109 int32_t led_flash = 0;
110 vParTestSetLED(0, 0);
brians0ab60bb2013-01-31 02:21:51 +0000111
Brian Silvermancb332812013-10-08 13:33:11 -0700112 for (;;) {
113 led_flash ++;
114 if (led_flash < hz / flash_hz / 2) {
115 vParTestSetLED(1, 0);
116 } else {
117 vParTestSetLED(1, 1);
118 }
119 if (led_flash >= hz / flash_hz) {
120 led_flash = 0;
121 }
122 /* Delay for half the flash period then turn the LED on. */
123 vTaskDelayUntil(&xLastFlashTime, 1000 / hz / portTICK_RATE_MS);
124 enable_gyro_csel();
125 uint16_t high_value = transfer_spi_bytes(0x2000);
126 uint16_t low_value = transfer_spi_bytes(0x0000);
127 disable_gyro_csel();
128 int16_t gyro_value = -((int16_t)((((uint32_t)high_value << 16) | (uint32_t)low_value) >> 10));
brians0ab60bb2013-01-31 02:21:51 +0000129
Brian Silvermancb332812013-10-08 13:33:11 -0700130 if (startup_cycles_left) {
131 vParTestSetLED(2, 0);
132 --startup_cycles_left;
133 } else if (zeroing_cycles_left) {
134 vParTestSetLED(2, 1);
135 //printf("Zeroing ");
136 --zeroing_cycles_left;
137 zero_bias -= gyro_value;
138 if (zeroing_cycles_left == 0) {
139 // Do all the nice math
140 full_units_offset = zero_bias / zeroing_cycles;
141 remainder_offset = zero_bias % zeroing_cycles;
142 if (remainder_offset < 0) {
143 remainder_offset += zeroing_cycles;
144 --full_units_offset;
brians0ab60bb2013-01-31 02:21:51 +0000145 }
Brian Silvermancb332812013-10-08 13:33:11 -0700146 }
147 } else {
148 vParTestSetLED(2, 0);
149 int64_t new_angle = gyro_angle + gyro_value + full_units_offset;
150 if (remainder_sum >= zeroing_cycles) {
151 remainder_sum -= zeroing_cycles;
152 new_angle += 1;
153 }
154 gyro_angle = new_angle;
155 remainder_sum += remainder_offset;
156 }
157 //printf("Angle %d Rate %d\n", (int)(gyro_angle / 16),
158 // (int)(gyro_value + full_units_offset));
159
160 //printf("time: %d analog %d encoder %d goal %d\n", (int)i, (int)analog(5),
161 // (int)encoder(), (int)goal);
162
163 /*
164 for(i = 0; i < 4; i++){
165 printf("analog(%d) => %d\n",i,analog(i));
166 }
167 for(i = 1; i < 13; i++){
168 printf("digital(%d) => %d\n",i,digital(i));
169 }
170 for(i = 0; i < 4; i++){
171 printf("dip(%d) => %d\n",i,dip(i));
172 }
173 for(i = 0; i < 4; i++){
174 printf("encoder(%d) => %d\n",i,encoder_bits(i));
175 }
176 for(i = 0; i < 4; i++){
177 printf("encoder_val(%d) => %d\n",i,(int)encoder_val(i));
178 }*/
179 }
180}
181
182int main(void) {
183 // Configure the hardware
184 prvSetupHardware();
185
186 /* Create the USB task. */
187 xTaskCreate(vUSBTask, (signed char *) "USB",
188 configMINIMAL_STACK_SIZE + 1020, (void *) NULL,
189 tskIDLE_PRIORITY + 3, NULL);
190
191 xTaskCreate(vPrintPeriodic, (signed char *) "PRINTx",
192 configMINIMAL_STACK_SIZE + 100, NULL,
193 tskIDLE_PRIORITY + 2, NULL);
194
195
196 initCAN();
197
198 // Start the scheduler.
199 vTaskStartScheduler();
200
201 /* Will only get here if there was insufficient memory to create the idle
202 task. The idle task is created within vTaskStartScheduler(). */
203 for (;;) {}
brians0ab60bb2013-01-31 02:21:51 +0000204}
205/*-----------------------------------------------------------*/
206
Brian Silvermancb332812013-10-08 13:33:11 -0700207// Sets up (and connects) PLL0.
208// The CPU will be running at 100 MHz with a 12 MHz clock input when this is
209// done.
210static void setup_PLL0(void) {
211 // If PLL0 is currently connected.
212 if (SC->PLL0STAT & (1 << 25)) {
213 /* Enable PLL0, disconnected. */
214 SC->PLL0CON = 1;
215 SC->PLL0FEED = PLLFEED_FEED1;
216 SC->PLL0FEED = PLLFEED_FEED2;
217 }
218
219 // Disable PLL0, disconnected.
220 SC->PLL0CON = 0;
221 SC->PLL0FEED = PLLFEED_FEED1;
222 SC->PLL0FEED = PLLFEED_FEED2;
223
224 // Enable main OSC.
225 SC->SCS |= 1 << 5;
226 // Wait until it's ready.
227 while (!(SC->SCS & (1 << 6)));
228
229 // Select main OSC as the PLL0 clock source.
230 SC->CLKSRCSEL = 0x1;
231
232 // Set up PLL0 to output 400MHz.
233 // 12MHz * 50 / 3 * 2 = 400MHz.
234 // The input is 12MHz (from the crystal), M = 50, and N = 3.
235 SC->PLL0CFG = 0x20031;
236 SC->PLL0FEED = PLLFEED_FEED1;
237 SC->PLL0FEED = PLLFEED_FEED2;
238
239 // Enable PLL0, disconnected.
240 SC->PLL0CON = 1;
241 SC->PLL0FEED = PLLFEED_FEED1;
242 SC->PLL0FEED = PLLFEED_FEED2;
243
244 // Set clock divider to dividing by 4 to give a final frequency of 100MHz.
245 SC->CCLKCFG = 0x03;
246
247 // Configure flash accelerator to use 5 CPU clocks like the datasheet says for
248 // a 100MHz clock.
249 SC->FLASHCFG = 0x403a;
250
251 // Wait until PLL0 is locked.
252 while (((SC->PLL0STAT & (1 << 26)) == 0));
253
254 // Enable PLL0 and connect.
255 SC->PLL0CON = 3;
256 SC->PLL0FEED = PLLFEED_FEED1;
257 SC->PLL0FEED = PLLFEED_FEED2;
258
259 // Wait until PLL0 is connected.
260 while (((SC->PLL0STAT & (1 << 25)) == 0));
261}
262
263// Configures PLL1 as the clock for USB.
264static void setup_PLL1(void) {
265 // If PLL1 is currently connected.
266 if (SC->PLL1STAT & (1 << 9)) {
267 // Enable PLL1, disconnected.
268 SC->PLL1CON = 1;
269 SC->PLL1FEED = PLLFEED_FEED1;
270 SC->PLL1FEED = PLLFEED_FEED2;
271 }
272
273 // Disable PLL1, disconnected.
274 SC->PLL1CON = 0;
275 SC->PLL1FEED = PLLFEED_FEED1;
276 SC->PLL1FEED = PLLFEED_FEED2;
277
278 // Set up PLL1 to produce the required 48MHz from the crystal.
279 // USBCLK = 12MHz * 4 = 48MHz.
280 // FCCO = USBCLK * 2 * 3 = 288MHz.
281 // The input is 12MHz, M = 4, and P = 3.
282 SC->PLL1CFG = 0x23;
283 SC->PLL1FEED = PLLFEED_FEED1;
284 SC->PLL1FEED = PLLFEED_FEED2;
285
286 /* Enable PLL1, disconnected. */
287 SC->PLL1CON = 1;
288 SC->PLL1FEED = PLLFEED_FEED1;
289 SC->PLL1FEED = PLLFEED_FEED2;
290
291 // Wait until PLL1 is locked.
292 while (((SC->PLL1STAT & (1 << 10)) == 0));
293
294 /* Enable PLL1 and connect it. */
295 SC->PLL1CON = 3;
296 SC->PLL1FEED = PLLFEED_FEED1;
297 SC->PLL1FEED = PLLFEED_FEED2;
298
299 // Wait until PLL1 is connected.
300 while (((SC->PLL1STAT & (1 << 9)) == 0));
301}
302
brians0ab60bb2013-01-31 02:21:51 +0000303void prvSetupHardware(void)
304{
Brian Silvermancb332812013-10-08 13:33:11 -0700305 // Setup the peripherals.
brians0ab60bb2013-01-31 02:21:51 +0000306
Brian Silvermancb332812013-10-08 13:33:11 -0700307 // Setup GPIO power.
308 SC->PCONP = PCONP_PCGPIO;
brians0ab60bb2013-01-31 02:21:51 +0000309
Brian Silvermancb332812013-10-08 13:33:11 -0700310 // Disable TPIU.
311 PINCON->PINSEL10 = 0;
brians0ab60bb2013-01-31 02:21:51 +0000312
Brian Silvermancb332812013-10-08 13:33:11 -0700313 setup_PLL0();
brians0ab60bb2013-01-31 02:21:51 +0000314
Brian Silvermancb332812013-10-08 13:33:11 -0700315 setup_PLL1();
brians0ab60bb2013-01-31 02:21:51 +0000316
Brian Silvermancb332812013-10-08 13:33:11 -0700317 // Setup the peripheral bus to be the same as the CCLK, 100 MHz.
318 // Set CAN to run at CCLK/6, which should have it running about 1 Mbit (1.042)
319 SC->PCLKSEL0 = 0xff555555;
brians0ab60bb2013-01-31 02:21:51 +0000320
Brian Silvermancb332812013-10-08 13:33:11 -0700321 /* Configure the LEDs. */
322 vParTestInitialise();
brians0ab60bb2013-01-31 02:21:51 +0000323}
324/*-----------------------------------------------------------*/
325
326void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed char *pcTaskName)
327{
Brian Silvermancb332812013-10-08 13:33:11 -0700328 /* This function will get called if a task overflows its stack. */
brians0ab60bb2013-01-31 02:21:51 +0000329
Brian Silvermancb332812013-10-08 13:33:11 -0700330 (void) pxTask;
331 (void) pcTaskName;
brians0ab60bb2013-01-31 02:21:51 +0000332
Brian Silvermancb332812013-10-08 13:33:11 -0700333 for (;;);
brians0ab60bb2013-01-31 02:21:51 +0000334}
335/*-----------------------------------------------------------*/
336
Brian Silvermancb332812013-10-08 13:33:11 -0700337// This is what portCONFIGURE_TIMER_FOR_RUN_TIME_STATS in FreeRTOSConfig.h
338// actually calls.
brians0ab60bb2013-01-31 02:21:51 +0000339void vConfigureTimerForRunTimeStats(void)
340{
Brian Silvermancb332812013-10-08 13:33:11 -0700341 const unsigned long TCR_COUNT_RESET = 2, CTCR_CTM_TIMER = 0x00, TCR_COUNT_ENABLE = 0x01;
brians0ab60bb2013-01-31 02:21:51 +0000342
Brian Silvermancb332812013-10-08 13:33:11 -0700343 /* This function configures a timer that is used as the time base when
344 collecting run time statistical information - basically the percentage
345 of CPU time that each task is utilising. It is called automatically when
346 the scheduler is started (assuming configGENERATE_RUN_TIME_STATS is set
347 to 1). */
brians0ab60bb2013-01-31 02:21:51 +0000348
Brian Silvermancb332812013-10-08 13:33:11 -0700349 /* Power up and feed the timer. */
350 SC->PCONP |= 0x02UL;
351 SC->PCLKSEL0 = (SC->PCLKSEL0 & (~(0x3 << 2))) | (0x01 << 2);
brians0ab60bb2013-01-31 02:21:51 +0000352
Brian Silvermancb332812013-10-08 13:33:11 -0700353 /* Reset Timer 0 */
354 TIM0->TCR = TCR_COUNT_RESET;
brians0ab60bb2013-01-31 02:21:51 +0000355
Brian Silvermancb332812013-10-08 13:33:11 -0700356 /* Just count up. */
357 TIM0->CTCR = CTCR_CTM_TIMER;
brians0ab60bb2013-01-31 02:21:51 +0000358
Brian Silvermancb332812013-10-08 13:33:11 -0700359 /* Prescale to a frequency that is good enough to get a decent resolution,
360 but not too fast so as to overflow all the time. */
361 TIM0->PR = (configCPU_CLOCK_HZ / 10000UL) - 1UL;
brians0ab60bb2013-01-31 02:21:51 +0000362
Brian Silvermancb332812013-10-08 13:33:11 -0700363 /* Start the counter. */
364 TIM0->TCR = TCR_COUNT_ENABLE;
brians0ab60bb2013-01-31 02:21:51 +0000365}