ComputerScience & Embedded/NUCLEO & CAN Tranceiver
PLL Programming
leecrossun
2025. 3. 1. 15:46
Introduction of PLL
PLL을 사용하면 마이크로 프로세서의 최대치 (180MHz) 까지 시스템 클럭 증가
이론적으로는 400MHz 이상도 가능하지만 PLL 프리스케일러로 출력 제한
- PLL의 입력 소스
- HSE또는 HSI 를 입력으로 사용
- 력 신호가 바로 VCO(전압 제어 오실레이터, Voltage-Controlled Oscillator)로 전달되지 않고,먼저 M 분주기(PLL M Divider) 를 통과
- VCO(Voltage-Controlled Oscillator) 역할
- VCO는 PLL 엔진의 핵심 부품으로, 주파수 합성(Frequency Synthesizer) 역할
- M 분주기(PLL M)를 통해 입력된 클럭이 VCO의 입력 클럭(f_vco input clock)
- VCO 내부에서 설정된 배수 값(PLL N Multiplier)을 적용하여 고주파 출력 클럭을 생성
- 출력 클럭 조정
- VCO에서 생성된 출력 클럭은 매우 높은 주파수를 가지므로,이를 다시 P 분주기(PLL P Divider) 를 거쳐 원하는 시스템 클럭(SYSCLK)으로 변환
- PLLCLK(PLL 출력 클럭) 을 SYSCLK으로 사용
PLL 설정 규칙
VCO 입력 클럭 제한
- VCO 입력 클럭은 1MHz ~ 2MHz 범위 내
- 예를 들어, HSE가 8MHz일 경우:
- M 값이 8이면: 8MHz / 8 = 1MHz → 허용됨 ✅
- M 값이 4이면: 8MHz / 4 = 2MHz → 허용됨 ✅
- 이 규칙을 준수해야 PLL이 정상적으로 동작
VCO 출력 클럭 제한
- VCO 출력 클럭은 100MHz 이상, 432MHz 이하
- 따라서, PLL N 배수를 설정할 때 이 범위를 초과하지 않도록 주의
PLL 출력 클럭 계산 공식
- PLLM : 입력 클럭 분주기 (M Divider)
- PLLN : VCO 배수 값 (N Multiplier)
- f_VCO : VCO 출력 클럭 (100MHz ~ 432MHz)
최종적으로 시스템 클럭(SYSCLK)을 얻기 위해 P 분주기(PLLP) 적용
PLL Configuration - Oscillator initialization
- PLLQ(USB OTG FS, SDIO CLK), PLLR(I2S, SAI 등) 은 사용하지 않으므로 기본값 2로 냅둠
- 주의할 점 :
- PLL 엔진의 입력 클럭 주파수는 1MHz ~ 2MHz 범위
- PLLN은 50이상 432이하 (레퍼런스 메뉴얼)
- 설정값 예 :
- 50MHz: PLLM=16, PLLN=100, PLLP=2 (예시 그림 참조)
- 84MHz: PLLM=16, PLLN=168, PLLP=2
- 120MHz: PLLM=16, PLLN=240, PLLP=2
PLL Configuration - Clock Initialization
- 클럭 초기화
- HCLK, APB1, APB2의 분배기를 설정하여 원하는 주파수에 맞게 시스템 클럭 설정
- 50MHz의 경우 APB1과 APB2는 2로 설정
- 플래시 대기 시간 설정:
- HCLK가 50MHz일 경우 플래시 대기 시간은 2, 84MHz일 경우 2, 120MHz일 경우 3
- Systick 구성:
- HCLK 주파수에 맞춰 Systick을 설정하여 1ms레이턴시 설정
// main_app.c
void SystemClock_Config(uint8_t clock_freq)
{
RCC_OscInitTypeDef osc_init;
RCC_ClkInitTypeDef clk_init;
uint32_t FLatency = 0;
osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSI;
osc_init.HSIState = RCC_HSI_ON;
osc_init.HSICalibrationValue = 16;
osc_init.PLL.PLLState = RCC_PLL_ON;
osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSI;
switch(clock_freq){
case SYS_CLOCK_FREQ_50_MHZ:
osc_init.PLL.PLLM = 16;
osc_init.PLL.PLLN = 100;
osc_init.PLL.PLLP = 2;
osc_init.PLL.PLLQ = 2;
osc_init.PLL.PLLR = 2;
clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
clk_init.APB2CLKDivider = RCC_HCLK_DIV2;
FLatency = FLASH_ACR_LATENCY_1WS;
break;
case SYS_CLOCK_FREQ_84_MHZ:
osc_init.PLL.PLLM = 16;
osc_init.PLL.PLLN = 168;
osc_init.PLL.PLLP = 2;
osc_init.PLL.PLLQ = 2;
osc_init.PLL.PLLR = 2;
clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
clk_init.APB2CLKDivider = RCC_HCLK_DIV2;
FLatency = FLASH_ACR_LATENCY_2WS;
break;
case SYS_CLOCK_FREQ_120_MHZ:
osc_init.PLL.PLLM = 16;
osc_init.PLL.PLLN = 240;
osc_init.PLL.PLLP = 2;
osc_init.PLL.PLLQ = 2;
osc_init.PLL.PLLR = 2;
clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk_init.APB1CLKDivider = RCC_HCLK_DIV4;
clk_init.APB2CLKDivider = RCC_HCLK_DIV2;
FLatency = FLASH_ACR_LATENCY_3WS;
break;
default:
return;
}
if(HAL_RCC_OscConfig(&osc_init) != HAL_OK) Error_handler();
if(HAL_RCC_ClockConfig(&clk_init, FLatency) != HAL_OK) Error_handler();
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
}
MAXIMUM 180MHz Configuration
- HCLK를 180MHz에서 실행하려면 voltage regulators over-drive mode 를 켜야 함. 그렇지 않으면 AHB CLK이 180MHz에 도달하지 않음. 그리고 voltage scale이 1이어야 함
- 전원 컨트롤러의 CR 이라는 레지스터를 통해 이를 설정할 수 있음
- ODEN : over-drive switching enabled
- VOS : voltage scale
case SYS_CLOCK_FREQ_180_MHZ:
__HAL_RCC_PWR_CLK_ENABLE(); // enable the clock for the power controller
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); // set regulator voltage scale as 1
__HAL_PWR_OVERDRIVE_ENABLE(); // turn on the oer drive mode of the voltage regulator
osc_init.PLL.PLLM = 16;
osc_init.PLL.PLLN = 360;
osc_init.PLL.PLLP = 2;
osc_init.PLL.PLLQ = 2;
osc_init.PLL.PLLR = 2;
clk_init.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk_init.APB1CLKDivider = RCC_HCLK_DIV4;
clk_init.APB2CLKDivider = RCC_HCLK_DIV2;
FLatency = FLASH_ACR_LATENCY_5WS;
break;
실행 결과
반응형