본문 바로가기
임베디드/STM32

18. [STM32] Clock

by fuhehe 2024. 11. 14.

모든 디지털 회로는 클럭을 기반으로 작동한다. 이 Clock이 Low/High로 전환될때 Rising/Falling Edge 박자에 맞춰 동작을 수행하도록 설계되어 있다.
따라서 클럭속도가 증가할수록 해당 회로의 속도는 빨라지고 소비전력이 늘어나는건 당연하다.

STM32의 경우도 마찬가지로 메인 시스템과, Peripheral등도 각각의 클럭을 입력받아 동작한다.
이번시간에는 이 STM32의 클럭에 대해 알아보자.

 

 

  • 본 블로그는 STM32를 소프트웨어 엔지니어 관점에서 바라본 블로그입니다. 따라서 회로등의 전자공학 관련 내용은 사실과 다를 수 있습니다.
  • 본 블로그에서 사용된 MCU 및 개발보드는 다음과 같습니다.
    1. NUCLEO-F429ZI (STM32F429ZIT LQFP144)
    2. NUCLEO-F439ZI (STM32F439ZIT LQFP144)

 

 

 

 

 

1. STM32의 Clock종류

STM32는 기본적으로 High-Speed클럭과 Low-Speed클럭 두가지 종류의 클럭을 사용한다.
High-Speed클럭은 메인 System 클럭(SYSCLK)과 각 Peripheral용 클럭에 사용되며 Low-Speed클럭은 RTC와 IWDG쪽에 사용된다.
SYSCLK과 Peripheral등은 시스템이 허용하는한 빠르게 동작해야 하므로 High-Speed클럭을 사용하지만 시계의 시간을 관리하는 RTC나 시스템의 동작여부를 체크하는 IWDG등은 상대적으로 빠른속도의 클럭이 불필요하므로 Low-Speed클럭을 사용한다.

 

STM32는 기본적으로 내부에 High-Speed클럭과 Low-Speed클럭을 발생시키는 RC 오실레이터를 내장하고 있으며 이들 클럭은 외부 소스로 대체할 수 있다.

내장된 클럭의 경우 온도가 25℃에서 1%의 오차를 가지도록 Calibration되어 있고 각 칩마다 이 Calibration정보가 RCC_CR레지스터의 HSICAL[7:0]비트에 저장되어 있다.

즉, 온도가 25 ℃ 가 아닌 경우 클럭의 속도는 부정확해진다. 따라서 클럭속도가 중요한 상황이고 외부온도가 25 ℃ 보다 높거나 낮다면 내부 클럭을 사용하면 안되고 별도의 외부 클럭을 사용해야 한다.

 

아무튼 STM32는 High-Speed클럭, Low-Speed클럭 두종류가 있으며, 각각 외부클럭과 내부클럭을 선택해 사용할 수 있도록 설계되어 있다.

따라서 이를 정리해보면 아래 4개의 클럭으로 나눠진다.

  • HSE(External High-Speed Clock) : High-Speed의 외부 클럭.
  • HSI(Interal High-Speed Clock) : High-Speed의 내부 클럭. (16MHz)
  • LSE(External Low-Speed Clock) : Low-Speed의 외부 클럭.
  • LSI(Interal Low-Speed Clock) : Low-Speed의 내부 클럭. (32KHz)

 

그리고 다음은 NUCLEO-F429Zi/439Zi 보드의 외부 클럭 구성이다.

  • HSE : ST-Link에서 사용하는 MCO(Master Clock Output)클럭을 HSE 소스로 사용한다. 이 클럭의 경우 8MHz로 고정되어 있다. 
    • ST-Link의 MCO사용(Default) : 보드의 기본 설정값으로 PH0을 통해 MCO의 클럭을 입력받는다. SB148은 Off, SB112, SB149는 On, SB8, SB9는 Off상태여야 한다.
    • X3외부 클럭사용 : 보드의 MCU밑에 보면 X3에 외부 오실레이터나 크리스탈을 붙일 수 있는 곳이 있다. 여기에 외부 클럭을 붙이고 SB148, SB163은 Off, SB8, SB9는 On, SB112, SB149는 Off,  그리고 C37, C38에 4.3pF커패시터를 붙여서 별도의 외부 클럭을 사용할 수 있다.
    • PF0/PH0핀을 통한 외부 클럭 사용 : SB148은 On, SB112, SB149는 Off, SB8, SB9는 제거를 해서 GPIO핀을 통한 클럭입력이 가능하다.
    • HSE미사용 : 외부 클럭이 필요없다면 SB148, SB163은 On, SB112, SB149(MCO)는 Off, SB8, SB9는 제거를 해서 외부클럭을 사용하지 않도록 할 수 있다.
  • LSE : 디폴트로 X2에 32.768KHz의 오실레이터가 달려있고 이 외부 클럭을 사용하도록 되어 있다.
    • X2 오실레이터 사용 : 별다른 커스터마이즈를 하지 않았으면 외부 32.768KHz의 오실레이터 입력이 적용된다.
    • PC14를 통한 외부 오실레이터 사용 : SB144, SB145는 On, R37, R38저항 제거를 해서 PC14를 통한 별도의 LSE를 사용할 수 있다.
    • LSE미사용 : LSE가 필요없다면 SB144, SB145는 On, R37, R38저항 제거를 하면 된다.

 

그리고 STM32는 이들 클럭을 그대로 사용하지는 않으며 중간에 PLL(Phase-Locked Loop)과 Prescaler를 통해 체배, 분주를 한 뒤 각 클럭소스로 사용한다.

 

다음은 STM32F42x/43x의 Clock Tree이다.

[STM32F42x/STM32F43x Clock Tree]

 

2. CubeMX에서 Clock설정

CubeMX에서는 클럭설정이 아래 그림과 같이 GUI형태로 되어 있어 한눈에 확인하고 설정하기가 편하다.

[CubeMX의 Clock Configuration]

우선 디폴트 값으로 설정된 위의 그림을 보자.

제일 왼쪽에 LSE와 HSE의 클럭속도가 파란색으로 나와있다. 이는 외부 X2와 ST-Link MCO의 클럭속도이다. 물론 외부에 별도 클럭을 붙여서 사용한다면 값을 바꿀 수 있다.

그 다음으로 각각의 Mux(Multiflexer)를 통해 내외부 클럭을 선택할 수 있도록 되어 있다.

RTC Clock Mux의 경우 Disable되어 있어 선택할 수 없도록 되어 있는데 이는 Pinout & Configuration의 Timers-RTC에서 Active Clock Source에 체크를 해 RTC를 사용한도록 설정해야 Enable된다.

오른쪽 하단의 I2S, SAI등의 다른 Mux도 마찬가지로 해당 항목의 사용여부를 설정해야 선택 가능해진다.

[RTC 사용여부 설정]

 

SYSCLK의 경우 HSE 신호를 Main PLL을 거쳐 168MHz로 만든 신호를 사용하게 되어 있고 이 신호가 다시 Ethernet, FCLK, APB등의 신호로 들어간다.

 

System Clock Mux에서는 HSI, HSE를 그대로 사용하거나 Main PLL을 거친 클럭을 선택할 수 있다.

그리고 아래에 "Enable CSS"라는 버튼이 있는데 이건 Clock security system(CSS)의 사용여부를 선택하는 버튼이다.

STM32는 HSE가 작동을 멈추거나 이상동작을 할 경우 이를 감지할 수 있는 회로가 있으며 이때 시스템은 Advanced-control 타이머인 TIM1, TIM8을 통해 인터럽트를 전달한다. 이 인터럽트는 CSSI(Clock system system interrupt)라고 하며 NMI(non-maskable interrupt)에 연결되어 있다.

 

각 Peripheral들은 각각 AHB, APB 버스에 연결되어 있는데 AHB의 경우 System Clock(HCLK)을 그대로 사용하며 APB의 경우 CubeMX그림의 제일 오른쪽 설정과 같이 각각 설정된 값을 사용하게 된다.

 

클럭속도가 중요한 역할을 하는 타이머 등의 장치를 사용한다면 아래 그림 Datasheet의 Block Diagram을 참조해서 해당 장치가 어느 클럭에 연결되어 있는지 확인하는 작업이 필요하다.

[STM32F427xx/STM32F429xx Block Diagram]

가령 TIM9의 경우 APB2에 연결되어 있으므로 Clock Configuration에서 APB2 Timer Clock부분의 클럭속도를 참조해야 하고 TIM2의 경우 APB1에 연결되어 있으므로 APB1 Timer Clock부분의 클럭속도를 참조해야 한다.

 

참고로 CubeMX의 Clock Configuration에 있는 숫자들은 체배/분주를 통해 이 값을 변경할 수 있지만 직접 입력도 가능하다. 이 경우 CubeMX가 그 값에 맞는 체배/분주를 찾는 작업을 자동으로 수행해 준다.

내부 로직은 잘 모르겠지만 동작방식으로 봐서는 어떤 수학적 알고리즘에 의해 찾는게 아니라 지정된 체배/분주를 일일이 루프돌면서 그에 맞는 값을 찾아 나가는거 같다. 

따라서 속도가 느리며 설정할 수 없는 값을 입력한 경우 한참 찾다가 못찾는다는 메시지를 출력한다.

 

CubeMX에서 Clock설정을 마치고 저장하면 소스의 SystemClock_Config()함수에 이 값들이 적용된 클럭설정 소스를 만들어 준다.

 

 

3. System Clock설정을 위한 Main Loop속도 측정

퍼포먼스가 중요한 애플리케이션에서는 지원되는 클럭 범위내에서 가장 빠른 속도를 설정하는것이 유리하다. 하지만 퍼포먼스보다 전력소모에 중점을 둔다면 클럭속도를 줄여야 할 필요가 있다.

이런 경우 퍼포먼스와 전력소모 사이에서 적절한 클럭속도를 찾는 작업이 중요해진다.

 

가장 손쉽게 측정하는 방법은 해당 애플리케이션이 문제없이 구동되기 위해 필요한 main함수안의 메인 while문 1회 루프의 최저 시간을 산출해 보는것이다.

 

간단하게 SysTick을 사용하는 방법도 있으나 SysTick은 인터럽트로 구동되고 HAL_IncTick()함수 호출에서 전역 uwTick을 증가시키는 로직등이 들어가므로 자체적으로 이를 수행하기 위한 시간이 필요하다.

따라서 좀더 정확히 측정하기 위해서는 DWT(Data watchpoint trigger)를 활용하는 방법이 있다.

DWT는 STM32F4의 레퍼런스 매뉴얼 1702p에 설명은 되어 있으나 레지스터에 대한 설명은 찾지 못했다. 하지만 ARM 레퍼런스 문서에서 해당 레지스터 내용을 찾을 수 있었다.

 

이 문서에 보면 DWT_CYCCNT라는 레지스터가 있는데 프로세서의 클럭주기를 카운트하는 자유실행카운터이다. 이 카운터는 인터럽트등의 영향을 받지 않고 독립적으로 수행된다.

단 이 기능을 사용하려면 DEMCR레지스터의 TRCENA비트와 DWT_CTRL의 CYCCNTENA비트를 1로 설정해 주어야 한다.(ARM 레퍼런스 706p, 737p, 741p참조)

 

이 내용들은 Jean Labrose가 작성한 ARM Cortex-M MUCs에서의 코드 실행 시간 계산을 참조하였으므로 자세한 내용은 이 사이트를 참조하기 바란다.

 

이 사이트의 내용대로 간단하게 작성해 보자면

#define  ARM_CM_DEMCR      (*(uint32_t *)0xE000EDFC)
#define  ARM_CM_DWT_CTRL   (*(uint32_t *)0xE0001000)
#define  ARM_CM_DWT_CYCCNT (*(uint32_t *)0xE0001004)

int main(void)
{
  uint32_t  start;
  uint32_t  delta;

  if (ARM_CM_DWT_CTRL != 0) {        // See if DWT is available
      ARM_CM_DEMCR      |= 1 << 24;  // Set bit 24
      ARM_CM_DWT_CYCCNT  = 0;
      ARM_CM_DWT_CTRL   |= 1 << 0;   // Set bit 0
  }
  
  
  while (1)
  {  
	  start = ARM_CM_DWT_CYCCNT;

	  // ... 실제 실행 코드

	  delta = ARM_CM_DWT_CYCCNT - start;
	  printf("delta : %ld\n", delta);
  }
}

 

이와 같이 구현할 수 있으며 delta는 실제 MCU가 사용한 클럭수이다. 물론 내부 로직상에 조건문이나 반복문이 상황에 따라 달라지거나 중간에 인터럽트가 걸리는 등의 상황에서는 루프를 돌 때마다 값이 달라질 수 있으나 위에 소개한 사이트에서 Peak값을 산출하는 예제도 소개하고 있으므로 관심이 있다면 한번 훑어보기 바란다.

 

delta값은 소요된 클럭수이므로 이를 시간으로 환산하려면 System클럭수를 시간으로 산출해서 이 값을 곱하면 소요시간을 산출할 수 있다.

예를들어 delta값이 1234이고 System클럭이 168MHz라고 했을 때

(1초 / 168000000Hz) * 1234 = 0.0000073452380952381초, 즉 7.35㎲가 된다.

 

 

4. 마무리

이번장에서는 STM32의 클럭과 클럭의 설정에 대해 알아보았다.

타이머나 외부 장치와 타이밍을 맞춰야 하는 상황에서는 이 클럭 설정이 매우 중요하며 전력소모가 문제가 되는 경우에도 클럭설정은 매우 중요하다.

클럭설정에 대한 레지스터 설명은 의도적으로 하지 않았으나 필요한 경우 SystemClock_Config() 함수를 분석해 보면 될 것이다.

그외 여기에서 언급하지 않은 내용을 찾아 더 연구해 보자.

 

 

'임베디드 > STM32' 카테고리의 다른 글

20. [STM32] Timer - Output Compare  (0) 2025.01.06
19. [STM32] Timer의 기초  (0) 2024.11.19
17. [STM32] Power - PVD  (0) 2024.11.08
16. [STM32] Power - Backup Domain Access  (0) 2024.11.07
15. [STM32] Power - Low Power Mode  (0) 2024.11.04