본문 바로가기

stm32 레지스터 직접 접근 (3. RCC)

반응형

관련 글


잡동사니 세상 :: stm32 레지스터 직접 접근 (소개) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (0. Microcontroller와 ARM ) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (1. STM32F10x란) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (2. 프로그램 설치 및 설정) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (4. GPIO [Output]) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (4. GPIO [Input]) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (5. Exception / Interrupt [설명 & 코드 Part 01]) (tistory.com)

잡동사니 세상 :: stm32 레지스터 직접 접근 (5. Exception / Interrupt [인터럽트 설정 Part 02]) (tistory.com)

stm32 레지스터 직접 접근 (5. Exception / Interrupt [중요 레지스터들 Part 03]) (tistory.com)


서론


STM32를 사용할 때 복잡한 요소 중 하나는 클럭과 관련된 것이라고 생각됩니다. STM32의 기능을 사용하기 위해선 반드시 클럭을 건들여야하죠. 예를 들어 간단한 GPIO를 제어할 때도 GPIO의 Clock을 Enable시켜야하는 것만 봐도 알 수 있습니다.

여기서 클럭이란 STM32의 모든 장치를 움직이게 하는 타이밍을 제공한다고 생각하시면 됩니다. 예를 들어 명령어들은 이 클럭 신호에 맞춰 실행되게 됩니다. 또한 GPIO등도 클럭 신호에 맞춰 동작하게 됩니다.

이번 포스트에서는 RCC란 무엇이며, RCC와 관련된 레지스터를 직접 다뤄 클럭을 설정하는 과정을 알아볼 예정입니다.

 


RCC

Registers

  Register 관련 (.h) 파일 만들기

  RCC_CFGR

  RCC_CR

Programming

  rcc.h


 

RCC


Reset Clock Controller 즉 RCC는 STM32의 리셋과 클럭을 담당하는 장치입니다. 즉 클럭 또는 리셋과 관련된 작업을 해야할 때는 RCC의 도움을 받아야한다는 것이죠.

RCC는 다시 두 부분으로 나눠져 RTCCLK과 Watchdog에 공급되는 2차 클럭(Secondary Clock)과 GPIO, USART, TIM 등과 관련된 AHB, APB에 공급되는 시스템 클럭 (System Clock 또는 SYSCLK)가 됩니다.

여기서 자주 사용하게 될 클럭은 SYSCLK입니다. 주변 장치들의 클럭 신호가 되는 클럭이죠.

 

SYSCLK는 프로그래머가 어떻게 작성하냐에 따라 다음 3가지에 하드웨어적으로 자동으로 연결됩니다.

이름 클럭률 설명
HSI 8 MHz 내부 RC 클럭
HSE 4 ~ 16 MHz 외부 oscilator 클럭
PLLCLK ~ 72 MHz 프로그래머가 HSE 또는 HSI 둘 중 하나를 선택하여 파생된 클럭 
(프로그래머가 설정한 바에 따라 HSE 또는 HSI의 n배의 클럭률을 가짐)

 

Registers


RCC는 클럭을 관장하는 장치라고 했습니다. 그렇다면, 적절히 클럭을 Enable 시키고, 설정하기 위해선 RCC를 설정해야한다는 것이죠. RCC를 설정하는 방법은 RCC와 관련된 레지스터들에 적절한 값을 넣는 것과 동일한 의미입니다.

 

STM32F103ZET6의 RCC에는 다음과 같은 레지스터들이 있습니다.

RCC_CR

RCC_CFGR

RCC_CIR

RCC_APB2RSTR

RCC_APB1RSTR

RCC_AHBENR

RCC_APB2ENR

RCC_APB1ENR

RCC_BDCR

RCC_CSR

와 총 10개나 있습니다. 저 많은 레지스터들을 이번 포스트에서 전부 다룰 것은 아니니 안심하셔도 됩니다.

이번 포스트에서는 RCC_CR (줄여서 CR), RCC_CFGR (CFGR)만 다룰 것이고, 나머지는 필요에 따라 다룰 것입니다.

 

레지스터가 나왔으니 강좌 처음에 올린 Reference Manual의 90쪽부터 적절히 넘기면서 따라오시면 되겠습니다.

이론보다는 기본적인 코드를 먼저 구현한 후 비교하면서 진행하겠습니다.

 

Register 관련 (.h) 파일 만들기

IAR Embedded Workbench를 실행시킨 후, 저번에 만든 Project01이 왼쪽 창에 있는지 확인해줍니다.

그런 다음 저번에 Project01.c를 만들었던 것처럼 rcc.h라는 파일을 생성해 줍니다.

더보기
그림1 
그림2
그림3 

 

 

rcc.h를 생성 후, 추가하셨다면 다음과 같이 작성해주시면 됩니다.

#ifndef _RCC_H
#define _RCC_H

#define RCC_OFFSET      0x40021000

#define RCC_CR          *(unsigned long *)      (RCC_OFFSET + 0x00)
#define RCC_CFGR        *(unsigned long *)      (RCC_OFFSET + 0x04)
#define RCC_CIR         *(unsigned long *)      (RCC_OFFSET + 0x08)
#define RCC_APB2RSTR    *(unsigned long *)      (RCC_OFFSET + 0x0C)
#define RCC_APB1RSTR    *(unsigned long *)      (RCC_OFFSET + 0x10)
#define RCC_AHBENR      *(unsigned long *)      (RCC_OFFSET + 0x14)
#define RCC_APB2ENR     *(unsigned long *)      (RCC_OFFSET + 0x18)
#define RCC_APB1ENR     *(unsigned long *)      (RCC_OFFSET + 0x1C)
#define RCC_BDCR        *(unsigned long *)      (RCC_OFFSET + 0x20)
#define RCC_CSR         *(unsigned long *)      (RCC_OFFSET + 0x24)

#endif

각각의 0x40021000 등의 숫자가 무엇을 의미하는지는 조금 있다 알아보도록 하겠습니다.

 

 

RCC_CFGR

순서상 RCC_CR이 우선이지만, RCC_CFGR을 먼저 설정해야하기 때문에 먼저 설명하도록 하겠습니다.

STM32는 32 bits 기반이기 때문에 모든 레지스터의 크기가 32 bits입니다. 따라서 RCC_CFGR도 32 bits의 크기이죠.

다음은 RCC_CFGR의 설명서입니다.

 

그림4 101 page

 

RCC_CFGR의 각 비트들을 어떻게 설정하느냐에 따라 어떤 클럭을 사용하고, 어떤 클럭률을 맞출지를 결정할 수 있습니다.

각 비트들에 대한 설명은 다음과 같습니다. (이런 게 있다라고 생각하시고, 뒤에서 자세하게 설명합니다.)

비트 이름 (위치) 명칭 및 설명 수행
MCO (26 ~ 24) Microcontroller clock output
MCU의 MCO에 연결될 클럭을 설정합니다.

여기서는 MCO핀을 사용하지 않을 것이기 때문에 0으로 설정합니다.
0xx: 클럭 공급x
100: SYSCLK 선택
101: HSI 선택
110: HSE 선택
111: PLL / 2 선택
USBPRE (22) USB prescaler
PLL 클럭률을 그대로 사용할지, 아니할지를 결정합니다.
0: PLL 클럭률에 *2/3을 USB 관련 장치에 공급합니다.
1: PLL 클럭률을 그대로 USB 관련 장치에 공급합니다.
PLLMUL (21 ~ 18) PLL multiplication factor

MCO에의해 결정된 PLL에 해당되는 클럭률을 증가시켜 높은 클럭률을 발생시키도록 합니다. 
0000: x2 배 
0001: x3 
0010: x4
0011: x5 
0100: x6 
0101: x7
0110: x8
0111: x9
1000: x10
1001: x11
1010: x12
1011: x13
1100: x14
1101: x15
1110: x16
1111: x16
PLLXTPRE (17) HSE divider for PLL entry

MCO에 의해 선택된 클럭(이하 HSE라고도 씁니다.)의 클럭률을 그대로 사용할지, / 2를 하여 낮춰 사용할지를 결정합니다.
0: 클럭률 그대로 사용
1: / 2의 클럭률 사용
PLLSRC (16) PLL entry clock source

PLL의 클럭으로 사용될 클럭을 결정하는데 사용됩니다.
0: HSI를 사용하지만, / 2의 클럭률로 사용합니다.
1: HSE을 그대로 사용합니다.
ADCPRE (15 ~ 14) ADC prescaler

ADC 장치에 인가할 클럭률을 결정하는데 사용됩니다.
00: PLCK2 / 2의 클럭률을 ADC에 공급합니다.
01: PLCK2 / 4의 클럭률을 ADC에 공급합니다.
10: PLCK2 / 6의 클럭률을 ADC에 공급합니다.
11: PLCK2 / 8의 클럭률을 ADC에 공급합니다.
PPRE2 (13 ~ 11) APB high-speed prescaler (APB2)

PLCK2에 사용될 클럭률을 결정합니다.
0xx: HCLK의 클럭률을 그대로 사용합니다.
100: HCLK / 2
101: HCLK / 4
110: HCLK / 8
111: HCLK / 16
PRE1 (10 ~ 8) APB low-speed prescaler (APB1)

PCLK1에 사용될 클럭률을 결정합니다.
0xx: HCLK의 클럭률을 그대로 사용합니다.
100: HCLK / 2
101: HCLK / 4
110: HCLK / 8
111: HCLK / 16
HPRE (7 ~ 4) AHB prescaler

HCLK(AHB)에 사용될 클럭률을 결정합니다.
0xxx: SYSCLK의 클럭률을 그대로 사용합니다.
1000: SYSCLK / 2
1001: SYSCLK / 4
1010: SYSCLK / 8
1011: SYSCLK / 16
1100: SYSCLK / 64
1101: SYSCLK / 128
1110: SYSCLK / 256
1111: SYSCLK / 512
SWS (3 ~ 2) System clock switch status

어떤 클럭이 SYSCLK로 사용되었는지를 알려줍니다.
00: HSI
01: HSE
10: PLL
11: not allowed
SW (1 ~ 0) System clock switch

어떤 클럭을 SYSCLK로 사용할지를 결정합니다.
00: HSI
01: HSE
10: PLL
11: not allowed

 

 

STM32의 클럭은 다음과 같은 과정을 거쳐 설정됩니다.

 

 

더보기
그림 5.1 RCC Reference manual 93 page

 

우리는 AHB를 36 MHz로 만들기 위해 위와 같은 과정을 거칠 수 있도록 관련 RCC 레지스터들을 설정을 할 것입니다.

1. 우선 Open103z를 기준으로 HSE에 인가된 8 MHz를 사용하기 위해 MCO를 110으로 설정합니다. (다른 장치가 이걸 대신함)

2. 4 MHz를 얻기 위해 PLLXTPRE을 0으로 설정합니다.

3. 4 MHz인 PLL을 사용하기 위해 PLLSRC를 1로 설정합니다.

4. 4 MHz인 PLL을 9배로 늘리기 위해 PLLMUL을 0111로 설정합니다.

5. 이제 36 MHz인 PLL을 사용하기 위해 SW을 10으로 설정합니다.

6. 36 MHz인 SYSCLK의 클럭률을 그대로 사용하기 위해 HPRE를 0000으로 설정합니다.

7. 나머지 설정은 필요에 따라 바꿔줍니다.

 

1 ~ 7번 과정을 종합하면 다음과 같은 이진수를 얻을 수 있습니다.

(여기서는 다른 장치는 사용하지 않을 것이기 때문에설정 안 한 부분은 0으로 설정합니다.)

RCC_CFGR 

offset : 0x04

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1
  MCO   USBPRE PLLMUL PLLXTPRE PLLSRC
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
ADCPRE PPRE2 PPRE1 HPRE SWS SW

코드로 작성한다면 다음과 같겠습니다.

RCC_CFGR = 0x001D0002; (이진수로 00000000000111010000000000000010)

 

 

RCC_CR

RCC_CFGR이 클럭을 설정하는 레지스터였다면, RCC_CR은 클럭의 끄고 키는 제어를 담당하는 레지스터입니다.

우리가 시계를 처음 샀을 때, 시간을 설정한 후 시계를 작동시키는 것과 같이 STM32도 클럭을 먼저 설정한 후, 클럭을 활성화시켜야합니다. 그래서 RCC_CFGR을 먼저 설정하고, RCC_CR을 나중에 설정하는 것이죠. 실제로 RCC_CFGR은 해당 클럭이 OFF되어 있을 때 설정이 가능하도록 되어 있습니다.

 

RCC_CR의 구조는 다음과 같습니다.

 

그림6 99 page

 

비트 이름 (위치) 명칭 및 설명 수행
PLLRDY (25) PLL clock ready flag

PLL 클럭이 준비 되었는지 아닌지를 알려줍니다.
0: PLL 안 잠겨 있음
1: PLL 잠겨 있음
PLLON (24) PLL enable

PLL 클럭을 사용합니다.
0: PLL OFF
1: PLL ON
CSSON (19) Clock security system enable

Clock detector을 활성화합니다.(사용해 보지 않아서 모르겠습니다.)
0: OFF
1: ON
HSEBYP (18) External high-speed clock bypass 0: not bypassed
1: bypassed with external clpck
HSERDY (17) External high-speed clock ready flag

HSE 클럭이 준비 되어 있는지 알려줍니다.
0: HSE 준비 되어 있음
1: HSE 준비 되어 있음
HSEON (16) HSE lock enable

HSE 클럭을 활성화 시킵니다.
0: OFF
1: ON
HSICAL (7 ~ 0) Internal high-speed clock calibration

자동으로 설정됩니다.
 
HSITRIM (4 ~ 0) Internal high-speed clock trimming

calibration 값에 임의로 값을 추가합니다. (책에서는 16으로 설정 되어 있네요)
 
HSIRDY (1) Internal high-speed clock ready flag

HSI 클럭이 준비 되어 있는지 알려줍니다.
0: OFF
1: ON
HSION (0) Internal high-speed clock enable

HSI 클럭을 활성화 시킵니다.
0: OFF
1: ON

 

 

우리는 HSE, PLL을 사용하니 나머지 기능들을 사용하지 않는 설정은 다음과 같습니다.

다음과 같이 설정하면 됩니다.

RCC_CR

offset: 0x00

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1
  PLLRDY PLLON   CSSON HSEBYP HSERDY HSEON
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
HSICAL HSITRIM   HSIRDY HSION

 

RCC_CR = 0x01010080;

 

 

Programming


이제 위에서 만든 rcc.h파일을 Project01.c에 include한 후, 위에서 본 RCC_CFGR, RCC_CR 레지스터에 값을 넣으면 됩니다.

 

Project01.c

#include "rcc.h"

int main(void) {
	RCC_CFGR	= 0x001D0002;
    RCC_CR		= 0x01010080;
    
    return 1;
}

 

rcc.h

#ifndef _RCC_H
#define _RCC_H

#define RCC_OFFSET      0x40021000

#define RCC_CR          *(unsigned long *)      (RCC_OFFSET + 0x00)
#define RCC_CFGR        *(unsigned long *)      (RCC_OFFSET + 0x04)
#define RCC_CIR         *(unsigned long *)      (RCC_OFFSET + 0x08)
#define RCC_APB2RSTR    *(unsigned long *)      (RCC_OFFSET + 0x0C)
#define RCC_APB1RSTR    *(unsigned long *)      (RCC_OFFSET + 0x10)
#define RCC_AHBENR      *(unsigned long *)      (RCC_OFFSET + 0x14)
#define RCC_APB2ENR     *(unsigned long *)      (RCC_OFFSET + 0x18)
#define RCC_APB1ENR     *(unsigned long *)      (RCC_OFFSET + 0x1C)
#define RCC_BDCR        *(unsigned long *)      (RCC_OFFSET + 0x20)
#define RCC_CSR         *(unsigned long *)      (RCC_OFFSET + 0x24)

#endif

 

 

rcc.h

rcc.h를 보면 앞에서 본 RCC_CR, RCC_CFGR이라는 글자가 보이고, 그 옆에 알기 힘든 것들로 구성 되어 있습니다.

*(unsigned long *)은 주소에 직접 값을 넣기 위한 키워드라고 생각하시면 됩니다. STM32가 32 bits 동작이기 때문에 주소도 32 bits 크기로 되어 있어 unsigned long -> 32 bits로 설정한 것입니다.

 

RCC_CR의 주소는 0x40021000이고, RCC_CFGR은 이보다 4 많은 0x40021004입니다. *(unsigned long *) 오른쪽에 있는 것이 주소를 지정해 준 것인데, *(unsigned long *) 0x4002100이런 식으로 하지 않은 이유는 프로그램을 작성할 때의 편리성을 위한 것입니다.

 

RCC_CR는 RCC_OFFSET + 0x00

RCC_CFGR은 RCC_OFFSET + 0x04로 되어 있습니다. 그리고 RCC_OFFSET은 0x40021000이고요.

여기서 0x00, 0x04는 Address offset이라고 해당 레지스터가 상대적으로 어느 위치에 있는지를 알려줍니다. 그림 4, 6를 보면 RCC_CR의 Address offset은 0x00, RCC_CFGR은 Address offset이 0x04로 되어 있습니다.

여기서 상대적 위치를 나타낸다고 했는데, 그러면 절대적인 위치도 있겠죠? RCC_CR의 절대적인 위치는 0x40021000이고, RCC_CFGR은 0x40021004입니다. 다시 표현하면 RCC_CR은 0x40021000 + 0, RCC_CFGR은 0x40021000 + 4로 표현할 수도 있죠.

즉 여기서 Address offset은 0x40021000으로 부터 해당 레지스터가 얼만큼 떨어져 있는지를 알려줍니다.

RCC_CR의 Address offset은 0x00이기 때문에 RCC_CR의 절대 위치는 0x40021000 + 0x00이 되는 것이고, RCC_CFGR은 0x04이기 때문에 0x40021000 + 0x04로 계산 되는 것입니다. 기준치가 되는 0x40021000은 RCC의 offset라고 부릅니다.

이제 rcc.h가 되 그런 식으로 작성 되었는지를 알 수 있을 것입니다.

 

 

RCC의 offset 값을 Reference Manual의 50쪽 표의 위에서 9번째에 나와 있습니다.

 

그림 7 50 page

 

 

 

 

그 외


 본문에서는 RCC 설정을 통해 최대 주파수 72MHz가 아닌, 그보다 낮은 주파수를 설정했다. 그 이유는 이 포스트를 작성할 당시, 72MHz로 설정할 때마다 HardFault Exception이 발생했기 때문이었다. 동작도 안 되는 코드를 올리는 것은 위험 부담이 컸기 때문에 해당 설정으로 올리지 않았던 것이었다. 하지만 July.4에 해당 문제의 원인으로 생각되는 부분을 HAL 라이브러리에서 찾았으며, 해결까지 완료한 상태이다. 해당 글은 아래 URL에서 확인 가능하다.

STM32F103ZET 최대 클럭 속도 관련 문제 및 해결 (tistory.com)

 

STM32F103ZET 최대 클럭 속도 관련 문제 및 해결

문제  STM32F103ZET를 다루면서 RCC 설정 시, STM32F103ZET의 최대 클럭인 72MHz로 설정할 때마다 HardFault Exception 즉, 컴퓨터로 치면 블루스크린과 같은 상황이 계속 발생되었다. RCC 설정의 문제인가? 아니.

pkr7098.tistory.com

 

 

 

 

 

 

 

 

반응형