brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 1 | /* |
| 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" |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 34 | #include "LPCUSB/usbapi.h" |
| 35 | |
Brian Silverman | f92396c | 2013-09-12 20:13:13 -0700 | [diff] [blame] | 36 | #include "analog.h" |
| 37 | #include "digital.h" |
| 38 | #include "encoder.h" |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 39 | #include "CAN.h" |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 40 | #include "gyro.h" |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 41 | |
Brian Silverman | d36b7d3 | 2013-10-24 15:56:47 -0700 | [diff] [blame^] | 42 | extern void usb_init(void); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 43 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 44 | // Sets up (and connects) PLL0. |
| 45 | // The CPU will be running at 100 MHz with a 12 MHz clock input when this is |
| 46 | // done. |
| 47 | static void setup_PLL0(void) { |
| 48 | // If PLL0 is currently connected. |
| 49 | if (SC->PLL0STAT & (1 << 25)) { |
| 50 | /* Enable PLL0, disconnected. */ |
| 51 | SC->PLL0CON = 1; |
| 52 | SC->PLL0FEED = PLLFEED_FEED1; |
| 53 | SC->PLL0FEED = PLLFEED_FEED2; |
| 54 | } |
| 55 | |
| 56 | // Disable PLL0, disconnected. |
| 57 | SC->PLL0CON = 0; |
| 58 | SC->PLL0FEED = PLLFEED_FEED1; |
| 59 | SC->PLL0FEED = PLLFEED_FEED2; |
| 60 | |
| 61 | // Enable main OSC. |
| 62 | SC->SCS |= 1 << 5; |
| 63 | // Wait until it's ready. |
| 64 | while (!(SC->SCS & (1 << 6))); |
| 65 | |
| 66 | // Select main OSC as the PLL0 clock source. |
| 67 | SC->CLKSRCSEL = 0x1; |
| 68 | |
| 69 | // Set up PLL0 to output 400MHz. |
| 70 | // 12MHz * 50 / 3 * 2 = 400MHz. |
| 71 | // The input is 12MHz (from the crystal), M = 50, and N = 3. |
| 72 | SC->PLL0CFG = 0x20031; |
| 73 | SC->PLL0FEED = PLLFEED_FEED1; |
| 74 | SC->PLL0FEED = PLLFEED_FEED2; |
| 75 | |
| 76 | // Enable PLL0, disconnected. |
| 77 | SC->PLL0CON = 1; |
| 78 | SC->PLL0FEED = PLLFEED_FEED1; |
| 79 | SC->PLL0FEED = PLLFEED_FEED2; |
| 80 | |
| 81 | // Set clock divider to dividing by 4 to give a final frequency of 100MHz. |
| 82 | SC->CCLKCFG = 0x03; |
| 83 | |
| 84 | // Configure flash accelerator to use 5 CPU clocks like the datasheet says for |
| 85 | // a 100MHz clock. |
| 86 | SC->FLASHCFG = 0x403a; |
| 87 | |
| 88 | // Wait until PLL0 is locked. |
| 89 | while (((SC->PLL0STAT & (1 << 26)) == 0)); |
| 90 | |
| 91 | // Enable PLL0 and connect. |
| 92 | SC->PLL0CON = 3; |
| 93 | SC->PLL0FEED = PLLFEED_FEED1; |
| 94 | SC->PLL0FEED = PLLFEED_FEED2; |
| 95 | |
| 96 | // Wait until PLL0 is connected. |
| 97 | while (((SC->PLL0STAT & (1 << 25)) == 0)); |
| 98 | } |
| 99 | |
| 100 | // Configures PLL1 as the clock for USB. |
| 101 | static void setup_PLL1(void) { |
| 102 | // If PLL1 is currently connected. |
| 103 | if (SC->PLL1STAT & (1 << 9)) { |
| 104 | // Enable PLL1, disconnected. |
| 105 | SC->PLL1CON = 1; |
| 106 | SC->PLL1FEED = PLLFEED_FEED1; |
| 107 | SC->PLL1FEED = PLLFEED_FEED2; |
| 108 | } |
| 109 | |
| 110 | // Disable PLL1, disconnected. |
| 111 | SC->PLL1CON = 0; |
| 112 | SC->PLL1FEED = PLLFEED_FEED1; |
| 113 | SC->PLL1FEED = PLLFEED_FEED2; |
| 114 | |
| 115 | // Set up PLL1 to produce the required 48MHz from the crystal. |
| 116 | // USBCLK = 12MHz * 4 = 48MHz. |
| 117 | // FCCO = USBCLK * 2 * 3 = 288MHz. |
| 118 | // The input is 12MHz, M = 4, and P = 3. |
| 119 | SC->PLL1CFG = 0x23; |
| 120 | SC->PLL1FEED = PLLFEED_FEED1; |
| 121 | SC->PLL1FEED = PLLFEED_FEED2; |
| 122 | |
| 123 | /* Enable PLL1, disconnected. */ |
| 124 | SC->PLL1CON = 1; |
| 125 | SC->PLL1FEED = PLLFEED_FEED1; |
| 126 | SC->PLL1FEED = PLLFEED_FEED2; |
| 127 | |
| 128 | // Wait until PLL1 is locked. |
| 129 | while (((SC->PLL1STAT & (1 << 10)) == 0)); |
| 130 | |
| 131 | /* Enable PLL1 and connect it. */ |
| 132 | SC->PLL1CON = 3; |
| 133 | SC->PLL1FEED = PLLFEED_FEED1; |
| 134 | SC->PLL1FEED = PLLFEED_FEED2; |
| 135 | |
| 136 | // Wait until PLL1 is connected. |
| 137 | while (((SC->PLL1STAT & (1 << 9)) == 0)); |
| 138 | } |
| 139 | |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 140 | // Setup the peripherals. |
| 141 | static void setup_hardware(void) { |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 142 | // Setup GPIO power. |
| 143 | SC->PCONP = PCONP_PCGPIO; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 144 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 145 | // Disable TPIU. |
| 146 | PINCON->PINSEL10 = 0; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 147 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 148 | setup_PLL0(); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 149 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 150 | setup_PLL1(); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 151 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 152 | // Set CAN to run at CCLK/6, which should have it running about 1 Mbit (1.042) |
| 153 | SC->PCLKSEL0 = 0xff555555; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 154 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 155 | /* Configure the LEDs. */ |
| 156 | vParTestInitialise(); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 157 | } |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 158 | |
| 159 | int main(void) { |
| 160 | setup_hardware(); |
| 161 | |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 162 | digital_init(); |
| 163 | |
| 164 | analog_init(); |
| 165 | |
| 166 | encoder_init(); |
| 167 | |
| 168 | gyro_init(); |
| 169 | |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 170 | initCAN(); |
| 171 | |
Brian Silverman | d36b7d3 | 2013-10-24 15:56:47 -0700 | [diff] [blame^] | 172 | usb_init(); |
| 173 | |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 174 | // Start the scheduler. |
| 175 | vTaskStartScheduler(); |
| 176 | |
| 177 | /* Will only get here if there was insufficient memory to create the idle |
| 178 | task. The idle task is created within vTaskStartScheduler(). */ |
| 179 | for (;;) {} |
| 180 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 181 | |
| 182 | void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed char *pcTaskName) |
| 183 | { |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 184 | /* This function will get called if a task overflows its stack. */ |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 185 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 186 | (void) pxTask; |
| 187 | (void) pcTaskName; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 188 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 189 | for (;;); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 190 | } |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 191 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 192 | // This is what portCONFIGURE_TIMER_FOR_RUN_TIME_STATS in FreeRTOSConfig.h |
| 193 | // actually calls. |
Brian Silverman | 4987694 | 2013-10-11 17:50:26 -0700 | [diff] [blame] | 194 | // It sets up timer 0 to use for timing. |
| 195 | void vConfigureTimerForRunTimeStats(void) { |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 196 | const unsigned long TCR_COUNT_RESET = 2, CTCR_CTM_TIMER = 0x00, TCR_COUNT_ENABLE = 0x01; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 197 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 198 | /* This function configures a timer that is used as the time base when |
| 199 | collecting run time statistical information - basically the percentage |
| 200 | of CPU time that each task is utilising. It is called automatically when |
| 201 | the scheduler is started (assuming configGENERATE_RUN_TIME_STATS is set |
| 202 | to 1). */ |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 203 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 204 | /* Power up and feed the timer. */ |
| 205 | SC->PCONP |= 0x02UL; |
| 206 | SC->PCLKSEL0 = (SC->PCLKSEL0 & (~(0x3 << 2))) | (0x01 << 2); |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 207 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 208 | /* Reset Timer 0 */ |
| 209 | TIM0->TCR = TCR_COUNT_RESET; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 210 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 211 | /* Just count up. */ |
| 212 | TIM0->CTCR = CTCR_CTM_TIMER; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 213 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 214 | /* Prescale to a frequency that is good enough to get a decent resolution, |
| 215 | but not too fast so as to overflow all the time. */ |
| 216 | TIM0->PR = (configCPU_CLOCK_HZ / 10000UL) - 1UL; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 217 | |
Brian Silverman | cb33281 | 2013-10-08 13:33:11 -0700 | [diff] [blame] | 218 | /* Start the counter. */ |
| 219 | TIM0->TCR = TCR_COUNT_ENABLE; |
brians | 0ab60bb | 2013-01-31 02:21:51 +0000 | [diff] [blame] | 220 | } |