source: rtems/c/src/lib/libbsp/arm/stm32f4/startup/bspstart.c @ 040ed0b4

4.11
Last change on this file since 040ed0b4 was 040ed0b4, checked in by Chris Nott <chrisn@…>, on Oct 18, 2014 at 8:55:37 AM

bsp/stm32f4: Add header files

Added register definition headers for STM32F4 ADC, EXTI, PWR, SYSCFG,
TIM, OTGFS and updated FLASH and RCC. Fixed PLL_Q for USB 48MHz
operation. Added flash prefetch enable.

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2012 Sebastian Huber.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Obere Lagerstr. 30
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <bsp.h>
16#include <bsp/io.h>
17#include <bsp/irq.h>
18#include <bsp/bootcard.h>
19#include <bsp/irq-generic.h>
20#include <assert.h>
21#include <bsp/stm32f4.h>
22
23#ifdef STM32F4_FAMILY_F4XXXX
24
25#include <bsp/stm32f4xxxx_rcc.h>
26#include <bsp/stm32f4xxxx_flash.h>
27
28static rtems_status_code set_system_clk(
29  uint32_t sys_clk,
30  uint32_t hse_clk,
31  uint32_t hse_flag
32);
33
34static void init_main_osc( void )
35{
36  volatile stm32f4_rcc *rcc = STM32F4_RCC;
37  rtems_status_code     status;
38
39  /* Revert to reset values */
40  rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
41
42  while ( !( rcc->cr & RCC_CR_HSIRDY ) ) ;
43
44  rcc->cfgr &= 0x00000300; /* all prescalers to 0, clock source to HSI */
45
46  rcc->cr &= 0xF0F0FFFD;   /* turn off all clocks and PLL except HSI */
47
48  status = set_system_clk( STM32F4_SYSCLK / 1000000L,
49    STM32F4_HSE_OSCILLATOR / 1000000L,
50    1 );
51
52  assert( rtems_is_status_successful( status ) );
53}
54
55/**
56 * @brief Sets up clocks configuration.
57 *
58 * Set up clocks configuration to achieve desired system clock
59 * as close as possible with simple math.
60 *
61 * Limitations:
62 * It is assumed that 1MHz resolution is enough.
63 * Best fits for the clocks are achieved with multiplies of 42MHz.
64 * Even though APB1, APB2 and AHB are calculated user is still required
65 * to provide correct values for the bsp configuration for the:
66 * STM32F4_PCLK1
67 * STM32F4_PCLK2
68 * STM32F4_HCLK
69 * as those are used for the peripheral clocking calculations.
70 *
71 * @param sys_clk Desired system clock in MHz.
72 * @param hse_clk External clock speed in MHz.
73 * @param hse_flag Flag determining which clock source to use, 1 for HSE,
74 *                 0 for HSI.
75 *
76 * @retval RTEMS_SUCCESSFUL Configuration has been succesfully aplied for the
77 *                          requested clock speed.
78 * @retval RTEMS_TIMEOUT HSE clock didn't start or PLL didn't lock.
79 * @retval RTEMS_INVALID_NUMBER Requested clock speed is out of range.
80 */
81static rtems_status_code set_system_clk(
82  uint32_t sys_clk,
83  uint32_t hse_clk,
84  uint32_t hse_flag
85)
86{
87  volatile stm32f4_rcc   *rcc = STM32F4_RCC;
88  volatile stm32f4_flash *flash = STM32F4_FLASH;
89  long                    timeout = 0;
90
91  int src_clk = 0;
92
93  uint32_t pll_m = 0;
94  uint32_t pll_n = 0;
95  uint32_t pll_p = 0;
96  uint32_t pll_q = 0;
97
98  uint32_t ahbpre = 0;
99  uint32_t apbpre1 = 0;
100  uint32_t apbpre2 = 0;
101
102  if ( sys_clk == 16 && hse_clk != 16 ) {
103    /* Revert to reset values */
104    rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
105
106    while ( !( rcc->cr & RCC_CR_HSIRDY ) ) ;
107
108    /* all prescalers to 0, clock source to HSI */
109    rcc->cfgr &= 0x00000300 | RCC_CFGR_SW_HSI;
110    rcc->cr &= 0xF0F0FFFD;   /* turn off all clocks and PLL except HSI */
111    flash->acr = 0; /* slow clock so no cache, no prefetch, no latency */
112
113    return RTEMS_SUCCESSFUL;
114  }
115
116  if ( sys_clk == hse_clk ) {
117    /* Revert to reset values */
118    rcc->cr |= RCC_CR_HSEON;   /* turn on HSE */
119    timeout = 400;
120
121    while ( !( rcc->cr & RCC_CR_HSERDY ) && --timeout ) ;
122
123    assert( timeout != 0 );
124
125    if ( timeout == 0 ) {
126      return RTEMS_TIMEOUT;
127    }
128
129    /* all prescalers to 0, clock source to HSE */
130    rcc->cfgr &= 0x00000300;
131    rcc->cfgr |= RCC_CFGR_SW_HSE;
132    /* turn off all clocks and PLL except HSE */
133    rcc->cr &= 0xF0F0FFFC | RCC_CR_HSEON;
134    flash->acr = 0; /* slow clock so no cache, no prefetch, no latency */
135
136    return RTEMS_SUCCESSFUL;
137  }
138
139  /*
140   * Lets use 1MHz input for PLL so we get higher VCO output
141   * this way we get better value for the PLL_Q divader for the USB
142   *
143   * Though you might want to use 2MHz as per CPU specification:
144   *
145   * Caution:The software has to set these bits correctly to ensure
146   * that the VCO input frequency ranges from 1 to 2 MHz.
147   * It is recommended to select a frequency of 2 MHz to limit PLL jitter.
148   */
149
150  if ( sys_clk > 180 ) {
151    return RTEMS_INVALID_NUMBER;
152  } else if ( sys_clk >= 96 ) {
153    pll_n = sys_clk << 1;
154    pll_p = RCC_PLLCFGR_PLLP_BY_2;
155  } else if ( sys_clk >= 48 ) {
156    pll_n = sys_clk << 2;
157    pll_p = RCC_PLLCFGR_PLLP_BY_4;
158  } else if ( sys_clk >= 24 ) {
159    pll_n = sys_clk << 3;
160    pll_p = RCC_PLLCFGR_PLLP_BY_8;
161  } else {
162    return RTEMS_INVALID_NUMBER;
163  }
164
165  if ( hse_clk == 0 || hse_flag == 0 ) {
166    src_clk = 16;
167    hse_flag = 0;
168  } else {
169    src_clk = hse_clk;
170  }
171
172  pll_m = src_clk; /* divide by the oscilator speed in MHz */
173
174  /* pll_q is a prescaler from VCO for the USB OTG FS, SDIO and RNG,
175   * best if results in the 48MHz for the USB
176   */
177  pll_q = ( (long) ( src_clk * pll_n ) ) / pll_m / 48;
178
179  if ( pll_q < 2 ) {
180    pll_q = 2;
181  }
182
183  /* APB1 prescaler, APB1 clock must be < 42MHz */
184  apbpre1 = ( sys_clk * 100 ) / 42;
185
186  if ( apbpre1 <= 100 ) {
187    apbpre1 = RCC_CFGR_PPRE1_BY_1;
188  } else if ( apbpre1 <= 200 ) {
189    apbpre1 = RCC_CFGR_PPRE1_BY_2;
190  } else if ( apbpre1 <= 400 ) {
191    apbpre1 = RCC_CFGR_PPRE1_BY_4;
192  } else if ( apbpre1 <= 800 ) {
193    apbpre1 = RCC_CFGR_PPRE1_BY_8;
194  } else if ( apbpre1 ) {
195    apbpre1 = RCC_CFGR_PPRE1_BY_16;
196  }
197
198  /* APB2 prescaler, APB2 clock must be < 84MHz */
199  apbpre2 = ( sys_clk * 100 ) / 84;
200
201  if ( apbpre2 <= 100 ) {
202    apbpre2 = RCC_CFGR_PPRE2_BY_1;
203  } else if ( apbpre2 <= 200 ) {
204    apbpre2 = RCC_CFGR_PPRE2_BY_2;
205  } else if ( apbpre2 <= 400 ) {
206    apbpre2 = RCC_CFGR_PPRE2_BY_4;
207  } else if ( apbpre2 <= 800 ) {
208    apbpre2 = RCC_CFGR_PPRE2_BY_8;
209  } else {
210    apbpre2 = RCC_CFGR_PPRE2_BY_16;
211  }
212
213  rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
214
215  while ( ( !( rcc->cr & RCC_CR_HSIRDY ) ) ) ;
216
217  /* all prescalers to 0, clock source to HSI */
218  rcc->cfgr &= 0x00000300;
219  rcc->cfgr |= RCC_CFGR_SW_HSI;
220
221  while ( ( ( rcc->cfgr & RCC_CFGR_SWS_MSK ) != RCC_CFGR_SWS_HSI ) ) ;
222
223  /* turn off PLL */
224  rcc->cr &= ~( RCC_CR_PLLON | RCC_CR_PLLRDY );
225
226  /* turn on HSE */
227  if ( hse_flag ) {
228    rcc->cr |= RCC_CR_HSEON;
229    timeout = 400;
230
231    while ( ( !( rcc->cr & RCC_CR_HSERDY ) ) && timeout-- ) ;
232
233    assert( timeout != 0 );
234
235    if ( timeout == 0 ) {
236      return RTEMS_TIMEOUT;
237    }
238  }
239
240  rcc->pllcfgr &= 0xF0BC8000; /* clear PLL prescalers */
241
242  /* set pll parameters */
243  rcc->pllcfgr |= RCC_PLLCFGR_PLLM( pll_m ) | /* input divider */
244                  RCC_PLLCFGR_PLLN( pll_n ) | /* multiplier */
245                  pll_p |                     /* output divider from table */
246                                              /* HSE v HSI */
247                  ( hse_flag ? RCC_PLLCFGR_PLLSRC_HSE : RCC_PLLCFGR_PLLSRC_HSI )
248                  |
249                  RCC_PLLCFGR_PLLQ( pll_q );    /* PLLQ divider */
250
251  /* set prescalers for the internal busses */
252  rcc->cfgr |= apbpre1 |
253               apbpre2 |
254               ahbpre;
255
256  /*
257   * Set flash parameters, hard coded for now for fast system clocks.
258   * TODO implement some math to use flash on as low latancy as possible
259   */
260  flash->acr = STM32F4_FLASH_ACR_LATENCY( 5 ) | /* latency */
261               STM32F4_FLASH_ACR_ICEN |       /* instruction cache */
262               STM32F4_FLASH_ACR_DCEN |        /* data cache */
263               STM32F4_FLASH_ACR_PRFTEN;
264
265  /* turn on PLL */
266  rcc->cr |= RCC_CR_PLLON;
267  timeout = 40000;
268
269  while ( ( !( rcc->cr & RCC_CR_PLLRDY ) ) && --timeout ) ;
270 
271  assert( timeout != 0 );
272
273  if ( timeout == 0 ) {
274    return RTEMS_TIMEOUT;
275  }
276
277  /* clock source to PLL */
278  rcc->cfgr = ( rcc->cfgr & ~RCC_CFGR_SW_MSK ) | RCC_CFGR_SW_PLL;
279
280  while ( ( ( rcc->cfgr & RCC_CFGR_SWS_MSK ) != RCC_CFGR_SWS_PLL ) ) ;
281
282  return RTEMS_SUCCESSFUL;
283}
284
285#endif /* STM32F4_FAMILY_F4XXXX */
286
287#ifdef STM32F4_FAMILY_F10XXX
288
289static void init_main_osc( void )
290{
291
292}
293
294#endif /* STM32F4_FAMILY_F10XXX */
295
296void bsp_start( void )
297{
298  init_main_osc();
299
300  stm32f4_gpio_set_config_array( &stm32f4_start_config_gpio[ 0 ] );
301
302  bsp_interrupt_initialize();
303}
Note: See TracBrowser for help on using the repository browser.