Blame view

RIOT/cpu/stm32f4/cpu.c 4.68 KB
fb11e647   vrobic   reseau statique a...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  /*
   * Copyright (C) 2014 Freie Universitรคt Berlin
   *
   * This file is subject to the terms and conditions of the GNU Lesser General
   * Public License v2.1. See the file LICENSE in the top level directory for more
   * details.
   */
  
  /**
   * @ingroup     cpu_stm32f4
   * @{
   *
   * @file
   * @brief       Implementation of the CPU initialization
   *
   * @author      Hauke Petersen <hauke.petersen@fu-berlin.de>
   * @author      Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
   * @}
   */
  
  #include <stdint.h>
  #include "cpu.h"
  #include "periph_conf.h"
  
  /* Check the source to be used for the PLL */
  #if defined(CLOCK_HSI) && defined(CLOCK_HSE)
  #error "Only provide one of two CLOCK_HSI/CLOCK_HSE"
  #elif CLOCK_HSI
  #define CLOCK_CR_SOURCE            RCC_CR_HSION
  #define CLOCK_CR_SOURCE_RDY        RCC_CR_HSIRDY
  #define CLOCK_PLL_SOURCE           RCC_PLLCFGR_PLLSRC_HSI
  #define CLOCK_DISABLE_HSI          0
  #elif CLOCK_HSE
  #define CLOCK_CR_SOURCE            RCC_CR_HSEON
  #define CLOCK_CR_SOURCE_RDY        RCC_CR_HSERDY
  #define CLOCK_PLL_SOURCE           RCC_PLLCFGR_PLLSRC_HSE
  #define CLOCK_DISABLE_HSI          1
  #else
  #error "Please provide CLOCK_HSI or CLOCK_HSE in boards/NAME/includes/perhip_cpu.h"
  #endif
  
  static void cpu_clock_init(void);
  
  /**
   * @brief Initialize the CPU, set IRQ priorities
   */
  void cpu_init(void)
  {
      /* initialize the Cortex-M core */
      cortexm_init();
      /* initialize the clock system */
      cpu_clock_init();
  }
  
  /**
   * @brief Configure the controllers clock system
   *
   * The clock initialization make the following assumptions:
   * - the external HSE clock from an external oscillator is used as base clock
   * - the internal PLL circuit is used for clock refinement
   *
   * Use the following formulas to calculate the needed values:
   *
   * SYSCLK = ((XTAL_SPEED / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_P
   * USB, SDIO and RNG Clock =  ((XTAL_SPEED / CLOCK_PLL_M) * CLOCK_PLL_N) / CLOCK_PLL_Q
   *
   * The actual used values are specified in the board's `periph_conf.h` file.
   *
   * NOTE: currently there is not timeout for initialization of PLL and other locks
   *       -> when wrong values are chosen, the initialization could stall
   */
  static void cpu_clock_init(void)
  {
      /* reset clock configuration register */
      RCC->CFGR = 0;
  
      /* disable HSE, CSS and PLL */
      RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_HSEBYP | RCC_CR_CSSON | RCC_CR_PLLON);
  
      /* disable all clock interrupts */
      RCC->CIR = 0;
  
      /* enable the high speed clock */
      RCC->CR |= CLOCK_CR_SOURCE;
  
      /* wait for the high speed clock source to be ready */
      while (!(RCC->CR & CLOCK_CR_SOURCE_RDY)) {}
  
      /* setup power module */
  
      /* enable the power module */
      periph_clk_en(APB1, RCC_APB1ENR_PWREN);
      /* set the voltage scaling to 1 to enable the maximum frequency */
      PWR->CR |= PWR_CR_VOS_1;
  
      /* setup the peripheral bus prescalers */
  
      /* set the AHB clock divider */
      RCC->CFGR &= ~RCC_CFGR_HPRE;
      RCC->CFGR |= CLOCK_AHB_DIV;
      /* set the APB2 (high speed) bus clock divider */
      RCC->CFGR &= ~RCC_CFGR_PPRE2;
      RCC->CFGR |= CLOCK_APB2_DIV;
      /* set the APB1 (low speed) bus clock divider */
      RCC->CFGR &= ~RCC_CFGR_PPRE1;
      RCC->CFGR |= CLOCK_APB1_DIV;
  
      /* configure the PLL */
  
      /* reset PLL config register */
      RCC->PLLCFGR = 0;
      /* set high speed clock as source for the PLL */
      RCC->PLLCFGR |= CLOCK_PLL_SOURCE;
      /* set division factor for main PLL input clock */
      RCC->PLLCFGR |= (CLOCK_PLL_M & 0x3F);
      /* set main PLL multiplication factor for VCO */
      RCC->PLLCFGR |= (CLOCK_PLL_N & 0x1FF) << 6;
      /* set main PLL division factor for main system clock */
      RCC->PLLCFGR |= (((CLOCK_PLL_P & 0x03) >> 1) - 1) << 16;
      /* set main PLL division factor for USB OTG FS, SDIO and RNG clocks */
      RCC->PLLCFGR |= (CLOCK_PLL_Q & 0x0F) << 24;
  
      /* enable PLL again */
      RCC->CR |= RCC_CR_PLLON;
      /* wait until PLL is stable */
      while(!(RCC->CR & RCC_CR_PLLRDY)) {}
  
      /* configure flash latency */
  
      /* reset flash access control register */
      FLASH->ACR = 0;
      /* enable instruction cache */
      FLASH->ACR |= FLASH_ACR_ICEN;
      /* enable data cache */
      FLASH->ACR |= FLASH_ACR_DCEN;
      /* enable pre-fetch buffer */
      // FLASH->ACR |= FLASH_ACR_PRFTEN;
      /* set flash latency */
      FLASH->ACR &= ~FLASH_ACR_LATENCY;
      FLASH->ACR |= CLOCK_FLASH_LATENCY;
  
      /* configure the sysclock and the peripheral clocks */
  
      /* set sysclock to be driven by the PLL clock */
      RCC->CFGR &= ~RCC_CFGR_SW;
      RCC->CFGR |= RCC_CFGR_SW_PLL;
  
      /* wait for sysclock to be stable */
      while (!(RCC->CFGR & RCC_CFGR_SWS_PLL)) {}
  
  #if CLOCK_DISABLE_HSI
      /* disable the HSI if we use the HSE */
      RCC->CR &= ~(RCC_CR_HSION);
      while (RCC->CR & RCC_CR_HSIRDY) {}
  #endif
  }