Implements ADC and PWM support in pin config, simplifies Pins() type.

wch-ch32v003
Felix "xq" Queißner 2 years ago
parent 5c07800cdb
commit 86d383e673

@ -7,7 +7,7 @@ const assert = std.debug.assert;
const log = std.log.scoped(.gpio); const log = std.log.scoped(.gpio);
pub const Function = enum(u5) { pub const Function = enum(u5) {
xip, xip = 0,
spi, spi,
uart, uart,
i2c, i2c,

@ -1,6 +1,8 @@
const std = @import("std"); const std = @import("std");
const gpio = @import("gpio.zig"); const gpio = @import("gpio.zig");
const pwm = @import("pwm.zig"); const pwm = @import("pwm.zig");
const adc = @import("adc.zig");
const resets = @import("resets.zig");
const regs = @import("microzig").chip.registers; const regs = @import("microzig").chip.registers;
const assert = std.debug.assert; const assert = std.debug.assert;
@ -59,6 +61,8 @@ pub const Pin = enum {
.out .out
else if (comptime config.function.isUartRx()) else if (comptime config.function.isUartRx())
.in .in
else if (comptime config.function.isAdc())
.in
else else
@panic("TODO"); @panic("TODO");
} }
@ -193,6 +197,17 @@ pub const Function = enum {
}; };
} }
pub fn isAdc(function: Function) bool {
return switch (function) {
.ADC0,
.ADC1,
.ADC2,
.ADC3,
=> true,
else => false,
};
}
pub fn pwmChannel(comptime function: Function) pwm.Channel { pub fn pwmChannel(comptime function: Function) pwm.Channel {
return switch (function) { return switch (function) {
.PWM0_A, .PWM0_A,
@ -322,53 +337,66 @@ pub fn GPIO(comptime num: u5, comptime direction: gpio.Direction) type {
} }
pub fn Pins(comptime config: GlobalConfiguration) type { pub fn Pins(comptime config: GlobalConfiguration) type {
const count = count: { comptime {
var ret: usize = 0; var fields: []const StructField = &.{};
inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| { for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config| if (@field(config, field.name)) |pin_config| {
if (pin_config.function == .SIO or pin_config.function.isPwm()) { var pin_field = StructField{
ret += 1;
};
}
break :count ret;
};
var i: usize = 0;
var fields: [count]StructField = undefined;
inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config|
if (pin_config.function == .SIO) {
fields[i] = StructField{
.name = pin_config.name orelse field.name,
.field_type = GPIO(@enumToInt(@field(Pin, field.name)), pin_config.direction orelse .in),
.is_comptime = false, .is_comptime = false,
.default_value = null, .default_value = null,
.alignment = 1,
};
i += 1; // initialized below:
} else if (pin_config.function.isPwm()) { .name = undefined,
fields[i] = StructField{ .field_type = undefined,
.name = pin_config.name orelse @tagName(pin_config.function), .alignment = undefined,
.field_type = pwm.PWM(pin_config.function.pwmSlice(), pin_config.function.pwmChannel()),
.is_comptime = false,
.default_value = null,
.alignment = 1,
}; };
i += 1; if (pin_config.function == .SIO) {
}; pin_field.name = pin_config.name orelse field.name;
} pin_field.field_type = GPIO(@enumToInt(@field(Pin, field.name)), pin_config.direction orelse .in);
} else if (pin_config.function.isPwm()) {
pin_field.name = pin_config.name orelse @tagName(pin_config.function);
pin_field.field_type = pwm.PWM(pin_config.function.pwmSlice(), pin_config.function.pwmChannel());
} else if (pin_config.function.isAdc()) {
pin_field.name = pin_config.name orelse @tagName(pin_config.function);
pin_field.field_type = adc.Input;
pin_field.default_value = @ptrCast(?*const anyopaque, 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.field_type);
fields = fields ++ &[_]StructField{pin_field};
}
}
return @Type(.{ return @Type(.{
.Struct = .{ .Struct = .{
.layout = .Auto, .layout = .Auto,
.is_tuple = false, .is_tuple = false,
.fields = &fields, .fields = fields,
.decls = &.{}, .decls = &.{},
}, },
}); });
}
} }
pub const GlobalConfiguration = struct { pub const GlobalConfiguration = struct {
@ -413,6 +441,8 @@ pub const GlobalConfiguration = struct {
pub fn apply(comptime config: GlobalConfiguration) Pins(config) { pub fn apply(comptime config: GlobalConfiguration) Pins(config) {
comptime var input_gpios: u32 = 0; comptime var input_gpios: u32 = 0;
comptime var output_gpios: u32 = 0; comptime var output_gpios: u32 = 0;
comptime var has_adc = false;
comptime var has_pwm = false;
// validate selected function // validate selected function
comptime { comptime {
@ -422,12 +452,22 @@ pub const GlobalConfiguration = struct {
if (0 == function_table[@enumToInt(pin_config.function)][gpio_num]) if (0 == function_table[@enumToInt(pin_config.function)][gpio_num])
@compileError(comptimePrint("{s} cannot be configured for {}", .{ field.name, pin_config.function })); @compileError(comptimePrint("{s} cannot be configured for {}", .{ field.name, pin_config.function }));
switch (pin_config.getDirection()) { if (pin_config.function == .SIO) {
.in => input_gpios |= 1 << gpio_num, switch (pin_config.getDirection()) {
.out => output_gpios |= 1 << gpio_num, .in => input_gpios |= 1 << gpio_num,
.out => output_gpios |= 1 << gpio_num,
}
}
if (pin_config.function.isAdc()) {
has_adc = true;
}
if (pin_config.function.isPwm()) {
has_pwm = true;
} }
}; };
} }
// TODO: ensure only one instance of an input function exists // TODO: ensure only one instance of an input function exists
const used_gpios = comptime input_gpios | output_gpios; const used_gpios = comptime input_gpios | output_gpios;
@ -436,11 +476,38 @@ pub const GlobalConfiguration = struct {
if (used_gpios != 0) { if (used_gpios != 0) {
regs.SIO.GPIO_OE_CLR.raw = used_gpios; regs.SIO.GPIO_OE_CLR.raw = used_gpios;
regs.SIO.GPIO_OUT_CLR.raw = used_gpios; regs.SIO.GPIO_OUT_CLR.raw = used_gpios;
}
comptime var i: u32 = 0; inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
inline while (i < 32) : (i += 1) if (@field(config, field.name)) |pin_config| {
if (0 != used_gpios & 1 << i) const gpio_num = @enumToInt(@field(Pin, field.name));
gpio.setFunction(i, .sio); const func = pin_config.function;
// xip = 0,
// spi,
// uart,
// i2c,
// pio0,
// pio1,
// gpck,
// usb,
// @"null" = 0x1f,
if (func == .SIO) {
gpio.setFunction(gpio_num, .sio);
} else if (comptime func.isPwm()) {
gpio.setFunction(gpio_num, .pwm);
} else if (comptime func.isAdc()) {
gpio.setFunction(gpio_num, .@"null");
} else if (comptime func.isUartTx() or func.isUartRx()) {
gpio.setFunction(gpio_num, .uart);
} else {
@compileError(comptime std.fmt.comptimePrint("Unimplemented pin function. Please implement setting pin function {s} for GPIO {}", .{
@tagName(func),
gpio_num,
}));
}
}
} }
if (output_gpios != 0) if (output_gpios != 0)
@ -461,14 +528,25 @@ pub const GlobalConfiguration = struct {
}; };
} }
// TODO: pwm initialization if (has_pwm) {
resets.reset(&.{.pwm});
}
if (has_adc) {
adc.init();
}
// fields in the Pins(config) type should be zero sized, so we just // 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 // default build them all (wasn't sure how to do that cleanly in
// `Pins()` // `Pins()`
var ret: Pins(config) = undefined; var ret: Pins(config) = undefined;
inline for (@typeInfo(Pins(config)).Struct.fields) |field| inline for (@typeInfo(Pins(config)).Struct.fields) |field| {
@field(ret, field.name) = .{}; if (field.default_value) |default_value| {
@field(ret, field.name) = @ptrCast(*const field.field_type, default_value).*;
} else {
@field(ret, field.name) = .{};
}
}
return ret; return ret;
} }

@ -28,8 +28,8 @@ pub const Parity = enum {
pub const Config = struct { pub const Config = struct {
clock_config: clocks.GlobalConfiguration, clock_config: clocks.GlobalConfiguration,
tx_pin: u32, tx_pin: ?u32 = null,
rx_pin: u32, rx_pin: ?u32 = null,
baud_rate: u32, baud_rate: u32,
word_bits: WordBits = .eight, word_bits: WordBits = .eight,
stop_bits: StopBits = .one, stop_bits: StopBits = .one,
@ -116,8 +116,8 @@ pub const UART = enum {
}); });
// TODO comptime assertions // TODO comptime assertions
gpio.setFunction(config.tx_pin, .uart); if (config.tx_pin) |tx_pin| gpio.setFunction(tx_pin, .uart);
gpio.setFunction(config.rx_pin, .uart); if (config.rx_pin) |rx_pin| gpio.setFunction(rx_pin, .uart);
return uart; return uart;
} }

Loading…
Cancel
Save