|
1 | | -pub const Clock = struct { |
2 | | - sys_clk: u32, |
3 | | - ahb: u32, |
4 | | - apb1: u32, |
5 | | - apb2: u32, |
| 1 | +const microzig = @import("microzig"); |
| 2 | +const RCC = microzig.chip.peripherals.RCC; |
| 3 | +const GPIOF = microzig.chip.peripherals.GPIOF; |
| 4 | +const FLASH = microzig.chip.peripherals.FLASH; |
| 5 | +const PREDIV = microzig.chip.types.peripherals.rcc_f3v1.PREDIV; |
| 6 | +const PLLMUL = microzig.chip.types.peripherals.rcc_f3v1.PLLMUL; |
| 7 | + |
| 8 | +pub const ClockName = enum { |
| 9 | + HSE, |
| 10 | + HSI, |
| 11 | + PLLCLK, |
| 12 | + SYSCLK, |
| 13 | + |
| 14 | + fn is_for_pll(self: @This()) bool { |
| 15 | + return self == .HSE or self == .HSI; |
| 16 | + } |
| 17 | + |
| 18 | + fn is_for_sysclk(self: @This()) bool { |
| 19 | + return self != .SYSCLK; |
| 20 | + } |
| 21 | +}; |
| 22 | + |
| 23 | +pub const RccErrorConfig = error{ |
| 24 | + WrongClockSource, |
| 25 | + SourceClockNotInitialized, |
| 26 | + OutputPllTooHigh, |
| 27 | + PllMustBeEnableFirst, |
6 | 28 | }; |
7 | 29 |
|
8 | | -pub var current_clock: Clock = .{ |
9 | | - .sys_clk = 8_000_000, |
10 | | - .ahb = 8_000_000, |
11 | | - .apb1 = 8_000_000, |
12 | | - .apb2 = 8_000_000, |
| 30 | +pub const Clock = struct { |
| 31 | + sys_clk: u32 = 8_000_000, |
| 32 | + h_clk: u32 = 8_000_000, |
| 33 | + p1_clk: u32 = 8_000_000, |
| 34 | + p2_clk: u32 = 8_000_000, |
| 35 | + hse: u32 = 0, |
| 36 | + hsi: u32 = 8_000_000, |
| 37 | + pllout: u32 = 0, |
| 38 | + usart1_clk: u32 = 8_000_000, |
13 | 39 | }; |
| 40 | + |
| 41 | +pub var current_clock: Clock = .{}; |
| 42 | + |
| 43 | +pub fn enable_pll(comptime source: ClockName, div: PREDIV, mul: PLLMUL) RccErrorConfig!void { |
| 44 | + if (!source.is_for_pll()) { |
| 45 | + return RccErrorConfig.WrongClockSource; |
| 46 | + } |
| 47 | + |
| 48 | + if (source == .HSE and current_clock.hse == 0) { |
| 49 | + return RccErrorConfig.SourceClockNotInitialized; |
| 50 | + } |
| 51 | + |
| 52 | + const inputClock = if (source == .HSE) current_clock.hse else (current_clock.hsi >> 1); |
| 53 | + |
| 54 | + const inputDiv = @intFromEnum(div) + 1; |
| 55 | + const outputMul = @intFromEnum(mul) + 2; |
| 56 | + |
| 57 | + const expectedPllOut = @divTrunc(inputClock, inputDiv) * outputMul; |
| 58 | + if (expectedPllOut > 72_000_000) { |
| 59 | + return RccErrorConfig.OutputPllTooHigh; |
| 60 | + } |
| 61 | + |
| 62 | + RCC.CFGR.modify(.{ .PLLSRC = comptime if (source == .HSE) .HSE_Div_PREDIV else .HSI_Div2, .PLLMUL = mul }); |
| 63 | + RCC.CR.modify(.{ .PLLON = 1 }); |
| 64 | + |
| 65 | + while (RCC.CR.read().PLLRDY != 1) { |
| 66 | + asm volatile ("" ::: .{ .memory = true }); |
| 67 | + } |
| 68 | + |
| 69 | + current_clock.pllout = expectedPllOut; |
| 70 | +} |
| 71 | + |
| 72 | +pub fn enable_hse(speed: u32) void { |
| 73 | + RCC.CR.modify(.{ .HSEON = 1, .HSEBYP = 1 }); |
| 74 | + |
| 75 | + while (RCC.CR.read().HSERDY != 1) { |
| 76 | + asm volatile ("" ::: .{ .memory = true }); |
| 77 | + } |
| 78 | + current_clock.hse = speed; |
| 79 | +} |
| 80 | + |
| 81 | +pub fn select_pll_for_sysclk() RccErrorConfig!void { |
| 82 | + if (current_clock.pllout == 0) { |
| 83 | + return RccErrorConfig.PllMustBeEnableFirst; |
| 84 | + } |
| 85 | + // Maximum APB low speed domain is 36Nhz, let's divide by 2 |
| 86 | + if (current_clock.pllout > 36_000_000) { |
| 87 | + RCC.CFGR.modify(.{ .PPRE1 = .Div2 }); |
| 88 | + current_clock.p1_clk = current_clock.pllout >> 1; |
| 89 | + } else { |
| 90 | + current_clock.p1_clk = current_clock.pllout; |
| 91 | + } |
| 92 | + RCC.CFGR.modify(.{ .SW = .PLL1_P }); |
| 93 | + current_clock.sys_clk = current_clock.pllout; |
| 94 | + current_clock.h_clk = current_clock.pllout; |
| 95 | + current_clock.p2_clk = current_clock.pllout; |
| 96 | + current_clock.usart1_clk = current_clock.pllout; |
| 97 | + adjust_flash(); |
| 98 | +} |
| 99 | + |
| 100 | +fn adjust_flash() void { |
| 101 | + if (current_clock.sys_clk < 24_000_000) { |
| 102 | + FLASH.ACR.modify(.{ .LATENCY = .WS0 }); |
| 103 | + } else if (current_clock.sys_clk < 42_000_000) { |
| 104 | + FLASH.ACR.modify(.{ .LATENCY = .WS1, .PRFTBE = 1 }); |
| 105 | + } else { |
| 106 | + FLASH.ACR.modify(.{ .LATENCY = .WS2, .PRFTBE = 1 }); |
| 107 | + } |
| 108 | +} |
0 commit comments