const registers = packed struct { moder: u32, otyper: u32, ospeedr: u32, pupdr: u32, idr: u32, odr: u32, bsrr: u32, lckr: u32, afr: u64, brr: u32, ascr: u32, }; const driver = struct { port: *registers, const mode = enum(u32) { alternate_0 = 0, alternate_1, alternate_2, alternate_3, alternate_4, alternate_5, alternate_6, alternate_7, alternate_8, alternate_9, alternate_10, alternate_11, alternate_12, alternate_13, alternate_14, alternate_15, input, output, analog, }; pub fn set_mode(self: driver, pin: u4, m: mode) void { const offset = 2 * @as(u5, pin); const moder = self.port.moder & ~(@as(u32, 3) << offset); const mask: u32 = switch (m) { .input => 0, .output => 1, .analog => 3, else => 2, }; self.port.moder = moder | (mask << offset); if (mask == 2) { const afr_offset = (4 * @as(u6, pin)); const afr = self.port.afr & ~(@as(u64, 0xF) << afr_offset); self.port.afr = afr | (@as(u64, @intFromEnum(m)) << afr_offset); } } pub fn toggle(self: driver, pin: u4) void { self.port.odr ^= @as(u32, 1) << pin; } pub fn set(self: driver, pin: u4) void { self.port.odr |= @as(u32, 1) << pin; } pub fn clear(self: driver, pin: u4) void { self.port.odr &= ~(@as(u32, 1) << pin); } pub fn write(self: driver, pin: u4, val: bool) void { if (val) { self.set(pin); } else { self.clear(pin); } } pub fn read(self: driver, pin: u4) bool { return (self.port.idr & @as(u32, 1) << pin) != 0; } }; pub const gpioa = driver { .port = @ptrFromInt(0x48000000) }; pub const gpiob = driver { .port = @ptrFromInt(0x48000400) }; pub const gpioc = driver { .port = @ptrFromInt(0x48000800) }; pub const gpiod = driver { .port = @ptrFromInt(0x48000C00) }; pub const gpioe = driver { .port = @ptrFromInt(0x48001000) }; pub const gpiof = driver { .port = @ptrFromInt(0x48001400) }; pub const gpiog = driver { .port = @ptrFromInt(0x48001800) }; pub const gpioh = driver { .port = @ptrFromInt(0x48001C00) };