Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C: Work around STM32 code generation bug #152

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/core/experimental/i2c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@ const std = @import("std");
const hal = @import("hal");
const cfg = @import("config");

/// This says whether or not (we think) code generation fails on returning an empty struct,
/// which was observed on ATmega328P and STM32F303.
/// There presumably is a more precise builtin.target-based check for this.
///
/// As @PhilippWendel says in https://github.com/ZigEmbeddedGroup/microzig/pull/125,
/// not passing around an empty struct
///
/// > prevents the controller from hanging/crash when running this line
/// > ```
/// > const i2c = try interfaces.i2c.I2CController(0, .{}).init(.{ .target_speed = 400_000 });
/// > ```
/// > I think this is caused because the struct that is returned contains just functions
/// > so it has size 0 and clangs avr code gen cant handle that properly.
///
/// And the same seems to happen for at least STM32. -- @marnix Klooster
const codegen_fails_on_empty_struct =
std.mem.eql(u8, cfg.chip_name[0..2], "AT") or
std.mem.eql(u8, cfg.chip_name[0..5], "STM32");

pub fn I2CController(comptime index: usize, comptime pins: Pins) type {
const SystemI2CController = hal.I2CController(index, pins);

Expand Down Expand Up @@ -128,7 +147,8 @@ pub fn I2CController(comptime index: usize, comptime pins: Pins) type {
const Self = @This();

internal: SystemI2CController,
variable_so_struct_is_not_of_size_zero_and_mcu_hangs_when_returning_struct_on_avr: if (std.mem.eql(u8, cfg.chip_name, "ATmega328P")) u8 else void = undefined,

dummy: if (@sizeOf(SystemI2CController) == 0 and codegen_fails_on_empty_struct) u8 else void = undefined,

pub fn init(config: Config) InitError!Self {
return Self{
Expand Down
4 changes: 3 additions & 1 deletion src/mmio.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ pub fn Mmio(comptime PackedT: type) type {
pub const underlying_type = PackedT;

pub inline fn read(addr: *volatile Self) PackedT {
return @bitCast(addr.raw);
const result: PackedT = @bitCast(addr.raw);
std.mem.doNotOptimizeAway(result); // work around https://github.com/ziglang/zig/issues/17882
return result;
}

pub inline fn write(addr: *volatile Self, val: PackedT) void {
Expand Down