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