Skip to content

Commit

Permalink
[RP2xxx] Update pins helper to create pins as comptime-available data…
Browse files Browse the repository at this point in the history
… instead of zero-sized-types (#303)

* Create Runtime-PWM abstraction

* Pins configuration refactor

This refactor maintains one of the very nice properties of the original approach: `pins.led_a` (for example) is comptime known. In order to preserve this property while also having `pins.led_a` be data (i.e. the existing gpio.Pin type) we needed to make pins accessible at comptime—before .apply has been called.

This refactor has a couple of parts
* Move `Pins(comptime config: GlobalConfiguration) type` to `PinsType(self: GlobalConfiguration) type`
* Move the return value from `GlobalConfiguration.apply` to `GlobalConfiguration.pins` (so `.apply` returns `void`. This allows `GlobalConfiguration.pins()` to be called at comptime, which allows sub-values of `pins` to be read at comptime.
* Change pins to be data instead of a type--replace Pwm with the new RuntimePwm and replace pins.GPIO with the existing gpio.Pin. The value of this is set in GlobalConfiguration.pins.

ADC is left broken, since I believe it's broken on main. Will be fixed in a later commit.

* Replace Pwm

* Update examples (and update Pwm again)

* Attempt to update ADC and create comment
  • Loading branch information
MatthiasPortzel authored Dec 19, 2024
1 parent 6207849 commit b07430e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 150 deletions.
4 changes: 3 additions & 1 deletion examples/raspberrypi/rp2xxx/src/blinky.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ const pin_config = rp2xxx.pins.GlobalConfiguration{
},
};

const pins = pin_config.pins();

pub fn main() !void {
const pins = pin_config.apply();
pin_config.apply();

while (true) {
pins.led.toggle();
Expand Down
4 changes: 3 additions & 1 deletion examples/raspberrypi/rp2xxx/src/rp2040_only/pwm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ const pin_config = rp2xxx.pins.GlobalConfiguration{
.GPIO25 = .{ .name = "led", .function = .PWM4_B },
};

const pins = pin_config.pins();

pub fn main() !void {
const pins = pin_config.apply();
pin_config.apply();
pins.led.slice().set_wrap(100);
pins.led.slice().enable();

Expand Down
175 changes: 72 additions & 103 deletions port/raspberrypi/rp2xxx/src/hal/pins.zig
Original file line number Diff line number Diff line change
Expand Up @@ -338,37 +338,49 @@ const function_table = [@typeInfo(Function).Enum.fields.len][30]u1{
single(29), // ADC3
};

pub fn GPIO(comptime num: u5, comptime direction: gpio.Direction) type {
return switch (direction) {
.in => struct {
const pin = gpio.num(num);

pub inline fn read(self: @This()) u1 {
_ = self;
return pin.read();
}
},
.out => struct {
const pin = gpio.num(num);

pub inline fn put(self: @This(), value: u1) void {
_ = self;
pin.put(value);
}

pub inline fn toggle(self: @This()) void {
_ = self;
pin.toggle();
}
},
};
}
pub const GlobalConfiguration = struct {
GPIO0: ?Pin.Configuration = null,
GPIO1: ?Pin.Configuration = null,
GPIO2: ?Pin.Configuration = null,
GPIO3: ?Pin.Configuration = null,
GPIO4: ?Pin.Configuration = null,
GPIO5: ?Pin.Configuration = null,
GPIO6: ?Pin.Configuration = null,
GPIO7: ?Pin.Configuration = null,
GPIO8: ?Pin.Configuration = null,
GPIO9: ?Pin.Configuration = null,
GPIO10: ?Pin.Configuration = null,
GPIO11: ?Pin.Configuration = null,
GPIO12: ?Pin.Configuration = null,
GPIO13: ?Pin.Configuration = null,
GPIO14: ?Pin.Configuration = null,
GPIO15: ?Pin.Configuration = null,
GPIO16: ?Pin.Configuration = null,
GPIO17: ?Pin.Configuration = null,
GPIO18: ?Pin.Configuration = null,
GPIO19: ?Pin.Configuration = null,
GPIO20: ?Pin.Configuration = null,
GPIO21: ?Pin.Configuration = null,
GPIO22: ?Pin.Configuration = null,
GPIO23: ?Pin.Configuration = null,
GPIO24: ?Pin.Configuration = null,
GPIO25: ?Pin.Configuration = null,
GPIO26: ?Pin.Configuration = null,
GPIO27: ?Pin.Configuration = null,
GPIO28: ?Pin.Configuration = null,
GPIO29: ?Pin.Configuration = null,

pub fn Pins(comptime config: GlobalConfiguration) type {
comptime {
const pin_field_count = @typeInfo(Pin).Enum.fields.len;
const config_field_count = @typeInfo(GlobalConfiguration).Struct.fields.len;
if (pin_field_count != config_field_count)
@compileError(comptimePrint("{} {}", .{ pin_field_count, config_field_count }));
}

pub fn PinsType(self: GlobalConfiguration) type {
var fields: []const StructField = &.{};
for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config| {
if (@field(self, field.name)) |pin_config| {
var pin_field = StructField{
.is_comptime = false,
.default_value = null,
Expand All @@ -379,37 +391,17 @@ pub fn Pins(comptime config: GlobalConfiguration) type {
.alignment = undefined,
};

pin_field.name = pin_config.name orelse field.name;
if (pin_config.function == .SIO) {
pin_field.name = pin_config.name orelse field.name;
pin_field.type = GPIO(@intFromEnum(@field(Pin, field.name)), pin_config.direction orelse .in);
pin_field.type = gpio.Pin;
} else if (pin_config.function.is_pwm()) {
pin_field.name = pin_config.name orelse @tagName(pin_config.function);
pin_field.type = pwm.Pwm(pin_config.function.pwm_slice(), pin_config.function.pwm_channel());
pin_field.type = pwm.Pwm;
} else if (pin_config.function.is_adc()) {
pin_field.name = pin_config.name orelse @tagName(pin_config.function);
pin_field.type = adc.Input;
pin_field.default_value = @as(?*const anyopaque, @ptrCast(switch (pin_config.function) {
.ADC0 => &adc.Input.ain0,
.ADC1 => &adc.Input.ain1,
.ADC2 => &adc.Input.ain2,
.ADC3 => &adc.Input.ain3,
else => unreachable,
}));
} else {
continue;
}

// if (pin_field.default_value == null) {
// if (@sizeOf(pin_field.field_type) > 0) {
// pin_field.default_value = @ptrCast(?*const anyopaque, &pin_field.field_type{});
// } else {
// const Struct = struct {
// magic_field: pin_field.field_type = .{},
// };
// pin_field.default_value = @typeInfo(Struct).Struct.fields[0].default_value;
// }
// }

pin_field.alignment = @alignOf(field.type);

fields = fields ++ &[_]StructField{pin_field};
Expand All @@ -425,48 +417,35 @@ pub fn Pins(comptime config: GlobalConfiguration) type {
},
});
}
}

pub const GlobalConfiguration = struct {
GPIO0: ?Pin.Configuration = null,
GPIO1: ?Pin.Configuration = null,
GPIO2: ?Pin.Configuration = null,
GPIO3: ?Pin.Configuration = null,
GPIO4: ?Pin.Configuration = null,
GPIO5: ?Pin.Configuration = null,
GPIO6: ?Pin.Configuration = null,
GPIO7: ?Pin.Configuration = null,
GPIO8: ?Pin.Configuration = null,
GPIO9: ?Pin.Configuration = null,
GPIO10: ?Pin.Configuration = null,
GPIO11: ?Pin.Configuration = null,
GPIO12: ?Pin.Configuration = null,
GPIO13: ?Pin.Configuration = null,
GPIO14: ?Pin.Configuration = null,
GPIO15: ?Pin.Configuration = null,
GPIO16: ?Pin.Configuration = null,
GPIO17: ?Pin.Configuration = null,
GPIO18: ?Pin.Configuration = null,
GPIO19: ?Pin.Configuration = null,
GPIO20: ?Pin.Configuration = null,
GPIO21: ?Pin.Configuration = null,
GPIO22: ?Pin.Configuration = null,
GPIO23: ?Pin.Configuration = null,
GPIO24: ?Pin.Configuration = null,
GPIO25: ?Pin.Configuration = null,
GPIO26: ?Pin.Configuration = null,
GPIO27: ?Pin.Configuration = null,
GPIO28: ?Pin.Configuration = null,
GPIO29: ?Pin.Configuration = null,
// Can be called at comptime or runtime
pub fn pins(comptime self: GlobalConfiguration) self.PinsType() {
var ret: self.PinsType() = undefined;
inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(self, field.name)) |pin_config| {
if (pin_config.function == .SIO) {
@field(ret, pin_config.name orelse field.name) = gpio.num(@intFromEnum(@field(Pin, field.name)));
} else if (pin_config.function.is_pwm()) {
@field(ret, pin_config.name orelse field.name) = pwm.Pwm {
.slice_number = pin_config.function.pwm_slice(),
.channel = pin_config.function.pwm_channel(),
};
} else if (pin_config.function.is_adc()) {
@field(ret, pin_config.name orelse field.name) = @as(adc.Input, @enumFromInt(switch(pin_config.function) {
.ADC0 => 0,
.ADC1 => 1,
.ADC2 => 2,
.ADC3 => 3,
else => unreachable,
}));
}
}
}

comptime {
const pin_field_count = @typeInfo(Pin).Enum.fields.len;
const config_field_count = @typeInfo(GlobalConfiguration).Struct.fields.len;
if (pin_field_count != config_field_count)
@compileError(comptimePrint("{} {}", .{ pin_field_count, config_field_count }));
return ret;
}

pub fn apply(comptime config: GlobalConfiguration) Pins(config) {
pub fn apply(comptime config: GlobalConfiguration) void {
comptime var input_gpios: u32 = 0;
comptime var output_gpios: u32 = 0;
comptime var has_adc = false;
Expand Down Expand Up @@ -525,7 +504,10 @@ pub const GlobalConfiguration = struct {
} else if (comptime func.is_pwm()) {
pin.set_function(.pwm);
} else if (comptime func.is_adc()) {
// Matches adc.Input.configure_gpio_pin
pin.set_function(.disabled);
pin.set_pull(.disabled);
pin.set_input_enabled(false);
} else if (comptime func.is_uart_tx() or func.is_uart_rx()) {
pin.set_function(.uart);
} else if (comptime func.is_spi()) {
Expand Down Expand Up @@ -557,21 +539,8 @@ pub const GlobalConfiguration = struct {
}

if (has_adc) {
adc.init();
}

// fields in the Pins(config) type should be zero sized, so we just
// default build them all (wasn't sure how to do that cleanly in
// `Pins()`
var ret: Pins(config) = undefined;
inline for (@typeInfo(Pins(config)).Struct.fields) |field| {
if (field.default_value) |default_value| {
@field(ret, field.name) = @as(*const field.field_type, @ptrCast(default_value)).*;
} else {
@field(ret, field.name) = .{};
}
// FIXME: https://github.com/ZigEmbeddedGroup/microzig/issues/311
// adc.init();
}

return ret;
}
};
Loading

0 comments on commit b07430e

Please sign in to comment.