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);
pub const Function = enum(u5) {
xip,
xip = 0,
spi,
uart,
i2c,

@ -1,6 +1,8 @@
const std = @import("std");
const gpio = @import("gpio.zig");
const pwm = @import("pwm.zig");
const adc = @import("adc.zig");
const resets = @import("resets.zig");
const regs = @import("microzig").chip.registers;
const assert = std.debug.assert;
@ -59,6 +61,8 @@ pub const Pin = enum {
.out
else if (comptime config.function.isUartRx())
.in
else if (comptime config.function.isAdc())
.in
else
@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 {
return switch (function) {
.PWM0_A,
@ -322,54 +337,67 @@ pub fn GPIO(comptime num: u5, comptime direction: gpio.Direction) type {
}
pub fn Pins(comptime config: GlobalConfiguration) type {
const count = count: {
var ret: usize = 0;
inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config|
if (pin_config.function == .SIO or pin_config.function.isPwm()) {
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),
comptime {
var fields: []const StructField = &.{};
for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config| {
var pin_field = StructField{
.is_comptime = false,
.default_value = null,
.alignment = 1,
// initialized below:
.name = undefined,
.field_type = undefined,
.alignment = undefined,
};
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()) {
fields[i] = StructField{
.name = pin_config.name orelse @tagName(pin_config.function),
.field_type = pwm.PWM(pin_config.function.pwmSlice(), pin_config.function.pwmChannel()),
.is_comptime = false,
.default_value = null,
.alignment = 1,
};
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;
}
i += 1;
};
// 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(.{
.Struct = .{
.layout = .Auto,
.is_tuple = false,
.fields = &fields,
.fields = fields,
.decls = &.{},
},
});
}
}
pub const GlobalConfiguration = struct {
GPIO0: ?Pin.Configuration = null,
@ -413,6 +441,8 @@ pub const GlobalConfiguration = struct {
pub fn apply(comptime config: GlobalConfiguration) Pins(config) {
comptime var input_gpios: u32 = 0;
comptime var output_gpios: u32 = 0;
comptime var has_adc = false;
comptime var has_pwm = false;
// validate selected function
comptime {
@ -422,12 +452,22 @@ pub const GlobalConfiguration = struct {
if (0 == function_table[@enumToInt(pin_config.function)][gpio_num])
@compileError(comptimePrint("{s} cannot be configured for {}", .{ field.name, pin_config.function }));
if (pin_config.function == .SIO) {
switch (pin_config.getDirection()) {
.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
const used_gpios = comptime input_gpios | output_gpios;
@ -436,11 +476,38 @@ pub const GlobalConfiguration = struct {
if (used_gpios != 0) {
regs.SIO.GPIO_OE_CLR.raw = used_gpios;
regs.SIO.GPIO_OUT_CLR.raw = used_gpios;
}
comptime var i: u32 = 0;
inline while (i < 32) : (i += 1)
if (0 != used_gpios & 1 << i)
gpio.setFunction(i, .sio);
inline for (@typeInfo(GlobalConfiguration).Struct.fields) |field| {
if (@field(config, field.name)) |pin_config| {
const gpio_num = @enumToInt(@field(Pin, field.name));
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)
@ -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
// 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|
inline for (@typeInfo(Pins(config)).Struct.fields) |field| {
if (field.default_value) |default_value| {
@field(ret, field.name) = @ptrCast(*const field.field_type, default_value).*;
} else {
@field(ret, field.name) = .{};
}
}
return ret;
}

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

Loading…
Cancel
Save