Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 1 | #include <stdint.h> |
| 2 | |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 3 | #include <STM32F2XX.h> |
| 4 | |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 5 | #include "cape/bootloader_handoff.h" |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 6 | #include "cape/led.h" |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 7 | |
| 8 | // Sets everything up and then jumps to the main code. |
| 9 | static void jump_to_main(void) __attribute__((noreturn)); |
| 10 | static void jump_to_main(void) { |
Brian Silverman | aa9183a | 2013-12-08 10:33:47 -0800 | [diff] [blame] | 11 | __asm__ __volatile__( |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 12 | "mov sp, %[stack]\n\t" |
| 13 | "bx %[reset]" : : |
| 14 | [stack]"r"(RAM_START + RAM_SIZE), [reset]"r"(MAIN_FLASH_START | 1) |
| 15 | : "memory"); |
| 16 | __builtin_unreachable(); |
| 17 | } |
| 18 | |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 19 | static void setup_main_clock(void) { |
| 20 | // We set up a couple of registers here separately from the actual register to |
| 21 | // avoid having to think about what happens when the value is in some |
| 22 | // intermediate state. |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 23 | |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 24 | RCC->CR |= RCC_CR_HSEON; // get the HSE oscillator going |
| 25 | |
| 26 | FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | |
| 27 | FLASH_ACR_LATENCY_3WS; |
| 28 | |
| 29 | uint32_t rcc_pllcfgr = 0; |
| 30 | rcc_pllcfgr |= RCC_PLLCFGR_PLLSRC; // use the external oscillator |
| 31 | // 8MHz * 120 / 4 / 2 = 120MHz |
| 32 | rcc_pllcfgr |= 120 << 6; // multiplier |
| 33 | rcc_pllcfgr |= 4; // divider |
| 34 | rcc_pllcfgr |= 5 << 24; // other stuff divider = 5, just in case |
| 35 | RCC->PLLCFGR = rcc_pllcfgr; |
| 36 | |
| 37 | uint32_t rcc_cfgr = 0; |
| 38 | rcc_cfgr |= 4 << 13; // APB2 divider = 2 |
| 39 | rcc_cfgr |= 5 << 10; // APB1 divider = 4 |
| 40 | rcc_cfgr |= 2; // use the PLL |
| 41 | |
| 42 | // Wait for the HSE oscillator to be stable. |
| 43 | while (!(RCC->CR & RCC_CR_HSERDY)) {} |
| 44 | |
| 45 | RCC->CR |= RCC_CR_PLLON; |
| 46 | // Wait for the main PLL to be stable. |
| 47 | while (!(RCC->CR & RCC_CR_PLLRDY)) {} |
| 48 | // Wait until the flash is using 3 wait states. |
| 49 | while ((FLASH->ACR & 7) != 3) {} |
| 50 | RCC->CFGR = rcc_cfgr; |
| 51 | // Wait until we are using the PLL as our main clock source. |
| 52 | while ((RCC->CFGR & (3 << 2)) != (2 << 2)) {} |
| 53 | } |
| 54 | |
| 55 | void _start(void) { |
| 56 | // Enable the GPIO pin clocks. |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 57 | // We don't have anything on the 1 port D pin, so don't bother enabling it. |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 58 | RCC->AHB1ENR |= |
| 59 | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; |
| 60 | led_init(); |
Brian Silverman | 176c676 | 2013-12-19 16:28:09 -0800 | [diff] [blame^] | 61 | led_set(LED_HB, 1); |
Brian Silverman | ed183e6 | 2013-12-18 15:51:16 -0800 | [diff] [blame] | 62 | |
| 63 | setup_main_clock(); |
| 64 | |
| 65 | #if 0 |
| 66 | SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable IO compensation cell |
| 67 | while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready |
| 68 | TODO(brians): Figure out what the story with this is. |
| 69 | #endif |
Brian Silverman | 1b6fbd0 | 2013-12-12 18:08:47 -0800 | [diff] [blame] | 70 | |
Brian Silverman | 44311d6 | 2013-12-06 22:03:29 -0800 | [diff] [blame] | 71 | jump_to_main(); |
Brian Silverman | 5020be6 | 2013-12-06 19:09:07 -0800 | [diff] [blame] | 72 | } |