Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:05

0001 /*
0002  * Copyright (c) 2012 Sebastian Huber.  All rights reserved.
0003  *
0004  * The license and distribution terms for this file may be
0005  * found in the file LICENSE in this distribution or at
0006  * http://www.rtems.org/license/LICENSE.
0007  */
0008 
0009 #include <bsp.h>
0010 #include <bsp/io.h>
0011 #include <bsp/irq.h>
0012 #include <bsp/bootcard.h>
0013 #include <bsp/irq-generic.h>
0014 #include <assert.h>
0015 #include <bsp/stm32f4.h>
0016 
0017 #ifdef STM32F4_FAMILY_F4XXXX
0018 
0019 #include <bsp/stm32f4xxxx_rcc.h>
0020 #include <bsp/stm32f4xxxx_flash.h>
0021 
0022 static rtems_status_code set_system_clk(
0023   uint32_t sys_clk,
0024   uint32_t hse_clk,
0025   uint32_t hse_flag
0026 );
0027 
0028 static void init_main_osc( void )
0029 {
0030   volatile stm32f4_rcc *rcc = STM32F4_RCC;
0031   rtems_status_code     status;
0032 
0033   /* Revert to reset values */
0034   rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
0035 
0036   while ( !( rcc->cr & RCC_CR_HSIRDY ) ) ;
0037 
0038   rcc->cfgr &= 0x00000300; /* all prescalers to 0, clock source to HSI */
0039 
0040   rcc->cr &= 0xF0F0FFFD;   /* turn off all clocks and PLL except HSI */
0041 
0042   status = set_system_clk( STM32F4_SYSCLK / 1000000L,
0043     STM32F4_HSE_OSCILLATOR / 1000000L,
0044     1 );
0045 
0046   assert( rtems_is_status_successful( status ) );
0047 }
0048 
0049 /**
0050  * @brief Sets up clocks configuration.
0051  *
0052  * Set up clocks configuration to achieve desired system clock
0053  * as close as possible with simple math.
0054  *
0055  * Limitations:
0056  * It is assumed that 1MHz resolution is enough.
0057  * Best fits for the clocks are achieved with multiplies of 42MHz.
0058  * Even though APB1, APB2 and AHB are calculated user is still required
0059  * to provide correct values for the bsp configuration for the:
0060  * STM32F4_PCLK1
0061  * STM32F4_PCLK2
0062  * STM32F4_HCLK
0063  * as those are used for the peripheral clocking calculations.
0064  *
0065  * @param sys_clk Desired system clock in MHz.
0066  * @param hse_clk External clock speed in MHz.
0067  * @param hse_flag Flag determining which clock source to use, 1 for HSE,
0068  *                 0 for HSI.
0069  *
0070  * @retval RTEMS_SUCCESSFUL Configuration has been succesfully aplied for the
0071  *                          requested clock speed.
0072  * @retval RTEMS_TIMEOUT HSE clock didn't start or PLL didn't lock.
0073  * @retval RTEMS_INVALID_NUMBER Requested clock speed is out of range.
0074  */
0075 static rtems_status_code set_system_clk(
0076   uint32_t sys_clk,
0077   uint32_t hse_clk,
0078   uint32_t hse_flag
0079 )
0080 {
0081   volatile stm32f4_rcc   *rcc = STM32F4_RCC;
0082   volatile stm32f4_flash *flash = STM32F4_FLASH;
0083   long                    timeout = 0;
0084 
0085   int src_clk = 0;
0086 
0087   uint32_t pll_m = 0;
0088   uint32_t pll_n = 0;
0089   uint32_t pll_p = 0;
0090   uint32_t pll_q = 0;
0091 
0092   uint32_t ahbpre = 0;
0093   uint32_t apbpre1 = 0;
0094   uint32_t apbpre2 = 0;
0095 
0096   if ( sys_clk == 16 && hse_clk != 16 ) {
0097     /* Revert to reset values */
0098     rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
0099 
0100     while ( !( rcc->cr & RCC_CR_HSIRDY ) ) ;
0101 
0102     /* all prescalers to 0, clock source to HSI */
0103     rcc->cfgr &= 0x00000300 | RCC_CFGR_SW_HSI;
0104     rcc->cr &= 0xF0F0FFFD;   /* turn off all clocks and PLL except HSI */
0105     flash->acr = 0; /* slow clock so no cache, no prefetch, no latency */
0106 
0107     return RTEMS_SUCCESSFUL;
0108   }
0109 
0110   if ( sys_clk == hse_clk ) {
0111     /* Revert to reset values */
0112     rcc->cr |= RCC_CR_HSEON;   /* turn on HSE */
0113     timeout = 400;
0114 
0115     while ( !( rcc->cr & RCC_CR_HSERDY ) && --timeout ) ;
0116 
0117     assert( timeout != 0 );
0118 
0119     if ( timeout == 0 ) {
0120       return RTEMS_TIMEOUT;
0121     }
0122 
0123     /* all prescalers to 0, clock source to HSE */
0124     rcc->cfgr &= 0x00000300;
0125     rcc->cfgr |= RCC_CFGR_SW_HSE;
0126     /* turn off all clocks and PLL except HSE */
0127     rcc->cr &= 0xF0F0FFFC | RCC_CR_HSEON;
0128     flash->acr = 0; /* slow clock so no cache, no prefetch, no latency */
0129 
0130     return RTEMS_SUCCESSFUL;
0131   }
0132 
0133   /*
0134    * Lets use 1MHz input for PLL so we get higher VCO output
0135    * this way we get better value for the PLL_Q divader for the USB
0136    *
0137    * Though you might want to use 2MHz as per CPU specification:
0138    *
0139    * Caution:The software has to set these bits correctly to ensure
0140    * that the VCO input frequency ranges from 1 to 2 MHz.
0141    * It is recommended to select a frequency of 2 MHz to limit PLL jitter.
0142    */
0143 
0144   if ( sys_clk > 180 ) {
0145     return RTEMS_INVALID_NUMBER;
0146   } else if ( sys_clk >= 96 ) {
0147     pll_n = sys_clk << 1;
0148     pll_p = RCC_PLLCFGR_PLLP_BY_2;
0149   } else if ( sys_clk >= 48 ) {
0150     pll_n = sys_clk << 2;
0151     pll_p = RCC_PLLCFGR_PLLP_BY_4;
0152   } else if ( sys_clk >= 24 ) {
0153     pll_n = sys_clk << 3;
0154     pll_p = RCC_PLLCFGR_PLLP_BY_8;
0155   } else {
0156     return RTEMS_INVALID_NUMBER;
0157   }
0158 
0159   if ( hse_clk == 0 || hse_flag == 0 ) {
0160     src_clk = 16;
0161     hse_flag = 0;
0162   } else {
0163     src_clk = hse_clk;
0164   }
0165 
0166   pll_m = src_clk; /* divide by the oscilator speed in MHz */
0167 
0168   /* pll_q is a prescaler from VCO for the USB OTG FS, SDIO and RNG,
0169    * best if results in the 48MHz for the USB
0170    */
0171   pll_q = ( (long) ( src_clk * pll_n ) ) / pll_m / 48;
0172 
0173   if ( pll_q < 2 ) {
0174     pll_q = 2;
0175   }
0176 
0177   /* APB1 prescaler, APB1 clock must be < 42MHz */
0178   apbpre1 = ( sys_clk * 100 ) / 42;
0179 
0180   if ( apbpre1 <= 100 ) {
0181     apbpre1 = RCC_CFGR_PPRE1_BY_1;
0182   } else if ( apbpre1 <= 200 ) {
0183     apbpre1 = RCC_CFGR_PPRE1_BY_2;
0184   } else if ( apbpre1 <= 400 ) {
0185     apbpre1 = RCC_CFGR_PPRE1_BY_4;
0186   } else if ( apbpre1 <= 800 ) {
0187     apbpre1 = RCC_CFGR_PPRE1_BY_8;
0188   } else if ( apbpre1 ) {
0189     apbpre1 = RCC_CFGR_PPRE1_BY_16;
0190   }
0191 
0192   /* APB2 prescaler, APB2 clock must be < 84MHz */
0193   apbpre2 = ( sys_clk * 100 ) / 84;
0194 
0195   if ( apbpre2 <= 100 ) {
0196     apbpre2 = RCC_CFGR_PPRE2_BY_1;
0197   } else if ( apbpre2 <= 200 ) {
0198     apbpre2 = RCC_CFGR_PPRE2_BY_2;
0199   } else if ( apbpre2 <= 400 ) {
0200     apbpre2 = RCC_CFGR_PPRE2_BY_4;
0201   } else if ( apbpre2 <= 800 ) {
0202     apbpre2 = RCC_CFGR_PPRE2_BY_8;
0203   } else {
0204     apbpre2 = RCC_CFGR_PPRE2_BY_16;
0205   }
0206 
0207   rcc->cr |= RCC_CR_HSION;   /* turn on HSI */
0208 
0209   while ( ( !( rcc->cr & RCC_CR_HSIRDY ) ) ) ;
0210 
0211   /* all prescalers to 0, clock source to HSI */
0212   rcc->cfgr &= 0x00000300;
0213   rcc->cfgr |= RCC_CFGR_SW_HSI;
0214 
0215   while ( ( ( rcc->cfgr & RCC_CFGR_SWS_MSK ) != RCC_CFGR_SWS_HSI ) ) ;
0216 
0217   /* turn off PLL */
0218   rcc->cr &= ~( RCC_CR_PLLON | RCC_CR_PLLRDY );
0219 
0220   /* turn on HSE */
0221   if ( hse_flag ) {
0222     rcc->cr |= RCC_CR_HSEON;
0223     timeout = 400;
0224 
0225     while ( ( !( rcc->cr & RCC_CR_HSERDY ) ) && timeout-- ) ;
0226 
0227     assert( timeout != 0 );
0228 
0229     if ( timeout == 0 ) {
0230       return RTEMS_TIMEOUT;
0231     }
0232   }
0233 
0234   rcc->pllcfgr &= 0xF0BC8000; /* clear PLL prescalers */
0235 
0236   /* set pll parameters */
0237   rcc->pllcfgr |= RCC_PLLCFGR_PLLM( pll_m ) | /* input divider */
0238                   RCC_PLLCFGR_PLLN( pll_n ) | /* multiplier */
0239                   pll_p |                     /* output divider from table */
0240                                               /* HSE v HSI */
0241                   ( hse_flag ? RCC_PLLCFGR_PLLSRC_HSE : RCC_PLLCFGR_PLLSRC_HSI )
0242                   |
0243                   RCC_PLLCFGR_PLLQ( pll_q );    /* PLLQ divider */
0244 
0245   /* set prescalers for the internal busses */
0246   rcc->cfgr |= apbpre1 |
0247                apbpre2 |
0248                ahbpre;
0249 
0250   /*
0251    * Set flash parameters, hard coded for now for fast system clocks.
0252    * TODO implement some math to use flash on as low latancy as possible
0253    */
0254   flash->acr = STM32F4_FLASH_ACR_LATENCY( 5 ) | /* latency */
0255                STM32F4_FLASH_ACR_ICEN |       /* instruction cache */
0256                STM32F4_FLASH_ACR_DCEN |        /* data cache */
0257                STM32F4_FLASH_ACR_PRFTEN;
0258 
0259   /* turn on PLL */
0260   rcc->cr |= RCC_CR_PLLON;
0261   timeout = 40000;
0262 
0263   while ( ( !( rcc->cr & RCC_CR_PLLRDY ) ) && --timeout ) ;
0264   
0265   assert( timeout != 0 );
0266 
0267   if ( timeout == 0 ) {
0268     return RTEMS_TIMEOUT;
0269   }
0270 
0271   /* clock source to PLL */
0272   rcc->cfgr = ( rcc->cfgr & ~RCC_CFGR_SW_MSK ) | RCC_CFGR_SW_PLL;
0273 
0274   while ( ( ( rcc->cfgr & RCC_CFGR_SWS_MSK ) != RCC_CFGR_SWS_PLL ) ) ;
0275 
0276   return RTEMS_SUCCESSFUL;
0277 }
0278 
0279 #endif /* STM32F4_FAMILY_F4XXXX */
0280 
0281 #ifdef STM32F4_FAMILY_F10XXX
0282 
0283 static void init_main_osc( void )
0284 {
0285 
0286 }
0287 
0288 #endif /* STM32F4_FAMILY_F10XXX */
0289 
0290 void bsp_start( void )
0291 {
0292   init_main_osc();
0293 
0294   stm32f4_gpio_set_config_array( &stm32f4_start_config_gpio[ 0 ] );
0295 
0296   bsp_interrupt_initialize();
0297 }