diff --git a/examples/stmicro/stm32/src/blinky.zig b/examples/stmicro/stm32/src/blinky.zig index 74968ec62..e019050fb 100644 --- a/examples/stmicro/stm32/src/blinky.zig +++ b/examples/stmicro/stm32/src/blinky.zig @@ -40,6 +40,13 @@ pub fn main() !void { pins.LD10, }; break :res .{ pins, all_leds }; + } else if (comptime microzig.config.board_name != null and std.mem.eql(u8, microzig.config.board_name.?, "STM32F429IDISCOVERY")) { + const pins = board.leds_config.apply(); + const all_leds = .{ + pins.LD3, + pins.LD4, + }; + break :res .{ pins, all_leds }; } else if (comptime microzig.config.board_name != null and std.mem.eql(u8, microzig.config.board_name.?, "STM32L476DISCOVERY")) { const pins = board.leds_config.apply(); const all_leds = .{ diff --git a/port/stmicro/stm32/build.zig b/port/stmicro/stm32/build.zig index c3c8cece0..859bda2a3 100644 --- a/port/stmicro/stm32/build.zig +++ b/port/stmicro/stm32/build.zig @@ -76,6 +76,10 @@ pub fn init(dep: *std.Build.Dependency) Self { .name = "STM32F429IDISCOVERY", .root_source_file = b.path("src/boards/STM32F429IDISCOVERY.zig"), }, + .hal = microzig.HardwareAbstractionLayer{ + .root_source_file = b.path("src/hals/STM32F429.zig"), + .imports = hal_imports, + }, }), }, }; diff --git a/port/stmicro/stm32/src/boards/STM32F429IDISCOVERY.zig b/port/stmicro/stm32/src/boards/STM32F429IDISCOVERY.zig index 034295a13..ce1449bf6 100644 --- a/port/stmicro/stm32/src/boards/STM32F429IDISCOVERY.zig +++ b/port/stmicro/stm32/src/boards/STM32F429IDISCOVERY.zig @@ -1,3 +1,7 @@ +pub const microzig = @import("microzig"); + +pub const hal = microzig.hal; + pub const cpu_frequency = 16_000_000; pub const pin_map = .{ @@ -10,3 +14,10 @@ pub const pin_map = .{ // User button .B1 = "PA0", }; + +pub const leds_config = (hal.pins.GlobalConfiguration{ + .GPIOG = .{ + .PIN13 = .{ .name = "LD3", .mode = .{ .output = .{ .resistor = .Floating, .o_type = .PushPull } } }, + .PIN14 = .{ .name = "LD4", .mode = .{ .output = .{ .resistor = .Floating, .o_type = .PushPull } } }, + }, +}); diff --git a/port/stmicro/stm32/src/hals/STM32F429.zig b/port/stmicro/stm32/src/hals/STM32F429.zig index 43caee757..2b303b027 100644 --- a/port/stmicro/stm32/src/hals/STM32F429.zig +++ b/port/stmicro/stm32/src/hals/STM32F429.zig @@ -6,14 +6,14 @@ //! default AHB prescaler = /1 (= values 0..7): //! //! ``` -//! RCC.CFGR.modify(.{ .HPRE = 0 }); +//! RCC.CFGR.modify(.{ .HPRE = .Div1 }); //! ``` //! //! so also HCLK = 16 MHz. //! And with the default APB1 prescaler = /1: //! //! ``` -//! RCC.CFGR.modify(.{ .PPRE1 = 0 }); +//! RCC.CFGR.modify(.{ .PPRE1 = .Div1 }); //! ``` //! //! results in PCLK1 = 16 MHz. @@ -22,9 +22,16 @@ const std = @import("std"); const microzig = @import("microzig"); -const peripherals = microzig.peripherals; +const mmio = microzig.mmio; +const peripherals = microzig.chip.peripherals; const RCC = peripherals.RCC; +const Digital_IO = microzig.drivers.base.Digital_IO; + +const State = Digital_IO.State; + +pub const pins = @import("./common/pins_v2.zig"); + pub const clock = struct { pub const Domain = enum { cpu, @@ -42,51 +49,63 @@ pub const clock_frequencies = .{ .apb2 = 16_000_000, }; -pub fn parse_pin(comptime spec: []const u8) type { - const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}{Pin}\" scheme."; - - if (spec[0] != 'P') - @compileError(invalid_format_msg); - if (spec[1] < 'A' or spec[1] > 'K') - @compileError(invalid_format_msg); - - const pin_number: comptime_int = std.fmt.parseInt(u4, spec[2..], 10) catch @compileError(invalid_format_msg); +// TODO: There should be a common rcc with stuff like this, just like pins_v2.zig +pub const rcc = struct { + const util = @import("common/util.zig"); + const _rcc = microzig.chip.peripherals.RCC; - return struct { - /// 'A'...'K' - const gpio_port_name = spec[1..2]; - const gpio_port = @field(peripherals, "GPIO" ++ gpio_port_name); - const suffix = std.fmt.comptimePrint("{d}", .{pin_number}); - }; -} - -fn set_reg_field(reg: anytype, comptime field_name: anytype, value: anytype) void { - var temp = reg.read(); - @field(temp, field_name) = value; - reg.write(temp); -} + // Any peripheral that must be enable in RCC. + pub const Peripherals = util.create_peripheral_enum(&.{ + "GPIO", + }); -pub const gpio = struct { - pub fn set_output(comptime pin: type) void { - set_reg_field(RCC.AHB1ENR, "GPIO" ++ pin.gpio_port_name ++ "EN", 1); - set_reg_field(@field(pin.gpio_port, "MODER"), "MODER" ++ pin.suffix, 0b01); + ///configure the power and clock registers before enabling the RTC + ///this function also can be called from `rtc.enable()` + pub fn enable_rtc(on: bool) void { + _rcc.BDCR.modify(.{ .RTCEN = @intFromBool(on) }); } - pub fn set_input(comptime pin: type) void { - set_reg_field(RCC.AHB1ENR, "GPIO" ++ pin.gpio_port_name ++ "EN", 1); - set_reg_field(@field(pin.gpio_port, "MODER"), "MODER" ++ pin.suffix, 0b00); + pub fn set_clock(comptime peri: Peripherals, state: u1) void { + const peri_name = @tagName(peri); + const field = peri_name ++ "EN"; + if (util.match_name(peri_name, &.{"RTC"})) { + enable_rtc(state != 0); + return; + } + const rcc_register_name = comptime if (util.match_name(peri_name, &.{ + "OTGHSULPI", + "OTGHS", + "ETHMACPTP", + "ETHMACRX", + "ETHMACTX", + "ETHMAC", + "DMA2D", + "DMA2", + "DMA1", + "CCMDATARAM", + "BKPSRAM", + "CRC", + "GPIOK", + "GPIOJ", + "GPIOI", + "GPIOH", + "GPIOG", + "GPIOF", + "GPIOE", + "GPIOD", + "GPIOC", + "GPIOB", + "GPIOA", + })) "AHB1ENR" else "AHB1ENR"; + + @field(_rcc, rcc_register_name).modify_one(field, state); } - pub fn read(comptime pin: type) microzig.gpio.State { - const idr_reg = pin.gpio_port.IDR; - const reg_value = @field(idr_reg.read(), "IDR" ++ pin.suffix); // TODO extract to getRegField()? - return @as(microzig.gpio.State, @enumFromInt(reg_value)); + pub fn enable_clock(comptime peri: Peripherals) void { + set_clock(peri, 1); } - pub fn write(comptime pin: type, state: microzig.gpio.State) void { - switch (state) { - .low => set_reg_field(pin.gpio_port.BSRR, "BR" ++ pin.suffix, 1), - .high => set_reg_field(pin.gpio_port.BSRR, "BS" ++ pin.suffix, 1), - } + pub fn disable_clock(comptime peri: Peripherals) void { + set_clock(peri, 0); } }; diff --git a/port/stmicro/stm32/src/hals/common/gpio_v2.zig b/port/stmicro/stm32/src/hals/common/gpio_v2.zig deleted file mode 100644 index fba4909f6..000000000 --- a/port/stmicro/stm32/src/hals/common/gpio_v2.zig +++ /dev/null @@ -1,177 +0,0 @@ -const std = @import("std"); -const microzig = @import("microzig"); - -const assert = std.debug.assert; -pub const peripherals = microzig.chip.peripherals; - -const gpio_v2 = microzig.chip.types.peripherals.gpio_v2; -const GPIO = gpio_v2.GPIO; -const MODER = gpio_v2.MODER; -const PUPDR = gpio_v2.PUPDR; -const OSPEEDR = gpio_v2.OSPEEDR; -const OT = gpio_v2.OT; -const AFIO = microzig.chip.peripherals.AFIO; - -pub const Port = enum { - A, - B, - C, - D, - E, - F, - G, -}; - -pub const Mode = union(enum) { - input: InputMode, - output: OutputMode, - analog: AnalogMode, - alternate_function: AlternateFunction, - digital_io: Digital_IO, -}; - -pub const Digital_IO = struct {}; - -pub const InputMode = struct { - resistor: PUPDR, -}; - -pub const OutputMode = struct { - resistor: PUPDR, - o_type: OT, - o_speed: OSPEEDR = .LowSpeed, -}; - -pub const AnalogMode = struct { - resistor: PUPDR = .Floating, -}; - -pub const AF = enum(u4) { - AF0, - AF1, - AF2, - AF3, - AF4, - AF5, - AF6, - AF7, - AF8, - AF9, - AF10, - AF11, - AF12, - AF13, - AF14, - AF15, -}; - -pub const AlternateFunction = struct { - afr: AF, - resistor: PUPDR = .Floating, - o_type: OT = .PushPull, - o_speed: OSPEEDR = .HighSpeed, -}; - -// This is mostly internal to hal for writing configuration. -// Public implementation is provided in the pins.zig file. -pub const Pin = enum(usize) { - _, - - pub inline fn write_pin_config(gpio: Pin, mode: Mode) void { - switch (mode) { - .input => |imode| { - gpio.set_moder(MODER.Input); - gpio.set_bias(imode.resistor); - }, - .output => |omode| { - gpio.set_moder(MODER.Output); - gpio.set_output_type(omode.o_type); - gpio.set_bias(omode.resistor); - gpio.set_speed(omode.o_speed); - }, - .analog => |amode| { - gpio.set_moder(MODER.Analog); - gpio.set_bias(amode.resistor); - }, - .alternate_function => |afmode| { - gpio.set_moder(MODER.Alternate); - gpio.set_bias(afmode.resistor); - gpio.set_speed(afmode.o_speed); - gpio.set_output_type(afmode.o_type); - gpio.set_alternate_function(afmode.afr); - }, - .digital_io => { - // Nothing for now - }, - } - } - - pub fn mask_2bit(gpio: Pin) u32 { - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - return @as(u32, 0b11) << (pin << 1); - } - - pub fn mask(gpio: Pin) u32 { - const pin: u4 = @intCast(@intFromEnum(gpio) % 16); - return @as(u32, 1) << pin; - } - - //NOTE: should invalid pins panic or just be ignored? - pub fn get_port(gpio: Pin) *volatile GPIO { - const port: usize = @divFloor(@intFromEnum(gpio), 16); - switch (port) { - 0 => return if (@hasDecl(peripherals, "GPIOA")) peripherals.GPIOA else @panic("Invalid Pin"), - 1 => return if (@hasDecl(peripherals, "GPIOB")) peripherals.GPIOB else @panic("Invalid Pin"), - 2 => return if (@hasDecl(peripherals, "GPIOC")) peripherals.GPIOC else @panic("Invalid Pin"), - 3 => return if (@hasDecl(peripherals, "GPIOD")) peripherals.GPIOD else @panic("Invalid Pin"), - 4 => return if (@hasDecl(peripherals, "GPIOE")) peripherals.GPIOE else @panic("Invalid Pin"), - 5 => return if (@hasDecl(peripherals, "GPIOF")) peripherals.GPIOF else @panic("Invalid Pin"), - 6 => return if (@hasDecl(peripherals, "GPIOG")) peripherals.GPIOG else @panic("Invalid Pin"), - else => @panic("The STM32 only has ports 0..6 (A..G)"), - } - } - - pub inline fn set_bias(gpio: Pin, bias: PUPDR) void { - const port = gpio.get_port(); - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - const modMask: u32 = gpio.mask_2bit(); - - port.PUPDR.write_raw((port.PUPDR.raw & ~modMask) | @as(u32, @intFromEnum(bias)) << (pin << 1)); - } - - pub inline fn set_speed(gpio: Pin, speed: OSPEEDR) void { - const port = gpio.get_port(); - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - const modMask: u32 = gpio.mask_2bit(); - - port.OSPEEDR.write_raw((port.OSPEEDR.raw & ~modMask) | @as(u32, @intFromEnum(speed)) << (pin << 1)); - } - - pub inline fn set_moder(gpio: Pin, moder: MODER) void { - const port = gpio.get_port(); - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - const modMask: u32 = gpio.mask_2bit(); - - port.MODER.write_raw((port.MODER.raw & ~modMask) | @as(u32, @intFromEnum(moder)) << (pin << 1)); - } - - pub inline fn set_output_type(gpio: Pin, otype: OT) void { - const port = gpio.get_port(); - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - - port.OTYPER.write_raw((port.OTYPER.raw & ~gpio.mask()) | @as(u32, @intFromEnum(otype)) << pin); - } - - pub inline fn set_alternate_function(gpio: Pin, afr: AF) void { - const port = gpio.get_port(); - const pin: u5 = @intCast(@intFromEnum(gpio) % 16); - const afrMask: u32 = @as(u32, 0b1111) << ((pin % 8) << 2); - const register = if (pin > 7) &port.AFR[1] else &port.AFR[0]; - register.write_raw((register.raw & ~afrMask) | @as(u32, @intFromEnum(afr)) << ((pin % 8) << 2)); - } - - pub fn from_port(port: Port, pin: u4) Pin { - const value: usize = pin + (@as(usize, 16) * @intFromEnum(port)); - return @enumFromInt(value); - } -}; diff --git a/port/stmicro/stm32/src/hals/common/pins_v2.zig b/port/stmicro/stm32/src/hals/common/pins_v2.zig index 198831cfd..6802d72ec 100644 --- a/port/stmicro/stm32/src/hals/common/pins_v2.zig +++ b/port/stmicro/stm32/src/hals/common/pins_v2.zig @@ -4,7 +4,7 @@ const comptimePrint = std.fmt.comptimePrint; const StructField = std.builtin.Type.StructField; const microzig = @import("microzig"); -const enums = @import("../common/enums.zig"); +const util = @import("util.zig"); const Digital_IO = microzig.drivers.base.Digital_IO; const Direction = Digital_IO.Direction; @@ -17,9 +17,63 @@ const State = Digital_IO.State; const gpio_v2 = microzig.chip.types.peripherals.gpio_v2; const PUPDR = gpio_v2.PUPDR; +const MODER = gpio_v2.MODER; +const OSPEEDR = gpio_v2.OSPEEDR; +const OT = gpio_v2.OT; +const AFIO = microzig.chip.peripherals.AFIO; + const rcc = microzig.hal.rcc; +const peripherals = microzig.chip.peripherals; + +pub const Mode = union(enum) { + input: InputMode, + output: OutputMode, + analog: AnalogMode, + alternate_function: AlternateFunctionMode, + digital_io: Digital_IO_Mode, +}; -const gpio = @import("gpio_v2.zig"); +const Digital_IO_Mode = struct {}; + +const InputMode = struct { + resistor: PUPDR, +}; + +const OutputMode = struct { + resistor: PUPDR, + o_type: OT, + o_speed: OSPEEDR = .LowSpeed, +}; + +const AnalogMode = struct { + resistor: PUPDR = .Floating, +}; + +const AF = enum(u4) { + AF0, + AF1, + AF2, + AF3, + AF4, + AF5, + AF6, + AF7, + AF8, + AF9, + AF10, + AF11, + AF12, + AF13, + AF14, + AF15, +}; + +pub const AlternateFunctionMode = struct { + afr: AF, + resistor: PUPDR = .Floating, + o_type: OT = .PushPull, + o_speed: OSPEEDR = .HighSpeed, +}; pub const Pin = enum { PIN0, @@ -40,12 +94,99 @@ pub const Pin = enum { PIN15, pub const Configuration = struct { name: ?[:0]const u8 = null, - mode: ?gpio.Mode = null, + mode: ?Mode = null, }; }; -pub const InputGPIO = struct { - pin: gpio.Pin, +const GPIO_Pin = struct { + pin: Pin, + port: Port, + + inline fn write_pin_config(_gpio: GPIO_Pin, mode: Mode) void { + switch (mode) { + .input => |imode| { + _gpio.set_moder(MODER.Input); + _gpio.set_bias(imode.resistor); + }, + .output => |omode| { + _gpio.set_moder(MODER.Output); + _gpio.set_output_type(omode.o_type); + _gpio.set_bias(omode.resistor); + _gpio.set_speed(omode.o_speed); + }, + .analog => |amode| { + _gpio.set_moder(MODER.Analog); + _gpio.set_bias(amode.resistor); + }, + .alternate_function => |afmode| { + _gpio.set_moder(MODER.Alternate); + _gpio.set_bias(afmode.resistor); + _gpio.set_speed(afmode.o_speed); + _gpio.set_output_type(afmode.o_type); + _gpio.set_alternate_function(afmode.afr); + }, + .digital_io => { + // Nothing for now + }, + } + } + + fn mask_2bit(_gpio: GPIO_Pin) u32 { + const pin: u4 = @intFromEnum(_gpio.pin); + return @as(u32, 0b11) << (pin << 1); + } + + fn mask(_gpio: GPIO_Pin) u32 { + const pin: u4 = @intFromEnum(_gpio.pin); + return @as(u32, 1) << pin; + } + + //NOTE: should invalid pins panic or just be ignored? + fn get_port(_gpio: GPIO_Pin) *volatile gpio_v2.GPIO { + return _gpio.port.get_port(); + } + + inline fn set_bias(_gpio: GPIO_Pin, bias: PUPDR) void { + const port = _gpio.port.get_port(); + const pin: u4 = @intFromEnum(_gpio.pin); + const modMask: u32 = _gpio.mask_2bit(); + + port.PUPDR.write_raw((port.PUPDR.raw & ~modMask) | @as(u32, @intFromEnum(bias)) << (pin << 1)); + } + + inline fn set_speed(_gpio: GPIO_Pin, speed: OSPEEDR) void { + const port = _gpio.port.get_port(); + const pin: u5 = @intFromEnum(_gpio.pin); + const modMask: u32 = _gpio.mask_2bit(); + + port.OSPEEDR.write_raw((port.OSPEEDR.raw & ~modMask) | @as(u32, @intFromEnum(speed)) << (pin << 1)); + } + + inline fn set_moder(_gpio: GPIO_Pin, moder: MODER) void { + const port = _gpio.port.get_port(); + const pin: u5 = @intFromEnum(_gpio.pin); + const modMask: u32 = _gpio.mask_2bit(); + + port.MODER.write_raw((port.MODER.raw & ~modMask) | @as(u32, @intFromEnum(moder)) << (pin << 1)); + } + + inline fn set_output_type(_gpio: GPIO_Pin, otype: OT) void { + const port = _gpio.port.get_port(); + const pin: u5 = @intFromEnum(_gpio.pin); + + port.OTYPER.write_raw((port.OTYPER.raw & ~_gpio.mask()) | @as(u32, @intFromEnum(otype)) << pin); + } + + fn from_port(port: Port, pin: Pin) GPIO_Pin { + return .{ + .port = port, + .pin = pin, + }; + } +}; + +pub const Input_GPIO = struct { + pin: GPIO_Pin, pub inline fn read(self: @This()) u1 { const port = self.pin.get_port(); return if (port.IDR.raw & self.pin.mask() != 0) @@ -55,8 +196,8 @@ pub const InputGPIO = struct { } }; -pub const OutputGPIO = struct { - pin: gpio.Pin, +pub const Output_GPIO = struct { + pin: GPIO_Pin, pub inline fn put(self: @This(), value: u1) void { var port = self.pin.get_port(); @@ -85,11 +226,11 @@ pub const AlternateFunction = struct { }; const Analog = struct { - pin: gpio.Pin, + pin: GPIO_Pin, }; pub const Digital_IO_Pin = struct { - pin: gpio.Pin, + pin: GPIO_Pin, const vtable: Digital_IO.VTable = .{ .set_direction_fn = Digital_IO_Pin.set_direction_fn, .set_bias_fn = Digital_IO_Pin.set_bias_fn, @@ -137,10 +278,10 @@ pub const Digital_IO_Pin = struct { } }; -pub fn GPIO(comptime mode: gpio.Mode) type { +pub fn GPIO(comptime mode: Mode) type { return switch (mode) { - .input => InputGPIO, - .output => OutputGPIO, + .input => Input_GPIO, + .output => Output_GPIO, .alternate_function => AlternateFunction, .analog => Analog, .digital_io => Digital_IO_Pin, @@ -151,6 +292,9 @@ pub fn Pins(comptime config: GlobalConfiguration) type { comptime { var fields: []const StructField = &.{}; for (@typeInfo(GlobalConfiguration).@"struct".fields) |port_field| { + if (port_field.type != ?Port.Configuration) { + continue; + } if (@field(config, port_field.name)) |port_config| { for (@typeInfo(Port.Configuration).@"struct".fields) |field| { if (@field(port_config, field.name)) |pin_config| { @@ -186,14 +330,19 @@ pub fn Pins(comptime config: GlobalConfiguration) type { } } -pub const Port = enum { - GPIOA, - GPIOB, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - GPIOG, +pub const Port = enum(u8) { + GPIOA = if (util.has_port('A')) 0 else undefined, + GPIOB = if (util.has_port('B')) 1 else undefined, + GPIOC = if (util.has_port('C')) 2 else undefined, + GPIOD = if (util.has_port('D')) 3 else undefined, + GPIOE = if (util.has_port('E')) 4 else undefined, + GPIOF = if (util.has_port('F')) 5 else undefined, + GPIOG = if (util.has_port('G')) 6 else undefined, + GPIOH = if (util.has_port('H')) 7 else undefined, + GPIOI = if (util.has_port('I')) 8 else undefined, + GPIOJ = if (util.has_port('J')) 9 else undefined, + GPIOK = if (util.has_port('K')) 10 else undefined, + pub const Configuration = struct { PIN0: ?Pin.Configuration = null, PIN1: ?Pin.Configuration = null, @@ -214,21 +363,35 @@ pub const Port = enum { comptime { const pin_field_count = @typeInfo(Pin).@"enum".fields.len; - const config_field_count = @typeInfo(Configuration).@"struct".fields.len; + const config_field_count = @typeInfo(Port.Configuration).@"struct".fields.len; if (pin_field_count != config_field_count) @compileError(comptimePrint("{} {}", .{ pin_field_count, config_field_count })); } }; + + pub fn get_port(port: Port) *volatile gpio_v2.GPIO { + switch (@intFromEnum(port)) { + inline 0...@typeInfo(Port).@"enum".fields.len - 1 => |p| { + const port_id = [_]u8{"ABCDEFGHIJK"[p]}; + return @field(peripherals, "GPIO" ++ port_id); + }, + else => unreachable, + } + } }; pub const GlobalConfiguration = struct { - GPIOA: ?Port.Configuration = null, - GPIOB: ?Port.Configuration = null, - GPIOC: ?Port.Configuration = null, - GPIOD: ?Port.Configuration = null, - GPIOE: ?Port.Configuration = null, - GPIOF: ?Port.Configuration = null, - GPIOG: ?Port.Configuration = null, + GPIOA: ?if (util.has_port('A')) Port.Configuration else undefined = null, + GPIOB: ?if (util.has_port('B')) Port.Configuration else undefined = null, + GPIOC: ?if (util.has_port('C')) Port.Configuration else undefined = null, + GPIOD: ?if (util.has_port('D')) Port.Configuration else undefined = null, + GPIOE: ?if (util.has_port('E')) Port.Configuration else undefined = null, + GPIOF: ?if (util.has_port('F')) Port.Configuration else undefined = null, + GPIOG: ?if (util.has_port('G')) Port.Configuration else undefined = null, + GPIOH: ?if (util.has_port('H')) Port.Configuration else undefined = null, + GPIOI: ?if (util.has_port('I')) Port.Configuration else undefined = null, + GPIOJ: ?if (util.has_port('J')) Port.Configuration else undefined = null, + GPIOK: ?if (util.has_port('K')) Port.Configuration else undefined = null, comptime { const port_field_count = @typeInfo(Port).@"enum".fields.len; @@ -241,23 +404,29 @@ pub const GlobalConfiguration = struct { var ret: Pins(config) = undefined; inline for (@typeInfo(GlobalConfiguration).@"struct".fields) |port_field| { + if (port_field.type != ?Port.Configuration) { + continue; + } if (@field(config, port_field.name)) |_| { - rcc.enable_clock(@field(enums.Peripherals, port_field.name)); + rcc.enable_clock(@field(rcc.Peripherals, port_field.name)); } } inline for (@typeInfo(GlobalConfiguration).@"struct".fields) |port_field| { + if (port_field.type != ?Port.Configuration) { + continue; + } if (@field(config, port_field.name)) |port_config| { inline for (@typeInfo(Port.Configuration).@"struct".fields) |field| { if (@field(port_config, field.name)) |pin_config| { - const port = @intFromEnum(@field(Port, port_field.name)); - var pin = gpio.Pin.from_port(@enumFromInt(port), @intFromEnum(@field(Pin, field.name))); + const port = @field(Port, port_field.name); + var pin = GPIO_Pin.from_port(port, @field(Pin, field.name)); pin.write_pin_config(pin_config.mode.?); const default_name = "P" ++ port_field.name[4..5] ++ field.name[3..]; switch (pin_config.mode orelse .input) { - .input => @field(ret, pin_config.name orelse default_name) = InputGPIO{ .pin = pin }, - .output => @field(ret, pin_config.name orelse default_name) = OutputGPIO{ .pin = pin }, + .input => @field(ret, pin_config.name orelse default_name) = Input_GPIO{ .pin = pin }, + .output => @field(ret, pin_config.name orelse default_name) = Output_GPIO{ .pin = pin }, .analog => @field(ret, pin_config.name orelse default_name) = Analog{}, .alternate_function => @field(ret, pin_config.name orelse default_name) = AlternateFunction{}, .digital_io => @field(ret, pin_config.name orelse default_name) = Digital_IO_Pin{ .pin = pin }, diff --git a/port/stmicro/stm32/src/hals/common/util.zig b/port/stmicro/stm32/src/hals/common/util.zig index 8713df969..ba5b3fe3b 100644 --- a/port/stmicro/stm32/src/hals/common/util.zig +++ b/port/stmicro/stm32/src/hals/common/util.zig @@ -2,6 +2,10 @@ const std = @import("std"); const microzig = @import("microzig"); const peripherals = microzig.chip.peripherals; +pub fn has_port(comptime id: u8) bool { + return @hasDecl(peripherals, "GPIO" ++ &[_]u8{id}); +} + pub fn match_name(heystack: []const u8, needles: []const []const u8) bool { for (needles) |needle| { if (std.mem.indexOf(u8, heystack, needle)) |_| {