blob: f0f76bfd161190496a50a3f1358dcc78998d4e6a [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"
40
brians0ab60bb2013-01-31 02:21:51 +000041/*-----------------------------------------------------------*/
42
43/* The time between cycles of the 'check' functionality (defined within the
44tick hook. */
45#define mainCHECK_DELAY ((portTickType) 5000 / portTICK_RATE_MS)
46
47/* Task priorities. */
48#define mainQUEUE_POLL_PRIORITY (tskIDLE_PRIORITY + 2)
49#define mainSEM_TEST_PRIORITY (tskIDLE_PRIORITY + 1)
50#define mainBLOCK_Q_PRIORITY (tskIDLE_PRIORITY + 2)
51#define mainUIP_TASK_PRIORITY (tskIDLE_PRIORITY + 3)
52#define mainINTEGER_TASK_PRIORITY (tskIDLE_PRIORITY)
53#define mainGEN_QUEUE_TASK_PRIORITY (tskIDLE_PRIORITY)
54#define mainFLASH_TASK_PRIORITY (tskIDLE_PRIORITY + 2)
55
56/* The WEB server has a larger stack as it utilises stack hungry string
57handling library calls. */
58#define mainBASIC_WEB_STACK_SIZE (configMINIMAL_STACK_SIZE * 4)
59
60int32_t goal = 0;
61int64_t gyro_angle = 0;
62
63/*-----------------------------------------------------------*/
64
65/*
66 * Configure the hardware for the demo.
67 */
68static void prvSetupHardware(void);
69
70/*
71 * The task that handles the USB stack.
72 */
73extern void vUSBTask(void *pvParameters);
74
75extern int VCOM_getchar(void);
76
77int VCOM_putchar(int c);
78
79inline int32_t encoder()
80{
81 return (int32_t)QEI->QEIPOS;
82}
83
84static portTASK_FUNCTION(vPrintPeriodic, pvParameters)
85{
86 portTickType xLastFlashTime;
87
88 /* We need to initialise xLastFlashTime prior to the first call to
89 vTaskDelayUntil(). */
90 xLastFlashTime = xTaskGetTickCount();
91
Brian Silvermanf92396c2013-09-12 20:13:13 -070092 digital_init();
93
brians0ab60bb2013-01-31 02:21:51 +000094 analog_init();
95
96 encoder_init();
97
98 // Wait 100 ms for it to boot.
99 vTaskDelayUntil(&xLastFlashTime, 100 / portTICK_RATE_MS);
100 spi_init();
101
102 // Enable USB. The PC has probably disconnected it now.
103 USBHwAllowConnect();
104
105 // TODO(aschuh): Write this into a gyro calibration function, and check all the outputs.
106 vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
107 enable_gyro_csel();
108 printf("SPI Gyro Second Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
109 disable_gyro_csel();
110
111 vTaskDelayUntil(&xLastFlashTime, 50 / portTICK_RATE_MS);
112 enable_gyro_csel();
113 printf("SPI Gyro Third Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
114 disable_gyro_csel();
115
116 vTaskDelayUntil(&xLastFlashTime, 10 / portTICK_RATE_MS);
117 enable_gyro_csel();
118 printf("SPI Gyro Fourth Response 0x%x %x\n", transfer_spi_bytes(0x2000), transfer_spi_bytes(0x0000));
119 disable_gyro_csel();
120 const int hz = 200;
121 const int flash_hz = 10;
122 const int startup_cycles = hz * 2;
123 const int zeroing_cycles = hz * 6;
124 int32_t zero_bias = 0;
125 int32_t startup_cycles_left = startup_cycles;
126 int32_t zeroing_cycles_left = zeroing_cycles;
127 int32_t full_units_offset = 0;
128 int32_t remainder_offset = 0;
129 int32_t remainder_sum = 0;
130 int32_t led_flash = 0;
131 vParTestSetLED(0, 0);
132
133 for (;;) {
134 led_flash ++;
135 if (led_flash < hz / flash_hz / 2) {
136 vParTestSetLED(1, 0);
137 } else {
138 vParTestSetLED(1, 1);
139 }
140 if (led_flash >= hz / flash_hz) {
141 led_flash = 0;
142 }
143 /* Delay for half the flash period then turn the LED on. */
144 vTaskDelayUntil(&xLastFlashTime, 1000 / hz / portTICK_RATE_MS);
145 enable_gyro_csel();
146 uint16_t high_value = transfer_spi_bytes(0x2000);
147 uint16_t low_value = transfer_spi_bytes(0x0000);
148 disable_gyro_csel();
149 int16_t gyro_value = -((int16_t)((((uint32_t)high_value << 16) | (uint32_t)low_value) >> 10));
150
151 if (startup_cycles_left) {
152 vParTestSetLED(2, 0);
153 --startup_cycles_left;
154 } else if (zeroing_cycles_left) {
155 vParTestSetLED(2, 1);
156 //printf("Zeroing ");
157 --zeroing_cycles_left;
158 zero_bias -= gyro_value;
159 if (zeroing_cycles_left == 0) {
160 // Do all the nice math
161 full_units_offset = zero_bias / zeroing_cycles;
162 remainder_offset = zero_bias % zeroing_cycles;
163 if (remainder_offset < 0) {
164 remainder_offset += zeroing_cycles;
165 --full_units_offset;
166 }
167 }
168 } else {
169 vParTestSetLED(2, 0);
170 int64_t new_angle = gyro_angle + gyro_value + full_units_offset;
171 if (remainder_sum >= zeroing_cycles) {
172 remainder_sum -= zeroing_cycles;
173 new_angle += 1;
174 }
175 NVIC_DisableIRQ(USB_IRQn);
176 gyro_angle = new_angle;
177 NVIC_EnableIRQ(USB_IRQn);
178 remainder_sum += remainder_offset;
179 }
180 //printf("Angle %d Rate %d\n", (int)(gyro_angle / 16), (int)(gyro_value + full_units_offset));
181
182 //printf("time: %d analog %d encoder %d goal %d\n", (int)i, (int)analog(5), (int)encoder(), (int)goal);
183
184 //printf("time: %d encoder %d goal %d\n", (int)i, (int)encoder(), (int)goal);
185 /*
186 for(i = 0; i < 4; i++){
187 printf("analog(%d) => %d\n",i,analog(i));
188 }
189 for(i = 1; i < 13; i++){
190 printf("digital(%d) => %d\n",i,digital(i));
191 }
192 for(i = 0; i < 4; i++){
193 printf("dip(%d) => %d\n",i,dip(i));
194 }
195 for(i = 0; i < 4; i++){
196 printf("encoder(%d) => %d\n",i,encoder_bits(i));
197 }
198 for(i = 0; i < 4; i++){
199 printf("encoder_val(%d) => %d\n",i,(int)encoder_val(i));
200 }*/
201 }
202}
203
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000204static portTASK_FUNCTION(vSensorPoll, pvParameters)
brians0ab60bb2013-01-31 02:21:51 +0000205{
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000206 portTickType xLastFlashTime;
207 xLastFlashTime = xTaskGetTickCount();
Brian Silverman6ad00b82013-03-27 19:02:38 -0700208
209
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000210 vTaskDelayUntil(&xLastFlashTime, 1000 / portTICK_RATE_MS);
211
212 for(;;){
213
214 vTaskDelayUntil(&xLastFlashTime, 20 / portTICK_RATE_MS);
215 /*
216 printf("not realtime! e0:%d e1:%d e2:%d e3:%d e4:%d e5:%d angle:%d \n", (int)encoder_val(0),
217 (int)encoder_val(1),
218 (int)encoder_val(2),
219 (int)encoder_val(3),
220 (int)encoder_val(4),
221 (int)encoder_val(5),
222 (int)gyro_angle);
223*/
brians0ab60bb2013-01-31 02:21:51 +0000224 }
225}
226
227
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000228#include "CAN.h"
229
brians0ab60bb2013-01-31 02:21:51 +0000230
231/*-----------------------------------------------------------*/
232
233int main(void)
234{
235 // Configure the hardware
236 prvSetupHardware();
237
238 /* Start the standard demo tasks. These are just here to exercise the
239 kernel port and provide examples of how the FreeRTOS API can be used. */
240 //vStartLEDFlashTasks(mainFLASH_TASK_PRIORITY);
241
242 /* Create the USB task. */
243 xTaskCreate(vUSBTask, (signed char *) "USB", configMINIMAL_STACK_SIZE + 1020, (void *) NULL, tskIDLE_PRIORITY + 3, NULL);
244
245 xTaskCreate(vPrintPeriodic, (signed char *) "PRINTx", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 2, NULL);
246
Austin Schuh63d0e9b2013-03-27 04:43:14 +0000247
248 xTaskCreate(vSensorPoll, (signed char *) "SENSORs", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, NULL);
249
brians0ab60bb2013-01-31 02:21:51 +0000250 initCAN();
251
252 // Start the scheduler.
253 vTaskStartScheduler();
254
255 /* Will only get here if there was insufficient memory to create the idle
256 task. The idle task is created within vTaskStartScheduler(). */
257 for (;;);
258}
259/*-----------------------------------------------------------*/
260
261
262void vApplicationTickHook(void)
263{
264 static unsigned long ulTicksSinceLastDisplay = 0;
265
266 /* Called from every tick interrupt as described in the comments at the top
267 of this file.
268
269 Have enough ticks passed to make it time to perform our health status
270 check again? */
271
272 ulTicksSinceLastDisplay++;
273
274 if (ulTicksSinceLastDisplay >= mainCHECK_DELAY) {
275 /* Reset the counter so these checks run again in mainCHECK_DELAY
276 ticks time. */
277 ulTicksSinceLastDisplay = 0;
278 }
279}
280/*-----------------------------------------------------------*/
281
282void prvSetupHardware(void)
283{
284 // Setup the peripherals.
285 // The CPU will be running at 100 MHz with a 12 MHz clock input.
286
287 // Setup GPIO power.
288 SC->PCONP = PCONP_PCGPIO;
289 // Disable TPIU.
290 PINCON->PINSEL10 = 0;
291
292 // Setup PLL0 so that the CPU runs at 100 MHz.
293 if (SC->PLL0STAT & (1 << 25)) {
294 /* Enable PLL, disconnected. */
295 SC->PLL0CON = 1;
296 SC->PLL0FEED = PLLFEED_FEED1;
297 SC->PLL0FEED = PLLFEED_FEED2;
298 }
299
300 // Disable PLL, disconnected.
301 SC->PLL0CON = 0;
302 SC->PLL0FEED = PLLFEED_FEED1;
303 SC->PLL0FEED = PLLFEED_FEED2;
304
305 // Enable main OSC and wait until it's ready.
306 SC->SCS |= 0x20;
307 while (!(SC->SCS & 0x40));
308
309 // select main OSC, 12MHz, as the PLL clock source.
310 SC->CLKSRCSEL = 0x1;
311
312 SC->PLL0CFG = 0x20031;
313 SC->PLL0FEED = PLLFEED_FEED1;
314 SC->PLL0FEED = PLLFEED_FEED2;
315
316 // Enable PLL, disconnected.
317 SC->PLL0CON = 1;
318 SC->PLL0FEED = PLLFEED_FEED1;
319 SC->PLL0FEED = PLLFEED_FEED2;
320
321 // Set clock divider.
322 SC->CCLKCFG = 0x03;
323
324 // Configure flash accelerator.
325 SC->FLASHCFG = 0x403a;
326
327 // Check lock bit status.
328 while (((SC->PLL0STAT & (1 << 26)) == 0));
329
330 // Enable and connect.
331 SC->PLL0CON = 3;
332 SC->PLL0FEED = PLLFEED_FEED1;
333 SC->PLL0FEED = PLLFEED_FEED2;
334
335 while (((SC->PLL0STAT & (1 << 25)) == 0));
336
337 // Configure the clock for the USB.
338 if (SC->PLL1STAT & (1 << 9)) {
339 // Enable PLL, disconnected.
340 SC->PLL1CON = 1;
341 SC->PLL1FEED = PLLFEED_FEED1;
342 SC->PLL1FEED = PLLFEED_FEED2;
343 }
344
345 // Disable PLL, disconnected.
346 SC->PLL1CON = 0;
347 SC->PLL1FEED = PLLFEED_FEED1;
348 SC->PLL1FEED = PLLFEED_FEED2;
349
350 SC->PLL1CFG = 0x23;
351 SC->PLL1FEED = PLLFEED_FEED1;
352 SC->PLL1FEED = PLLFEED_FEED2;
353
354 /* Enable PLL, disconnected. */
355 SC->PLL1CON = 1;
356 SC->PLL1FEED = PLLFEED_FEED1;
357 SC->PLL1FEED = PLLFEED_FEED2;
358 while (((SC->PLL1STAT & (1 << 10)) == 0));
359
360 /* Enable and connect. */
361 SC->PLL1CON = 3;
362 SC->PLL1FEED = PLLFEED_FEED1;
363 SC->PLL1FEED = PLLFEED_FEED2;
364 while (((SC->PLL1STAT & (1 << 9)) == 0));
365
366 // Setup the peripheral bus to be the same as the CCLK, 100 MHz.
367 // Set CAN to run at CCLK/6, which should have it running about 1 Mbit (1.042)
368 SC->PCLKSEL0 = 0xff555555;
369
370 /* Configure the LEDs. */
371 vParTestInitialise();
372}
373/*-----------------------------------------------------------*/
374
375void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed char *pcTaskName)
376{
377 /* This function will get called if a task overflows its stack. */
378
379 (void) pxTask;
380 (void) pcTaskName;
381
382 for (;;);
383}
384/*-----------------------------------------------------------*/
385
386void vConfigureTimerForRunTimeStats(void)
387{
388 const unsigned long TCR_COUNT_RESET = 2, CTCR_CTM_TIMER = 0x00, TCR_COUNT_ENABLE = 0x01;
389
390 /* This function configures a timer that is used as the time base when
391 collecting run time statistical information - basically the percentage
392 of CPU time that each task is utilising. It is called automatically when
393 the scheduler is started (assuming configGENERATE_RUN_TIME_STATS is set
394 to 1). */
395
396 /* Power up and feed the timer. */
397 SC->PCONP |= 0x02UL;
398 SC->PCLKSEL0 = (SC->PCLKSEL0 & (~(0x3 << 2))) | (0x01 << 2);
399
400 /* Reset Timer 0 */
401 TIM0->TCR = TCR_COUNT_RESET;
402
403 /* Just count up. */
404 TIM0->CTCR = CTCR_CTM_TIMER;
405
406 /* Prescale to a frequency that is good enough to get a decent resolution,
407 but not too fast so as to overflow all the time. */
408 TIM0->PR = (configCPU_CLOCK_HZ / 10000UL) - 1UL;
409
410 /* Start the counter. */
411 TIM0->TCR = TCR_COUNT_ENABLE;
412}
413