From b1266cd247d458de8d3e2d89bda60a27e3b34730 Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Mon, 19 Jan 2026 11:43:59 +0100 Subject: [PATCH] STM32:Use ClockTree helper for STM32F3 --- examples/stmicro/stm32/build.zig | 4 +- examples/stmicro/stm32/src/hts221.zig | 7 +- port/stmicro/stm32/build.zig | 2 + port/stmicro/stm32/build.zig.zon | 4 +- .../stm32/src/boards/STM32F3DISCOVERY.zig | 44 ++- .../stm32/src/boards/STM32L476DISCOVERY.zig | 4 +- port/stmicro/stm32/src/hals/STM32F303.zig | 8 +- port/stmicro/stm32/src/hals/STM32F303/rcc.zig | 339 +++++++++++++----- port/stmicro/stm32/src/hals/STM32L47X.zig | 8 +- port/stmicro/stm32/src/hals/STM32L47X/rcc.zig | 46 ++- port/stmicro/stm32/src/hals/common/i2c_v2.zig | 58 +-- port/stmicro/stm32/src/hals/common/spi_v2.zig | 2 +- .../stmicro/stm32/src/hals/common/uart_v3.zig | 2 +- 13 files changed, 387 insertions(+), 141 deletions(-) diff --git a/examples/stmicro/stm32/build.zig b/examples/stmicro/stm32/build.zig index 2231e806b..22cc0307d 100644 --- a/examples/stmicro/stm32/build.zig +++ b/examples/stmicro/stm32/build.zig @@ -14,8 +14,8 @@ pub fn build(b: *std.Build) void { const stm32 = mb.ports.stm32; const available_examples = [_]Example{ - .{ .target = stm32.boards.stm32f303nucleo, .name = "stm32f303nucleo_Blinky", .file = "src/blinky.zig" }, - .{ .target = stm32.boards.stm32f3discovery, .name = "stm32f3discovery", .file = "src/blinky.zig" }, + .{ .target = stm32.boards.stm32f303nucleo, .name = "STM32F303nucleo_Blinky", .file = "src/blinky.zig" }, + .{ .target = stm32.boards.stm32f3discovery, .name = "STM32F3discovery", .file = "src/blinky.zig" }, // TODO: stm32.pins.GlobalConfiguration is not available on those targets // .{ .target = stm32.chips.stm32f407vg, .name = "stm32f407vg", .file = "src/blinky.zig" }, // .{ .target = stm32.chips.stm32f429zit6u, .name = "stm32f429zit6u", .file = "src/blinky.zig" }, diff --git a/examples/stmicro/stm32/src/hts221.zig b/examples/stmicro/stm32/src/hts221.zig index f05e9d6eb..e28ea9cb6 100644 --- a/examples/stmicro/stm32/src/hts221.zig +++ b/examples/stmicro/stm32/src/hts221.zig @@ -10,6 +10,9 @@ pub const microzig_options: microzig.Options = .{ .cpu = .{ .ram_vector_table = true, }, + .hal = if (std.mem.eql(u8, microzig.config.chip_name, "STM32F303VC")) .{ + .rcc_clock_config = board.rcc_medium_speed, + } else .{}, }; pub fn init() void { @@ -24,8 +27,8 @@ pub fn init() void { pub fn main() !void { std.log.info("Starting main", .{}); const clock = try stm32.systick_timer.clock_device(); - var i2c1 = board.i2c1(); - try i2c1.apply(); + var i2c1 = try board.i2c1(); + i2c1.apply(); var device = i2c1.i2c_device(); var hts221 = HTS221.init(&device); diff --git a/port/stmicro/stm32/build.zig b/port/stmicro/stm32/build.zig index 40150bdcd..c3c8cece0 100644 --- a/port/stmicro/stm32/build.zig +++ b/port/stmicro/stm32/build.zig @@ -38,6 +38,7 @@ pub fn init(dep: *std.Build.Dependency) Self { }, .hal = microzig.HardwareAbstractionLayer{ .root_source_file = b.path("src/hals/STM32F303.zig"), + .imports = hal_imports, }, .stack = .{ .ram_region_name = "CCMRAM" }, }), @@ -54,6 +55,7 @@ pub fn init(dep: *std.Build.Dependency) Self { }, .hal = microzig.HardwareAbstractionLayer{ .root_source_file = b.path("src/hals/STM32F303.zig"), + .imports = hal_imports, }, .stack = .{ .ram_region_name = "CCMRAM" }, }), diff --git a/port/stmicro/stm32/build.zig.zon b/port/stmicro/stm32/build.zig.zon index 1c07ecd74..b0e344bbf 100644 --- a/port/stmicro/stm32/build.zig.zon +++ b/port/stmicro/stm32/build.zig.zon @@ -10,8 +10,8 @@ .hash = "N-V-__8AAFi8WBlOh-NikHFVBjzQE0F1KixgKjVWYnlijPNm", }, .ClockHelper = .{ - .url = "git+https://github.com/ZigEmbeddedGroup/ClockHelper#7fd073b1be9544941c15f9a63032ed06149ddb70", - .hash = "ClockHelper-2.0.0-RcMaOSniGQHXH_qeoZbQDG64XThqpXTVPMfJ6P7LHpYY", + .url = "git+https://github.com/ZigEmbeddedGroup/ClockHelper#922c35eb54f0417318ccfcc32367bdcf11823ede", + .hash = "ClockHelper-2.0.0-RcMaOUMGIwEUEHQJ0C2Q-KbWdKXN2GqzQcs9MpVSTgm3", }, }, .paths = .{ diff --git a/port/stmicro/stm32/src/boards/STM32F3DISCOVERY.zig b/port/stmicro/stm32/src/boards/STM32F3DISCOVERY.zig index 76f1034d5..148442ae0 100644 --- a/port/stmicro/stm32/src/boards/STM32F3DISCOVERY.zig +++ b/port/stmicro/stm32/src/boards/STM32F3DISCOVERY.zig @@ -1,9 +1,37 @@ const std = @import("std"); pub const microzig = @import("microzig"); +const RCC = microzig.chip.peripherals.RCC; pub const hal = microzig.hal; -pub const rcc = hal.rcc; +const rcc = hal.rcc; + +pub const rcc_high_speed: rcc.Config = .{ + .PRESCALERUSB = .RCC_USBCLKSOURCE_PLL_DIV1_5, + .SYSCLKSource = .RCC_SYSCLKSOURCE_PLLCLK, + .APB1CLKDivider = .RCC_HCLK_DIV2, + .PLLSource = .RCC_PLLSOURCE_HSE, + .PLLMUL = .RCC_PLL_MUL9, + .flags = .{ + .HSEByPass = true, + .HSEOscillator = true, + .USART1Used_ForRCC = true, + .I2C1Used_ForRCC = true, + }, +}; + +pub const rcc_medium_speed: rcc.Config = .{ + .SYSCLKSource = .RCC_SYSCLKSOURCE_PLLCLK, + .APB1CLKDivider = .RCC_HCLK_DIV2, + .PLLSource = .RCC_PLLSOURCE_HSE, + .PLLMUL = .RCC_PLL_MUL6, + .flags = .{ + .HSEByPass = true, + .HSEOscillator = true, + .USART1Used_ForRCC = true, + .I2C1Used_ForRCC = true, + }, +}; pub const uart_logger = hal.uart.UARTLogger(.USART1); @@ -21,13 +49,7 @@ pub const leds_config = (hal.pins.GlobalConfiguration{ }); pub fn init() void { - rcc.enable_hse(8_000_000); - rcc.enable_pll(.HSE, .Div1, .Mul5) catch { - @panic("PLL faile to enable"); - }; - rcc.select_pll_for_sysclk() catch { - @panic("Faile to select sysclk"); - }; + rcc.apply(); } // Init should come first or the baud_rate would be too fast for the default HSI. @@ -39,12 +61,12 @@ pub fn init_log() void { }, }).apply(); uart_logger.init(.{ - .baud_rate = 115200, + .baud_rate = 9600, .dma = hal.dma.DMA1_Channel4.get_channel(), }); } -pub fn i2c1() hal.i2c.I2C_Device { +pub fn i2c1() !hal.i2c.I2C_Device { _ = (hal.pins.GlobalConfiguration{ .GPIOB = .{ // I2C @@ -57,5 +79,5 @@ pub fn i2c1() hal.i2c.I2C_Device { }, }).apply(); - return hal.i2c.I2C_Device.init(.I2C1); + return try hal.i2c.I2C_Device.init(.I2C1); } diff --git a/port/stmicro/stm32/src/boards/STM32L476DISCOVERY.zig b/port/stmicro/stm32/src/boards/STM32L476DISCOVERY.zig index 73352bd1d..35b310e12 100644 --- a/port/stmicro/stm32/src/boards/STM32L476DISCOVERY.zig +++ b/port/stmicro/stm32/src/boards/STM32L476DISCOVERY.zig @@ -201,7 +201,7 @@ pub const Lcd = struct { } }; -pub fn i2c1() hal.i2c.I2C_Device { +pub fn i2c1() !hal.i2c.I2C_Device { _ = (hal.pins.GlobalConfiguration{ .GPIOB = .{ // I2C @@ -214,7 +214,7 @@ pub fn i2c1() hal.i2c.I2C_Device { }, }).apply(); - return hal.i2c.I2C_Device.init(.I2C1); + return try hal.i2c.I2C_Device.init(.I2C1); } pub const uart_logger = hal.uart.UARTLogger(.USART2); diff --git a/port/stmicro/stm32/src/hals/STM32F303.zig b/port/stmicro/stm32/src/hals/STM32F303.zig index 35864fa2a..3cd46707b 100644 --- a/port/stmicro/stm32/src/hals/STM32F303.zig +++ b/port/stmicro/stm32/src/hals/STM32F303.zig @@ -12,9 +12,13 @@ pub const systick_timer = @import("./common/systick_timer.zig"); pub const systick = @import("./common/systick.zig"); pub fn get_sys_clk() u32 { - return rcc.current_clock.h_clk; + return @intFromFloat(rcc.current_clocks.clock.HCLKOutput); } pub fn get_systick_clk() u32 { - return rcc.current_clock.h_clk / 8; + return @as(u32, @intFromFloat(rcc.current_clocks.clock.HCLKOutput)) / 8; } + +pub const HAL_Options = struct { + rcc_clock_config: rcc.Config = .{}, +}; diff --git a/port/stmicro/stm32/src/hals/STM32F303/rcc.zig b/port/stmicro/stm32/src/hals/STM32F303/rcc.zig index 89326c19e..6cd5f2430 100644 --- a/port/stmicro/stm32/src/hals/STM32F303/rcc.zig +++ b/port/stmicro/stm32/src/hals/STM32F303/rcc.zig @@ -1,127 +1,306 @@ +/// This RCC config file apply to +/// 303xB or 303xC only. (regz using rcc_f3v1 from ambassy) +/// +/// Other chip D/E/6/8 have different clock tree +/// In the future we can switch on chip name to address +/// this limitation. const microzig = @import("microzig"); +const Clock_Device = microzig.drivers.base.Clock_Device; const enums = @import("../common/enums.zig"); const util = @import("../common/util.zig"); +const clock_tree = @import("ClockTree").get_mcu_tree(microzig.config.chip_name); +const app = microzig.app; + +pub const RCC_Peripheral = @This(); + +//expose only configurations structs +pub const Config = clock_tree.Config; + const RCC = microzig.chip.peripherals.RCC; -const GPIOF = microzig.chip.peripherals.GPIOF; const FLASH = microzig.chip.peripherals.FLASH; +const LATENCY = microzig.chip.types.peripherals.flash_f3.LATENCY; const PREDIV = microzig.chip.types.peripherals.rcc_f3v1.PREDIV; +const HPRE = microzig.chip.types.peripherals.rcc_f3v1.HPRE; +const PPRE = microzig.chip.types.peripherals.rcc_f3v1.PPRE; +const ADCPRES = microzig.chip.types.peripherals.rcc_f3v1.ADCPRES; +const USBPRE = microzig.chip.types.peripherals.rcc_f3v1.USBPRE; + const PLLMUL = microzig.chip.types.peripherals.rcc_f3v1.PLLMUL; +const PLLSRC = microzig.chip.types.peripherals.rcc_f3v1.PLLSRC; const ICSW = microzig.chip.types.peripherals.rcc_f3v1.ICSW; +const ISSRC = microzig.chip.types.peripherals.rcc_f3v1.ISSRC; +const SW = microzig.chip.types.peripherals.rcc_f3v1.SW; +const TIM2SW = microzig.chip.types.peripherals.rcc_f3v1.TIM2SW; +const TIMSW = microzig.chip.types.peripherals.rcc_f3v1.TIMSW; +const USART1SW = microzig.chip.types.peripherals.rcc_f3v1.USART1SW; +const USARTSW = microzig.chip.types.peripherals.rcc_f3v1.USARTSW; pub const Peripherals = enums.Peripherals; -pub const ClockName = enum { - HSE, - HSI, - PLLCLK, - SYSCLK, - - fn is_for_pll(self: @This()) bool { - return self == .HSE or self == .HSI; - } - - fn is_for_sysclk(self: @This()) bool { - return self != .SYSCLK; - } -}; - -pub const RccErrorConfig = error{ - WrongClockSource, - SourceClockNotInitialized, - OutputPllTooHigh, - PllMustBeEnableFirst, -}; +// The current running clock +pub const current_clocks: clock_tree.Tree_Output = clock_tree.get_clocks(microzig.options.hal.rcc_clock_config) catch unreachable; -pub const Clock = struct { - sys_clk: u32 = 8_000_000, - h_clk: u32 = 8_000_000, - p1_clk: u32 = 8_000_000, - p2_clk: u32 = 8_000_000, - hse: u32 = 0, - hsi: u32 = 8_000_000, - pllout: u32 = 0, - usart1_clk: u32 = 8_000_000, -}; +pub fn apply() void { + apply_flash_flash(); + apply_prescaler(); -pub var current_clock: Clock = .{}; + // Configure primary clock source if need be + apply_hse(); + apply_hsi(); + apply_pll(); -pub fn enable_pll(comptime source: ClockName, div: PREDIV, mul: PLLMUL) RccErrorConfig!void { - if (!source.is_for_pll()) { - return RccErrorConfig.WrongClockSource; - } + clean_clock(); + select_clock(); +} - if (source == .HSE and current_clock.hse == 0) { - return RccErrorConfig.SourceClockNotInitialized; - } +fn get_ppll_source() PLLSRC { + return if (current_clocks.config.flags.PLLSource) |source| + @enumFromInt(@as(u1, @intCast(source.get()))) + else + .HSI_Div2; +} - const inputClock = if (source == .HSE) current_clock.hse else (current_clock.hsi >> 1); +fn apply_flash_flash() void { + const latency: LATENCY = if (current_clocks.config.FLatency) |lat| @enumFromInt(@as(u3, @intFromEnum(lat))) else .WS0; + const prefetch: u1 = if (current_clocks.config.flags.PREFETCH_ENABLE) 1 else 0; - const inputDiv = @intFromEnum(div) + 1; - const outputMul = @intFromEnum(mul) + 2; + FLASH.ACR.modify(.{ .LATENCY = latency, .PRFTBE = prefetch }); +} - const expectedPllOut = @divTrunc(inputClock, inputDiv) * outputMul; - if (expectedPllOut > 72_000_000) { - return RccErrorConfig.OutputPllTooHigh; +fn apply_pll() void { + if (!current_clocks.config.flags.PLLUsed) { + return; } + const source: PLLSRC = if (current_clocks.config.PLLSource) |src| @enumFromInt(@as(u1, @intCast(src.get()))) else .HSI_Div2; + const mul: PLLMUL = if (current_clocks.config.PLLMUL) |pre| @enumFromInt(@as(u4, @intFromEnum(pre))) else .Mul2; + // TODO: ClockHelper need fix for STM32F303xC/xB + // const divider: PREDIV = if (current_clocks.config.PLLDivider) |pre| @enumFromInt(@as(u4, @intFromEnum(pre))) else .Div1; + //RCC.CFGR2.modify(.{ .PREDIV = divider }); - RCC.CFGR.modify(.{ .PLLSRC = comptime if (source == .HSE) .HSE_Div_PREDIV else .HSI_Div2, .PLLMUL = mul }); + RCC.CFGR.modify(.{ + .PLLSRC = source, + .PLLMUL = mul, + }); RCC.CR.modify(.{ .PLLON = 1 }); while (RCC.CR.read().PLLRDY != 1) { asm volatile ("" ::: .{ .memory = true }); } - - current_clock.pllout = expectedPllOut; } -pub fn enable_hse(speed: u32) void { - RCC.CR.modify(.{ .HSEON = 1, .HSEBYP = 1 }); +fn apply_hsi() void { + if (!current_clocks.config.flags.HSIUsed) { + return; + } + RCC.CR.modify(.{ + .HSION = 1, + }); - while (RCC.CR.read().HSERDY != 1) { + while (RCC.CR.read().HSIRDY != 1) { asm volatile ("" ::: .{ .memory = true }); } - current_clock.hse = speed; } -pub fn select_pll_for_sysclk() RccErrorConfig!void { - if (current_clock.pllout == 0) { - return RccErrorConfig.PllMustBeEnableFirst; - } - // Maximum APB low speed domain is 36Nhz, let's divide by 2 - if (current_clock.pllout > 36_000_000) { - RCC.CFGR.modify(.{ .PPRE1 = .Div2 }); - current_clock.p1_clk = current_clock.pllout >> 1; +fn apply_hse() void { + if (!current_clocks.config.flags.HSEUsed) { + return; } else { - current_clock.p1_clk = current_clock.pllout; + const hse_by_pass: u1 = if (current_clocks.config.flags.HSEByPass) 1 else 0; + RCC.CR.modify(.{ + .HSEON = 1, + .HSEBYP = hse_by_pass, + }); + + while (RCC.CR.read().HSERDY != 1) { + asm volatile ("" ::: .{ .memory = true }); + } + } +} + +fn apply_prescaler() void { + const apb1: PPRE = if (current_clocks.config.APB1CLKDivider) |pre| @enumFromInt(@as(u3, @intFromEnum(pre))) else .Div1; + const apb2: PPRE = if (current_clocks.config.APB2CLKDivider) |pre| @enumFromInt(@as(u3, @intFromEnum(pre))) else .Div1; + const ahb: HPRE = if (current_clocks.config.AHBCLKDivider) |pre| @enumFromInt(@as(u4, @intFromEnum(pre))) else .Div1; + const adc12: ADCPRES = if (current_clocks.config.ADC12PRES) |pre| @enumFromInt(@as(u5, @intFromEnum(pre))) else .Div1; + const adc34: ADCPRES = if (current_clocks.config.ADC34PRES) |pre| @enumFromInt(@as(u5, @intFromEnum(pre))) else .Div1; + const usbprescal: USBPRE = if (current_clocks.config.PRESCALERUSB) |pre| @enumFromInt(@as(u1, @intFromEnum(pre))) else .Div1; + + RCC.CFGR.modify(.{ + .HPRE = ahb, + .PPRE1 = apb1, + .PPRE2 = apb2, + .USBPRE = usbprescal, + }); + RCC.CFGR2.modify(.{ + .ADC12PRES = adc12, + .ADC34PRES = adc34, + }); +} + +// Once all clock is setup for the system +// we can disable all clock not used +fn clean_clock() void { + if (current_clocks.config.flags.EnbaleCSS) { + RCC.CR.modify(.{ .CSSON = 0 }); + } + if (!current_clocks.config.flags.HSEUsed) { + RCC.CR.modify(.{ .HSEON = 0 }); + } + if (!current_clocks.config.flags.HSEUsed) { + RCC.CR.modify(.{ .HSION = 0 }); + } + if (!current_clocks.config.flags.PLLUsed) { + RCC.CR.modify(.{ .PLLON = 0 }); } - current_clock.sys_clk = current_clock.pllout; - adjust_flash(); - RCC.CFGR.modify(.{ .SW = .PLL1_P }); - current_clock.h_clk = current_clock.pllout; - current_clock.p2_clk = current_clock.pllout; - current_clock.usart1_clk = current_clock.pllout; } -pub fn get_spi_clk(spiindex: enums.SPI_Type) u32 { - return switch (spiindex) { - .SPI1 => current_clock.p2_clk, - .SPI2, .SPI3 => current_clock.p1_clk, +// TODO: Patch for ClockTree +fn usart1Selection(src: anytype) USART1SW { + return switch (src) { + .RCC_USART1CLKSOURCE_SYSCLK => .SYS, + .RCC_USART1CLKSOURCE_HSI => .HSI, + .RCC_USART1CLKSOURCE_LSE => .LSE, + .RCC_USART1CLKSOURCE_PCLK1 => unreachable, + .RCC_USART1CLKSOURCE_PCLK2 => .PCLK2, }; } -fn adjust_flash() void { - if (current_clock.sys_clk < 24_000_000) { - FLASH.ACR.modify(.{ .LATENCY = .WS0 }); - } else if (current_clock.sys_clk < 42_000_000) { - FLASH.ACR.modify(.{ .LATENCY = .WS1, .PRFTBE = 1 }); - } else { - FLASH.ACR.modify(.{ .LATENCY = .WS2, .PRFTBE = 1 }); +// TODO: Patch for ClockTree +fn usart2Selection(src: anytype) USARTSW { + return switch (src) { + .RCC_USART2CLKSOURCE_SYSCLK => .SYS, + .RCC_USART2CLKSOURCE_HSI => .HSI, + .RCC_USART2CLKSOURCE_LSE => .LSE, + .RCC_USART2CLKSOURCE_PCLK1 => .PCLK1, + }; +} + +// TODO: Patch for ClockTree +fn usart3Selection(src: anytype) USARTSW { + return switch (src) { + .RCC_USART3CLKSOURCE_SYSCLK => .SYS, + .RCC_USART3CLKSOURCE_HSI => .HSI, + .RCC_USART3CLKSOURCE_LSE => .LSE, + .RCC_USART3CLKSOURCE_PCLK1 => .PCLK1, + }; +} + +// TODO: Patch for ClockTree +fn uart4Selection(src: anytype) USARTSW { + return switch (src) { + .RCC_UART4CLKSOURCE_SYSCLK => .SYS, + .RCC_UART4CLKSOURCE_HSI => .HSI, + .RCC_UART4CLKSOURCE_LSE => .LSE, + .RCC_UART4CLKSOURCE_PCLK1 => .PCLK1, + }; +} // TODO: Patch for ClockTree +fn uart5Selection(src: anytype) USARTSW { + return switch (src) { + .RCC_UART5CLKSOURCE_SYSCLK => .SYS, + .RCC_UART5CLKSOURCE_HSI => .HSI, + .RCC_UART5CLKSOURCE_LSE => .LSE, + .RCC_UART5CLKSOURCE_PCLK1 => .PCLK1, + }; +} + +// TODO: Patch for ClockTree +fn i2sSelection(src: anytype) ISSRC { + return switch (src) { + .RCC_I2SCLKSOURCE_EXT => .CKIN, + .RCC_I2SCLKSOURCE_SYSCLK => .SYS, + }; +} + +pub fn select_clock() void { + const sys_clk: SW = if (current_clocks.config.SYSCLKSource) |src| @enumFromInt(@as(u2, @intFromEnum(src))) else .HSI; + const i2s_clk: ISSRC = if (current_clocks.config.I2SClockSource) |src| i2sSelection(src) else .SYS; + const i2c1_clk: ICSW = if (current_clocks.config.I2c1ClockSelection) |src| @enumFromInt(@as(u1, @intCast(src.get()))) else .HSI; + const i2c2_clk: ICSW = if (current_clocks.config.I2c1ClockSelection) |src| @enumFromInt(@as(u1, @intCast(src.get()))) else .HSI; + + const usart1_clk: USART1SW = if (current_clocks.config.Usart1ClockSelection) |src| usart1Selection(src) else .HSI; + const usart2_clk: USARTSW = if (current_clocks.config.Usart2ClockSelection) |src| usart2Selection(src) else .HSI; + const usart3_clk: USARTSW = if (current_clocks.config.Usart3ClockSelection) |src| usart3Selection(src) else .HSI; + const uart4_clk: USARTSW = if (current_clocks.config.Uart4ClockSelection) |src| uart4Selection(src) else .HSI; + const uart5_clk: USARTSW = if (current_clocks.config.Uart5ClockSelection) |src| uart5Selection(src) else .HSI; + + RCC.CFGR.modify(.{ + .SW = sys_clk, + .I2SSRC = i2s_clk, + }); + RCC.CFGR3.modify(.{ + .USART1SW = usart1_clk, + .USART2SW = usart2_clk, + .USART3SW = usart3_clk, + .UART4SW = uart4_clk, + .UART5SW = uart5_clk, + .I2C1SW = i2c1_clk, + .I2C2SW = i2c2_clk, + }); +} + +pub fn get_clock(comptime source: Peripherals) u32 { + const peri_name = @tagName(source); + + if (comptime util.match_name(peri_name, &.{ + "TIM", + })) { + return @intFromFloat(@field(current_clocks.clock, peri_name ++ "out")); } + if (comptime util.match_name(peri_name, &.{ + "USART", + "UART", + "I2C", + "RTC", + })) { + return @intFromFloat(@field(current_clocks.clock, peri_name ++ "Output")); + } + if (comptime util.match_name(peri_name, &.{ + "DMA", + "FLASH", + "CRC", + "GPIO", + })) { + return @intFromFloat(current_clocks.clock.AHBOutput); + } + if (comptime util.match_name(peri_name, &.{ + "ADC1", + "ADC2", + })) { + return @intFromFloat(current_clocks.clock.ADC12output); + } + if (comptime util.match_name(peri_name, &.{ + "ADC3", + "ADC4", + })) { + return @intFromFloat(current_clocks.clock.ADC34output); + } + if (comptime util.match_name(peri_name, &.{ + "SPI1", + })) { + return @intFromFloat(current_clocks.clock.APB2Prescaler); + } + if (comptime util.match_name(peri_name, &.{ + "SPI2", + "SPI3", + "DAC", + "CAN", + "WWDG", + "IWDG", + })) { + return @intFromFloat(current_clocks.clock.APB1Prescaler); + } + if (comptime util.match_name(peri_name, &.{ + "USB", + })) { + return @intFromFloat(current_clocks.clock.USBoutput); + } + + @panic("Unknown clock for peripheral"); } pub fn set_clock(comptime peri: Peripherals, state: u1) void { const peri_name = @tagName(peri); - if (util.match_name(peri_name, &.{"RTC"})) { + if (comptime util.match_name(peri_name, &.{"RTC"})) { @panic("RTC not implemented yet"); } diff --git a/port/stmicro/stm32/src/hals/STM32L47X.zig b/port/stmicro/stm32/src/hals/STM32L47X.zig index 031a96302..9102c76da 100644 --- a/port/stmicro/stm32/src/hals/STM32L47X.zig +++ b/port/stmicro/stm32/src/hals/STM32L47X.zig @@ -9,9 +9,13 @@ pub const i2c = @import("./STM32L47X/i2c.zig"); pub const dma = @import("./STM32L47X/dma.zig"); pub fn get_sys_clk() u32 { - return rcc.current_clock.h_clk; + return @intFromFloat(rcc.current_clocks.clock.HCLKOutput); } pub fn get_systick_clk() u32 { - return rcc.current_clock.h_clk / 8; + return @as(u32, @intFromFloat(rcc.current_clocks.clock.HCLKOutput)) / 8; } + +pub const HAL_Options = struct { + rcc_clock_config: rcc.Config = .{}, +}; diff --git a/port/stmicro/stm32/src/hals/STM32L47X/rcc.zig b/port/stmicro/stm32/src/hals/STM32L47X/rcc.zig index b67934e79..e7f45562e 100644 --- a/port/stmicro/stm32/src/hals/STM32L47X/rcc.zig +++ b/port/stmicro/stm32/src/hals/STM32L47X/rcc.zig @@ -1,7 +1,10 @@ const microzig = @import("microzig"); const enums = @import("../common/enums.zig"); const util = @import("../common/util.zig"); +const clock_tree = @import("ClockTree").get_mcu_tree(microzig.config.chip_name); +//expose only configurations structs +pub const Config = clock_tree.Config; pub const Peripherals = enums.Peripherals; const RCC = microzig.chip.peripherals.RCC; const PWR = microzig.chip.peripherals.PWR; @@ -20,18 +23,8 @@ const ICSW = enum(u2) { }; const pins = microzig.hal.pins; -pub const Clock = struct { - sys_clk: u32 = 4_000_000, - h_clk: u32 = 4_000_000, - p1_clk: u32 = 4_000_000, - p2_clk: u32 = 4_000_000, - hse: u32 = 0, - hsi: u32 = 4_000_000, - pllout: u32 = 0, - usart1_clk: u32 = 4_000_000, -}; - -pub var current_clock: Clock = .{}; +// The current running clock +pub const current_clocks: clock_tree.Tree_Output = clock_tree.get_clocks(microzig.options.hal.rcc_clock_config) catch unreachable; pub fn enable_rtc_lcd() void { RCC.APB1ENR1.modify(.{ @@ -61,6 +54,35 @@ pub fn enable_rtc_lcd() void { }); } +pub fn get_clock(comptime source: Peripherals) u32 { + const peri_name = @tagName(source); + + if (comptime util.match_name(peri_name, &.{ + "USART", + "UART", + "I2C", + })) { + return @intFromFloat(@field(current_clocks.clock, peri_name ++ "output")); + } + if (comptime util.match_name(peri_name, &.{ + "SPI1", + })) { + return @intFromFloat(current_clocks.clock.APB2Prescaler); + } + if (comptime util.match_name(peri_name, &.{ + "SPI2", + "SPI3", + })) { + return @intFromFloat(current_clocks.clock.APB1Prescaler); + } + if (comptime util.match_name(peri_name, &.{ + "USB", + })) { + return @intFromFloat(current_clocks.clock.USBoutput); + } + + @panic("Unknown clock for peripheral"); +} pub fn set_clock(comptime peri: Peripherals, state: u1) void { const peri_name = @tagName(peri); if (util.match_name(peri_name, &.{"RTC"})) { diff --git a/port/stmicro/stm32/src/hals/common/i2c_v2.zig b/port/stmicro/stm32/src/hals/common/i2c_v2.zig index d3e49809e..dfd0ae589 100644 --- a/port/stmicro/stm32/src/hals/common/i2c_v2.zig +++ b/port/stmicro/stm32/src/hals/common/i2c_v2.zig @@ -30,13 +30,22 @@ const TimingSpec_Standard = .{ .t_min_af = 0.05, }; +const TIMINGR = blk: for (@typeInfo(I2C_Peripherals).@"struct".fields) |field| +{ + if (std.mem.eql(u8, "TIMINGR", field.name)) { + break :blk field.type; + } +} else @compileError("No TIMINGR register"); + const I2C = struct { regs: *volatile I2C_Peripherals, + timingr: TIMINGR.underlying_type, - fn compute_presc() ConfigError!struct { f32, u4 } { + fn compute_presc(comptime instance: I2C_Type) ConfigError!struct { f32, u4 } { // Let first see if we need to prescale. // 100Khz = 10us period ~ 5us for SCLL/SCLH - const t_sckl = 1_000_000.0 / @as(f32, @floatFromInt(hal.rcc.current_clock.sys_clk)); + const device_clock = @as(f32, @floatFromInt(hal.rcc.get_clock(enums.to_peripheral(instance)))); + const t_sckl = 1_000_000.0 / device_clock; if (t_sckl > 0.1) { return .{ t_sckl, 0 }; @@ -110,26 +119,12 @@ const I2C = struct { // Interupt, // Frequency // Others... - pub fn apply(i2c: *const I2C) ConfigError!void { + pub fn apply(i2c: *const I2C) void { const regs = i2c.regs; - const t_presc, const presc = try compute_presc(); - const scdel = try compute_setup_time(t_presc); - const sdadel = try compute_hold_time(t_presc); - const scll = try compute_low_time(t_presc); - const sclh = try compute_high_time(t_presc); - regs.CR1.modify(.{ .PE = 0 }); - std.log.info("TIMINGR register: SCEDL {}, SDADEL {}, SCLL {}, SCLH {}\r\n", .{ scdel, sdadel, scll, sclh }); - - regs.TIMINGR.modify(.{ - .PRESC = presc, - .SCLDEL = scdel, - .SDADEL = sdadel, - .SCLL = scll, - .SCLH = sclh, - }); + regs.TIMINGR.modify(i2c.timingr); regs.CR1.modify(.{ .PE = 1 }); } @@ -194,9 +189,24 @@ const I2C = struct { return i2c.write_blocking_intern(address, false, data); } - pub fn init(comptime instance: I2C_Type) I2C { + /// This init should be comptime safe. + pub fn init(comptime instance: I2C_Type) ConfigError!I2C { hal.rcc.enable_clock(enums.to_peripheral(instance)); - return .{ .regs = enums.get_regs(I2C_Peripherals, instance) }; + const t_presc, const presc = try compute_presc(instance); + const scdel = try compute_setup_time(t_presc); + const sdadel = try compute_hold_time(t_presc); + const scll = try compute_low_time(t_presc); + const sclh = try compute_high_time(t_presc); + + const timingr: TIMINGR.underlying_type = .{ + .PRESC = presc, + .SCLDEL = scdel, + .SDADEL = sdadel, + .SCLL = scll, + .SCLH = sclh, + }; + + return .{ .regs = enums.get_regs(I2C_Peripherals, instance), .timingr = timingr }; } }; @@ -246,12 +256,12 @@ pub const I2C_Device = struct { } } - pub fn apply(i2c: *const I2C_Device) ConfigError!void { - try i2c.i2c.apply(); + pub fn apply(i2c: *const I2C_Device) void { + i2c.i2c.apply(); } - pub fn init(comptime instance: I2C_Type) I2C_Device { - return .{ .i2c = I2C.init(instance) }; + pub fn init(comptime instance: I2C_Type) ConfigError!I2C_Device { + return .{ .i2c = try I2C.init(instance) }; } pub fn i2c_device(i2c: *I2C_Device) drivers.I2C_Device { diff --git a/port/stmicro/stm32/src/hals/common/spi_v2.zig b/port/stmicro/stm32/src/hals/common/spi_v2.zig index cd5ba172a..5d28c5218 100644 --- a/port/stmicro/stm32/src/hals/common/spi_v2.zig +++ b/port/stmicro/stm32/src/hals/common/spi_v2.zig @@ -31,7 +31,7 @@ pub const SPI = struct { nss: ?*Digital_IO, pub fn apply(self: *const SPI, config: Config) Error!void { - const clk = hal.rcc.get_spi_clk(self.instance); + const clk = hal.rcc.get_clock(self.instance); const divider = (clk / config.max_frequency) + 1; diff --git a/port/stmicro/stm32/src/hals/common/uart_v3.zig b/port/stmicro/stm32/src/hals/common/uart_v3.zig index baf93196f..b1ff8050a 100644 --- a/port/stmicro/stm32/src/hals/common/uart_v3.zig +++ b/port/stmicro/stm32/src/hals/common/uart_v3.zig @@ -79,7 +79,7 @@ pub fn Uart(comptime index: UART_Type) type { // TODO: Do not use the _board_'s frequency, but the _U(S)ARTx_ frequency // from the chip // TODO: Do some checks to see if the baud rate is too high (or perhaps too low) - const usartdiv = @divTrunc(if (index == .USART1) rcc.current_clock.usart1_clk else rcc.current_clock.p1_clk, config.baud_rate); + const usartdiv = @divTrunc(rcc.get_clock(enums.to_peripheral(index)), config.baud_rate); regs.BRR.raw = @as(u16, @intCast(usartdiv)); // TODO: We assume the default OVER8=0 configuration above.