More improvements (#37)

* Makes AVR UART work.
* Some comment. This is definitly not padding.
* Exports panic, log and log_level from application.
* Implements generic quadrature decoder driver.
* Fixes `@export` bug in AVR interrupt logic. Now we get distinct interrupt vectors.

Co-authored-by: Felix "xq" Queißner <git@masterq32.de>
wch-ch32v003
Felix Queißner 3 years ago committed by GitHub
parent d3c539e35b
commit f317ce0c9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,6 +13,10 @@ pub const Mode = enum {
pub const State = enum(u1) {
low = 0,
high = 1,
pub fn value(self: State) u1 {
return @enumToInt(self);
}
};
pub const Drive = enum(u1) {

@ -46,13 +46,30 @@ pub const debug = @import("debug.zig");
pub const mmio = @import("mmio.zig");
/// The microzig panic handler. Will disable interrupts and loop endlessly.
/// Export this symbol from your main file to enable microzig:
/// ```
/// const micro = @import("microzig");
/// pub const panic = micro.panic;
/// ```
pub fn panic(message: []const u8, maybe_stack_trace: ?*std.builtin.StackTrace) noreturn {
// Allow app to override the panic handler
pub const panic = if (@hasDecl(app, "panic"))
app.panic
else
microzig_panic;
// Conditionally export log_level if the app has it defined.
usingnamespace if (@hasDecl(app, "log_level"))
struct {
pub const log_level = app.log_level;
}
else
struct {};
// Conditionally export log() if the app has it defined.
usingnamespace if (@hasDecl(app, "log"))
struct {
pub const log = app.log;
}
else
struct {};
/// The microzig default panic handler. Will disable interrupts and loop endlessly.
pub fn microzig_panic(message: []const u8, maybe_stack_trace: ?*std.builtin.StackTrace) noreturn {
// utilize logging functions
std.log.err("microzig PANIC: {s}", .{message});

@ -0,0 +1,50 @@
const micro = @import("microzig");
pub const Event = enum {
/// No change since the last decoding happened
idle,
/// The quadrature signal incremented a step.
increment,
/// The quadrature signal decremented a step.
decrement,
/// The quadrature signal skipped a sequence point and entered a invalid state.
@"error",
};
pub fn Decoder(comptime pin_a: type, comptime pin_b: type) type {
return struct {
const Self = @This();
last_a: micro.gpio.State,
last_b: micro.gpio.State,
pub fn init() Self {
pin_a.init();
pin_b.init();
return Self{
.last_a = pin_a.read(),
.last_b = pin_b.read(),
};
}
pub fn tick(self: *Self) Event {
var a = pin_a.read();
var b = pin_b.read();
defer self.last_a = a;
defer self.last_b = b;
const enable = a.value() ^ b.value() ^ self.last_a.value() ^ self.last_b.value();
const direction = a.value() ^ self.last_b.value();
if (enable != 0) {
if (direction != 0) {
return .increment;
} else {
return .decrement;
}
} else {
return .idle;
}
}
};
}

@ -181,3 +181,12 @@ const pkgs = struct {
.path = .{ .path = root_path ++ "core/import-package.zig" },
};
};
/// Generic purpose drivers shipped with microzig
pub const drivers = struct {
pub const quadrature = std.build.Pkg{
.name = "microzig.quadrature",
.path = .{ .path = root_path ++ "drivers/quadrature.zig" },
.dependencies = &.{pkgs.microzig},
};
};

@ -52,27 +52,10 @@ pub const vector_table = blk: {
const new_insn = if (has_interrupts) overload: {
if (@hasDecl(microzig.app.interrupts, field.name)) {
const handler = @field(microzig.app.interrupts, field.name);
const calling_convention = switch (@typeInfo(@TypeOf(@field(microzig.app.interrupts, field.name)))) {
.Fn => |info| info.calling_convention,
else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ field.name ++ "' is not a function"),
};
const exported_fn = switch (calling_convention) {
.Unspecified => struct {
fn wrapper() callconv(.Signal) void {
if (calling_convention == .Unspecified) // TODO: workaround for some weird stage1 bug
@call(.{ .modifier = .always_inline }, handler, .{});
}
}.wrapper,
.Signal => handler,
.Interrupt => handler,
else => @compileError("Calling conventions for interrupts must be 'Interrupt', 'Signal', or unspecified. The signal calling convention leaves global interrupts disabled during the ISR, where the interrupt calling conventions enables global interrupts for nested ISRs."),
};
const exported_name = "microzig_isr_" ++ field.name;
const options = .{ .name = exported_name, .linkage = .Strong };
@export(exported_fn, options);
break :overload "jmp " ++ exported_name;
const isr = makeIsrHandler(field.name, handler);
break :overload "jmp " ++ isr.exported_name;
} else {
break :overload "jmp microzig_unhandled_vector";
}
@ -90,6 +73,31 @@ pub const vector_table = blk: {
break :blk T._start;
};
fn makeIsrHandler(comptime name: []const u8, comptime func: anytype) type {
const calling_convention = switch (@typeInfo(@TypeOf(func))) {
.Fn => |info| info.calling_convention,
else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ name ++ "' is not a function"),
};
switch (calling_convention) {
.Unspecified, .Signal, .Interrupt => {},
else => @compileError("Calling conventions for interrupts must be 'Interrupt', 'Signal', or unspecified. The signal calling convention leaves global interrupts disabled during the ISR, where the interrupt calling conventions enables global interrupts for nested ISRs."),
}
return struct {
pub const exported_name = "microzig_isr_" ++ name;
pub fn isr_vector() callconv(.Signal) void {
@call(.{ .modifier = .always_inline }, func, .{});
}
comptime {
const options = .{ .name = exported_name, .linkage = .Strong };
@export(isr_vector, options);
}
};
}
pub const startup_logic = struct {
export fn microzig_unhandled_vector() callconv(.Naked) noreturn {
@panic("Unhandled interrupt");

Loading…
Cancel
Save