-
Notifications
You must be signed in to change notification settings - Fork 20
systemclock
myCortex-STM32F4 예제는 STM32F4 MCU에 168MHz 클럭으로 구성되어 있습니다.
STM32 MCU의 클럭은 SYSCLK라 불리는 시스템 클럭을 기반으로 결정됩니다. 위에서 말한 168MHz가 SYSCLK 입니다. SYSCLK를 결정하는 것은 클럭소스, PLL 등이 있습니다.
우선 클럭 소스로 사용될 수 있는 것은 아래와 같습니다.
- 내장 RC 오실레이터(HSI)
- 16MHz 발진회로가 내장되어 있습니다.
- 별도의 외부 회로가 필요하지 않습니다.
- RC 오실레이터이므로 정밀한 동작에는 적합하지 않습니다. -4~+4% 정도의 오차 범위를 가지고 있습니다.
- 외장 오실레이터(HSE)
- MCU 내부에 Pierce 오실레이터가 내장되어 있어 외부에 크리스털과 load capacitor만 추가하면 됩니다.
- 혹은 외부에 자체 발진하는 오실레이터를 사용해도 됩니다.
- 외장 오실레이터는 1
50MHz 범위의 클럭을 사용할 수 있습니다. 크리스털이나 레조네이터를 사용하는 경우에는 426MHz 클럭을 사용할 수 있습니다.
위 두 클럭 소스는 모두 그대로 SYSCLK로 사용될 수 있습니다. 또한 이 클럭 소스를 PLL 회로의 입력에 연결하여 보다 높은 클럭을 구현할 수도 있습니다. STM32F407VE의 PLL은 최대 168MHz의 출력 클럭을 지원합니다.
PLL은 1MHz의 클럭 입력을 받아 이를 최대 336MHz로 높인 후 최종적으로 168MHz 클럭을 출력합니다.
SYSCLK는 HSI, HSE, PLL 출력 중 하나로 설정될 수 있습니다.
아래 그림은 STM32F4의 클럭을 요약한 것입니다. MCU를 제대로 사용하기 위해서는 클럭 시스템을 이해하는 것이 가장 중요하며, 이 그림은 앞으로 자주 보게 될 것입니다.

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 */
}
}