hal::clock

Clock Configuration - PLL & System Clock Setup

~410 satır ~22 function STM32/GD32

Overview

Clock modülü, mikrodenetleyicinin kalp atışıdır. HSI/HSE/PLL kaynaklarını structlandırır, sistem clockunu ayarlar ve peripheral clocklarını dağıtır. Doğru clock structlandırması sistemin performansını, güç tüketimini ve timing accuracy'sini truedan etkiler.

Key Features

Quick Start

import hal::clock

// HSE + PLL -> 72 MHz (STM32F1)
clock.init(do
    source: clock.SOURCE_PLL,
    hse_freq: 8_000_000,  // 8 MHz crystal
    pll_mul: 9,           // 8 * 9 = 72 MHz
    ahb_div: 1,           // HCLK = 72 MHz
    apb1_div: 2,          // PCLK1 = 36 MHz (max 36 MHz)
    apb2_div: 1           // PCLK2 = 72 MHz
end)

// Verify clock
let sysclk = clock.get_sysclk_freq()
io.yazdir_satır("SYSCLK: " + sysclk.metne() + " Hz")

Types and Enums'lar

// Clock Sources
enum ClockSource {
    HSI,        // High-Speed Internal (16 MHz)
    HSE,        // High-Speed External (4-25 MHz crystal)
    PLL,        // Phase-Locked Loop (multiplied clock)
    LSI,        // Low-Speed Internal (32 kHz, RTC)
    LSE         // Low-Speed External (32.768 kHz, RTC)
}

// PLL Source
enum PLLSource {
    PLL_HSI,    // HSI as PLL input
    PLL_HSE     // HSE as PLL input
}

// AHB Prescaler
enum AHBPrescaler {
    DIV_1, DIV_2, DIV_4, DIV_8, DIV_16,
    DIV_64, DIV_128, DIV_256, DIV_512
}

// APB Prescaler
enum APBPrescaler {
    DIV_1, DIV_2, DIV_4, DIV_8, DIV_16
}

struct ClockConfig do
    source: ClockSource,
    hse_freq: int = 8_000_000,
    pll_source: PLLSource = PLL_HSE,
    pll_mul: int = 9,      // STM32F1: 2-16
    pll_m: int = 8,        // STM32F4: input divider
    pll_n: int = 336,      // STM32F4: multiplier
    pll_p: int = 2,        // STM32F4: system clock divider
    pll_q: int = 7,        // STM32F4: USB/SDIO divider
    ahb_prescaler: AHBPrescaler = DIV_1,
    apb1_prescaler: APBPrescaler = DIV_2,
    apb2_prescaler: APBPrescaler = DIV_1,
    css_enable: bool = true,  // Clock Security System
    flash_latency: int = 2      // Wait states
end

Example 1: STM32F1 - 72 MHz Maximum Speed

Problem: STM32F103 for maksimum performans (72 MHz)

import hal::clock, hal::flash

function clock_72mhz_init() do
    // Enable HSE (8 MHz external crystal)
    clock.hse_enable()
    
    // Wait for HSE ready
    if değil clock.hse_wait_ready(1000) do
        io.yazdir_satır("HSE failed to start!")
        return
    end
    
    // Configure Flash latency (2 wait states for 72 MHz)
    flash.set_latency(flash.LATENCY_2)
    
    // Configure PLL: HSE * 9 = 8 MHz * 9 = 72 MHz
    clock.pll_config(do
        source: clock.PLL_HSE,
        mul: 9
    end)
    
    // Enable PLL
    clock.pll_enable()
    clock.pll_wait_ready(1000)
    
    // Configure bus prescalers
    clock.set_ahb_prescaler(clock.AHB_DIV_1)   // 72 MHz
    clock.set_apb1_prescaler(clock.APB_DIV_2)  // 36 MHz (max!)
    clock.set_apb2_prescaler(clock.APB_DIV_1)  // 72 MHz
    
    // Switch to PLL as system clock
    clock.set_sysclk_source(clock.SOURCE_PLL)
    
    // Wait for switch
    loop do
        if clock.get_sysclk_source() == clock.SOURCE_PLL do
            break
        end
    end
    
    // Update SystemCoreClock variable
    clock.system_core_clock_update()
    
    io.yazdir_satır("Clock configured successfully!")
    io.yazdir_satır("SYSCLK: " + clock.get_sysclk_freq().metne() + " Hz")
    io.yazdir_satır("HCLK: " + clock.get_hclk_freq().metne() + " Hz")
    io.yazdir_satır("PCLK1: " + clock.get_pclk1_freq().metne() + " Hz")
    io.yazdir_satır("PCLK2: " + clock.get_pclk2_freq().metne() + " Hz")
end

Çıktı: SYSCLK: 72000000 Hz, HCLK: 72000000 Hz, PCLK1: 36000000 Hz, PCLK2: 72000000 Hz

Example 2: STM32F4 - 168 MHz with USB Support

Problem: STM32F407 for 168 MHz + 48 MHz USB clock

import hal::clock, hal::flash, hal::power

function clock_168mhz_usb_init() do
    // Enable power interface clock
    clock.periph_clock_enable(clock.PERIPH_PWR)
    
    // Voltage scaling for max frequency
    power.set_voltage_scaling(power.SCALE_1)
    
    // Enable HSE (8 MHz)
    clock.hse_enable()
    clock.hse_wait_ready(1000)
    
    // Flash latency (5 wait states for 168 MHz @ 3.3V)
    flash.set_latency(flash.LATENCY_5)
    flash.prefetch_enable()
    flash.instruction_cache_enable()
    flash.data_cache_enable()
    
    // PLL configuration:
    // VCO_IN = HSE / PLLM = 8 MHz / 8 = 1 MHz
    // VCO_OUT = VCO_IN * PLLN = 1 MHz * 336 = 336 MHz
    // SYSCLK = VCO_OUT / PLLP = 336 MHz / 2 = 168 MHz
    // USB_CLK = VCO_OUT / PLLQ = 336 MHz / 7 = 48 MHz
    clock.pll_config(do
        source: clock.PLL_HSE,
        pllm: 8,   // Input divider
        plln: 336, // Multiplier
        pllp: 2,   // System clock divider
        pllq: 7    // USB clock divider
    end)
    
    clock.pll_enable()
    clock.pll_wait_ready(1000)
    
    // Bus prescalers
    clock.set_ahb_prescaler(clock.AHB_DIV_1)   // 168 MHz
    clock.set_apb1_prescaler(clock.APB_DIV_4)  // 42 MHz (max 42 MHz!)
    clock.set_apb2_prescaler(clock.APB_DIV_2)  // 84 MHz (max 84 MHz!)
    
    // Switch to PLL
    clock.set_sysclk_source(clock.SOURCE_PLL)
    loop do
        if clock.get_sysclk_source() == clock.SOURCE_PLL do
            break
        end
    end
    
    clock.system_core_clock_update()
    
    // Verify USB clock
    let usb_clk = clock.get_usb_freq()
    io.yazdir_satır("USB Clock: " + usb_clk.metne() + " Hz")
    
    if usb_clk != 48_000_000 do
        io.yazdir_satır("WARNING: USB clock is not 48 MHz!")
    end
end

Result: 168 MHz sistem clocku + 48 MHz USB clock. Maksimum performans.

Example 3: Clock Security System (CSS)

Problem: HSE crystal failure durumunda otomatik HSI'ye geçiş

import hal::clock, hal::nvic

let hse_failed: bool = false

function clock_css_init() do
    // Normal clock setup with HSE
    clock.hse_enable()
    clock.hse_wait_ready(1000)
    
    clock.pll_config(do
        source: clock.PLL_HSE,
        mul: 9
    end)
    clock.pll_enable()
    clock.pll_wait_ready(1000)
    
    // Enable Clock Security System
    clock.css_enable()
    
    // Enable NMI interrupt for CSS
    nvic.enable_irq(nvic.RCC_IRQn, do priority: 0 end)
    
    clock.set_sysclk_source(clock.SOURCE_PLL)
    
    io.yazdir_satır("CSS enabled, monitoring HSE...")
end

// CSS failure interrupt handler
function RCC_IRQHandler() do
    if clock.get_flag(clock.FLAG_CSS) do
        io.yazdir_satır("CSS INTERRUPT: HSE FAILURE DETECTED!")
        
        hse_failed = true
        
        // System automatically switched to HSI
        // Reconfigure PLL with HSI
        clock.pll_disable()
        
        clock.pll_config(do
            source: clock.PLL_HSI,
            mul: 16  // HSI/2 * 16 = 8 MHz * 8 = 64 MHz
        end)
        
        clock.pll_enable()
        clock.pll_wait_ready(1000)
        
        // Clear CSS flag
        clock.clear_flag(clock.FLAG_CSS)
        
        io.yazdir_satır("Switched to HSI-based PLL (64 MHz)")
    end
end

function ana() do
    clock_css_init()
    
    loop do
        if hse_failed do
            io.yazdir_satır("Running on backup HSI clock")
            // Reduce performance or enter safe mode
        end
        
        // Normal operation
        delay_ms(1000)
    end
end

Güvenlik: HSE arızasında sistem donmaz, otomatik HSI'ye geçer.

Example 4: MCO (Master Clock Output) for Debugging

Problem: Oscilloscope ile clock sinyalini gözlemlemek

import hal::clock, hal::gpio

function mco_debug_init() do
    // MCO pin: PA8 (STM32F4)
    gpio.pin_init(gpio.PORT_A, 8, do
        mode: gpio.MODE_AF,
        af: gpio.AF0_MCO,
        speed: gpio.SPEED_VERY_HIGH
    end)
    
    // Output SYSCLK / 4 to MCO
    // (168 MHz / 4 = 42 MHz on PA8)
    clock.mco1_config(do
        source: clock.MCO_SYSCLK,
        prescaler: clock.MCO_DIV_4
    end)
    
    io.yazdir_satır("MCO output enabled on PA8")
    io.yazdir_satır("Expected frequency: " + 
                    (clock.get_sysclk_freq() / 4).metne() + " Hz")
end

// Alternative: Output PLL clock for verification
function mco_pll_check() do
    gpio.pin_init(gpio.PORT_A, 8, do
        mode: gpio.MODE_AF, af: gpio.AF0_MCO
    end)
    
    // Output PLL / 2
    clock.mco1_config(do
        source: clock.MCO_PLL,
        prescaler: clock.MCO_DIV_2
    end)
    
    io.yazdir_satır("PLL clock on PA8 (use oscilloscope)")
end

Debug: Oscilloscope ile gerçek clock frekansını truelayın. PLL lock problemlerini tespit edin.

API Reference

Clock Source Control

// HSE control
function hse_enable()
function hse_disable()
function hse_wait_ready(timeout_ms: int) -> bool

// HSI control
function hsi_enable()
function hsi_disable()
function hsi_calibration_set(value: int)

// PLL control
function pll_config(config: PLLConfig)
function pll_enable()
function pll_disable()
function pll_wait_ready(timeout_ms: int) -> bool

// System clock
function set_sysclk_source(source: ClockSource)
function get_sysclk_source() -> ClockSource
function get_sysclk_freq() -> int

// Bus clocks
function set_ahb_prescaler(div: AHBPrescaler)
function set_apb1_prescaler(div: APBPrescaler)
function set_apb2_prescaler(div: APBPrescaler)
function get_hclk_freq() -> int
function get_pclk1_freq() -> int
function get_pclk2_freq() -> int

// Peripheral clocks
function periph_clock_enable(periph: Peripheral)
function periph_clock_disable(periph: Peripheral)

// CSS and MCO
function css_enable()
function css_disable()
function mco1_config(source: MCOSource, div: MCODiv)

// Utilities
function system_core_clock_update()
function get_flag(flag: ClockFlag) -> bool
function clear_flag(flag: ClockFlag)
Important Notes:
  • Flash Latency: High frequency for wait state gerekli (168 MHz -> 5 WS)
  • APB1 Max: STM32F1 36 MHz, F4 42 MHz, F7 54 MHz
  • USB Clock: Tam 48 MHz olmalı (tolerance 0.25%)
  • PLL Lock Time: ~200 μs, timeout kullanın

Platform Support

Platform Max SYSCLK HSE Range PLL Multiplier
STM32F1 72 MHz 4-16 MHz 2-16x
STM32F4 168 MHz 4-26 MHz PLLM/N/P/Q
STM32F7 216 MHz 4-26 MHz PLLM/N/P/Q
STM32H7 480 MHz 4-48 MHz PLLM/N/P/Q/R
GD32VF103 108 MHz 4-25 MHz 2-32x

Best Practices

Related Modules

HAL Modules | Turkish