systemclock - withrobot/myCortex-STM32F4 GitHub Wiki

myCortex-STM32F4 μ˜ˆμ œλŠ” STM32F4 MCU에 168MHz 클럭으둜 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

STM32 MCU의 ν΄λŸ­μ€ SYSCLK라 λΆˆλ¦¬λŠ” μ‹œμŠ€ν…œ ν΄λŸ­μ„ 기반으둜 κ²°μ •λ©λ‹ˆλ‹€. μœ„μ—μ„œ λ§ν•œ 168MHzκ°€ SYSCLK μž…λ‹ˆλ‹€. SYSCLKλ₯Ό κ²°μ •ν•˜λŠ” 것은 ν΄λŸ­μ†ŒμŠ€, PLL 등이 μžˆμŠ΅λ‹ˆλ‹€.

μš°μ„  클럭 μ†ŒμŠ€λ‘œ μ‚¬μš©λ  수 μžˆλŠ” 것은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

  • λ‚΄μž₯ RC μ˜€μ‹€λ ˆμ΄ν„°(HSI)
    • 16MHz λ°œμ§„νšŒλ‘œκ°€ λ‚΄μž₯λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
    • λ³„λ„μ˜ μ™ΈλΆ€ νšŒλ‘œκ°€ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    • RC μ˜€μ‹€λ ˆμ΄ν„°μ΄λ―€λ‘œ μ •λ°€ν•œ λ™μž‘μ—λŠ” μ ν•©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. -4~+4% μ •λ„μ˜ 였차 λ²”μœ„λ₯Ό 가지고 μžˆμŠ΅λ‹ˆλ‹€.
  • μ™Έμž₯ μ˜€μ‹€λ ˆμ΄ν„°(HSE)
    • MCU 내뢀에 Pierce μ˜€μ‹€λ ˆμ΄ν„°κ°€ λ‚΄μž₯λ˜μ–΄ μžˆμ–΄ 외뢀에 ν¬λ¦¬μŠ€ν„Έκ³Ό load capacitor만 μΆ”κ°€ν•˜λ©΄ λ©λ‹ˆλ‹€.
    • ν˜Ήμ€ 외뢀에 자체 λ°œμ§„ν•˜λŠ” μ˜€μ‹€λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•΄λ„ λ©λ‹ˆλ‹€.
    • μ™Έμž₯ μ˜€μ‹€λ ˆμ΄ν„°λŠ” 150MHz λ²”μœ„μ˜ ν΄λŸ­μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. ν¬λ¦¬μŠ€ν„Έμ΄λ‚˜ λ ˆμ‘°λ„€μ΄ν„°λ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λŠ” 426MHz ν΄λŸ­μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μœ„ 두 클럭 μ†ŒμŠ€λŠ” λͺ¨λ‘ κ·ΈλŒ€λ‘œ SYSCLK둜 μ‚¬μš©λ  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ 이 클럭 μ†ŒμŠ€λ₯Ό PLL 회둜의 μž…λ ₯에 μ—°κ²°ν•˜μ—¬ 보닀 높은 ν΄λŸ­μ„ κ΅¬ν˜„ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. STM32F407VE의 PLL은 μ΅œλŒ€ 168MHz의 좜λ ₯ ν΄λŸ­μ„ μ§€μ›ν•©λ‹ˆλ‹€.

PLL은 1MHz의 클럭 μž…λ ₯을 λ°›μ•„ 이λ₯Ό μ΅œλŒ€ 336MHz둜 높인 ν›„ μ΅œμ’…μ μœΌλ‘œ 168MHz ν΄λŸ­μ„ 좜λ ₯ν•©λ‹ˆλ‹€.

SYSCLKλŠ” HSI, HSE, PLL 좜λ ₯ 쀑 ν•˜λ‚˜λ‘œ 섀정될 수 μžˆμŠ΅λ‹ˆλ‹€.

μ•„λž˜ 그림은 STM32F4의 ν΄λŸ­μ„ μš”μ•½ν•œ κ²ƒμž…λ‹ˆλ‹€. MCUλ₯Ό μ œλŒ€λ‘œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 클럭 μ‹œμŠ€ν…œμ„ μ΄ν•΄ν•˜λŠ” 것이 κ°€μž₯ μ€‘μš”ν•˜λ©°, 이 그림은 μ•žμœΌλ‘œ 자주 보게 될 κ²ƒμž…λ‹ˆλ‹€.

clock

myCortex-STM32F4의 예제 μ†ŒμŠ€μ—μ„œλŠ” drv/system_stm32f4xx.c 파일의 SetSysClock() ν•¨μˆ˜μ—μ„œ SYSCLK 섀정을 ν•©λ‹ˆλ‹€. λ³΄λ“œμ— μž₯착된 8MHz ν¬λ¦¬μŠ€ν„Έμ„ μ΄μš©ν•΄ HSE μ˜€μ‹€λ ˆμ΄ν„°λ₯Ό κΈ°λ™ν•˜κ³ , 이λ₯Ό PLL μž…λ ₯으둜 μ—°κ²°ν•΄μ„œ μ΅œμ’…μ μœΌλ‘œ 168MHz 클럭 좜λ ₯을 SYSCLK둜 μ‚¬μš©ν•©λ‹ˆλ‹€.

static void SetSysClock(void)
{
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  /* Enable HSE */
#if FEATURE_HSE_OSC16
  RCC->CR |= ((uint32_t)(RCC_CR_HSEON | RCC_CR_HSEBYP));

  HSEStatus = (uint32_t)0x01;
#else
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

HSE μ˜€μ‹€λ ˆμ΄ν„°λ₯Ό enable μ‹œν‚΅λ‹ˆλ‹€.

  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

μ˜€μ‹€λ ˆμ΄ν„°κ°€ enable 된 λ‹€μŒμ—λŠ” μ˜€μ‹€λ ˆμ΄ν„°κ°€ μ•ˆμ •ν™” 될 λ•Œ κΉŒμ§€ μž μ‹œ μ‹œκ°„μ΄ ν•„μš”ν•©λ‹ˆλ‹€. μ•ˆμ •ν™” 되면 κ΄€λ ¨ flagκ°€ μžλ™μœΌλ‘œ set λ˜μ–΄ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }
#endif  // FEATURE_HSE_OSC16

  if (HSEStatus == (uint32_t)0x01)
  {

HSEκ°€ μ„±κ³΅μ μœΌλ‘œ λ™μž‘ν•˜λ©΄ 이곳으둜 μ§„μž…ν•©λ‹ˆλ‹€.

    /* Select regulator voltage output Scale 1 mode */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS;

MCU coreλ₯Ό μœ„ν•œ λ ˆκ·€λ ˆμ΄ν„°λ₯Ό μ„€μ •ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

    /* HCLK = SYSCLK / 1*/
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

HCLKλŠ” SYSCLK κ·ΈλŒ€λ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.

#if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)
    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;

    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx */

PCLK1은 HCLK/4 즉 168/4=42MHzλ₯Ό, PCLK2λŠ” HCLK/2 즉 84MHzλ₯Ό μ‚¬μš©ν•˜κ² λ‹€κ³  μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€. PCLKλŠ” peripheral bus clock이며, RCC μ„€μ •μ‹œ APB1, APB2에 μ‚¬μš©λ˜λŠ” ν΄λŸ­μ„ μ˜λ―Έν•©λ‹ˆλ‹€.

#if defined (STM32F401xx)
    /* PCLK2 = HCLK / 2*/
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;

    /* PCLK1 = HCLK / 4*/
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
#endif /* STM32F401xx */

이 μ½”λ“œλŠ” μ‚¬μš©λ˜μ§€ μ•ŠλŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.

    /* Configure the main PLL */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

    /* Enable the main PLL */
    RCC->CR |= RCC_CR_PLLON;

PLL 섀정을 ν•˜κ³  PLL을 on μ‹œν‚΅λ‹ˆλ‹€. PLL μž…λ ₯은 1MHzμ—¬μ•Ό ν•©λ‹ˆλ‹€. κ·Έλž˜μ„œ HSE 8MHzλ₯Ό 8λΆ„μ£Όν•΄μ„œ 1MHzλ₯Ό λ§Œλ“­λ‹ˆλ‹€. PLL_M은 8λΆ„μ£Όλ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

PLL_N은 PLL λ‚΄λΆ€μ—μ„œ 생성할 ν΄λŸ­μ„ μ˜λ―Έν•©λ‹ˆλ‹€. μ΅œλŒ€ 336MHzκΉŒμ§€ κ°€λŠ₯ν•©λ‹ˆλ‹€.

PLL_PλŠ” PLL λ‚΄λΆ€μ—μ„œ μƒμ„±λœ 336MHz ν΄λŸ­μ„ λ‹€μ‹œ λΆ„μ£Όν•΄μ„œ SYSCLK둜 μ‚¬μš©ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. STM32F4λŠ” SYSCLK에 μ΅œλŒ€ 168MHz κΉŒμ§€ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 336MHzλ₯Ό 2λΆ„μ£Όν•˜λ©΄ 168MHzκ°€ λ§Œλ“€μ–΄μ§‘λ‹ˆλ‹€.

RCC_PLLCFGR_PLLSRC_HSEλŠ” PLL μž…λ ₯ μ†ŒμŠ€λ‘œ HSE ν΄λŸ­μ„ μ‚¬μš©ν•˜κ² λ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.

PLL_QλŠ” APB1, APB2κ°€ μ•„λ‹Œ μ „μš© ν΄λŸ­μ„ μ‚¬μš©ν•˜λŠ” μž₯치λ₯Ό μœ„ν•œ 별도 클럭 라인을 μœ„ν•œ λΆ„μ£ΌνšŒλ‘œμž…λ‹ˆλ‹€. 이런 μž₯μΉ˜μ—λŠ” USB, SDIO, RNG 등이 μžˆμŠ΅λ‹ˆλ‹€.

    /* Wait till the main PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

PLL이 μ•ˆμ •ν™” 될 λ•Œ κΉŒμ§€ κΈ°λ‹€λ Έλ‹€κ°€ μ§„ν–‰ν•©λ‹ˆλ‹€.

#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
    /* Enable the Over-drive to extend the clock frequency to 180 Mhz */
    PWR->CR |= PWR_CR_ODEN;
    while((PWR->CSR & PWR_CSR_ODRDY) == 0)
    {
    }
    PWR->CR |= PWR_CR_ODSWEN;
    while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
    {
    }
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F427_437x || STM32F429_439xx  */

μœ„ μ½”λ“œλŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ½”λ“œμž…λ‹ˆλ‹€.

#if defined (STM32F40_41xxx)
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    // 20131217 hwpark. errata sheet. rev.A
    if (DBGMCU->IDCODE & DBGMCU_IDCODE_REV_ID == 0x20000000)    // revision A
        FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
    else    // revision Z or later
        FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F40_41xxx  */

캐쉬 λ©”λͺ¨λ¦¬ κ΄€λ ¨ μ„€μ •μž…λ‹ˆλ‹€. STM32F4 MCU의 초기 λ²„μ „μ—λŠ” 칩에 버그가 μžˆμ–΄ prefetch κΈ°λŠ₯을 μ‚¬μš©ν•  수 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ§€κΈˆμ€ 이 κΈ°λŠ₯을 μ •μƒμ μœΌλ‘œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 μ½”λ“œλŠ” μΉ© 리비전에 따라 prefetch κΈ°λŠ₯을 μ‚΄λ¦¬κ±°λ‚˜ μ£½μ΄λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

#if defined (STM32F401xx)
    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
#endif /* STM32F401xx */

    /* Select the main PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;

이제 PLL 클럭이 μ •μƒμ μœΌλ‘œ λ§Œλ“€μ–΄ 지고 μžˆμœΌλ‹ˆ PLL 좜λ ₯ ν΄λŸ­μ„ SYSCLK둜 μ§€μ •ν•©λ‹ˆλ‹€.

    /* Wait till the main PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock
         configuration. User can add here some code to deal with this error */
  }

}