source: rtems/bsps/arm/stm32f4/start/bspstart.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

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