Designs the basic uart frontend.

wch-ch32v003
Felix (xq) Queißner 3 years ago
parent f5bc3be1ae
commit deb9c3fe03

@ -21,6 +21,7 @@ pub fn build(b: *std.build.Builder) void {
const all_tests = [_]Test{
Test{ .name = "minimal", .source = "tests/minimal.zig" },
Test{ .name = "blinky", .source = "tests/blinky.zig" },
Test{ .name = "uart-sync", .source = "tests/uart-sync.zig" },
};
const filter = b.option(std.Target.Cpu.Arch, "filter-target", "Filters for a certain cpu target");

@ -0,0 +1,20 @@
const std = @import("std");
const root = @import("root");
/// Is `true` when microzig has a clock frequency available.
pub const has_clock = @hasDecl(root, "cpu_frequency");
/// Returns `true` when the frequency can change at runtime.
pub const is_dynamic = has_clock and !@typeInfo(@TypeOf(&root.cpu_frequency)).Pointer.is_const;
/// Ensures that microzig has a clock available. This will @compileError when no clock is available, otherwise, it will be a no-op.
pub fn ensure() void {
if (!has_clock)
@compileError("microzig requires the clock frequency to perform this operation. Please export a const or var cpu_frequency from your root file that contains the cpu frequency in hertz!");
}
/// Returns the current cpu frequency in hertz.
pub fn get() callconv(.Inline) u32 {
ensure();
return root.cpu_frequency;
}

@ -15,12 +15,18 @@ pub const cpu = chip.cpu;
/// Module that helps with interrupt handling.
pub const interrupts = @import("interrupts.zig");
/// Module that provides clock related functions
pub const clock = @import("clock.zig");
const gpio = @import("gpio.zig");
pub const Gpio = gpio.Gpio;
const pin = @import("pin.zig");
pub const Pin = pin.Pin;
const uart = @import("uart.zig");
pub const Uart = uart.Uart;
/// The microzig panic handler. Will disable interrupts and loop endlessly.
/// Export this symbol from your main file to enable microzig:
/// ```
@ -72,7 +78,7 @@ export fn microzig_main() noreturn {
// - Compute maximum size on the type of "err"
// - Do not emit error names when std.builtin.strip is set.
var msg: [64]u8 = undefined;
@panic(std.fmt.bufPrint(&msg, "main() returned error {s}", .{@tagName(err)}) catch @panic("main() returned error."));
@panic(std.fmt.bufPrint(&msg, "main() returned error {s}", .{@errorName(err)}) catch @panic("main() returned error."));
};
} else {
main();

@ -1,3 +1,4 @@
const std = @import("std");
pub fn mmio(addr: usize, comptime size: u8, comptime PackedT: type) *volatile MMIO(size, PackedT) {

@ -0,0 +1,73 @@
const std = @import("std");
const micro = @import("microzig.zig");
const chip = @import("chip");
/// A UART configuration. The config defaults to the *8N1* setting, so "8 data bits, no parity, 1 stop bit" which is the
/// most common serial format.
pub const Config = struct {
baud_rate: u32,
stop_bits: StopBits = .one,
parity: Parity = .none,
data_bits: DataBits = .@"8",
};
const DataBits = enum {
@"5",
@"6",
@"7",
@"8",
@"9",
};
const StopBits = enum { one, two };
const Parity = enum {
none,
even,
odd,
mark,
space,
};
pub fn Uart(comptime index: usize) type {
return struct {
const Self = @This();
/// Initializes the UART with the given config and returns a handle to the uart.
pub fn init(config: Config) Self {
micro.clock.ensure();
return Self{};
}
pub fn reader(self: Self) Reader {
return Reader{ .context = self };
}
pub fn writer(self: Self) Writer {
return Writer{ .context = self };
}
const ReadError = error{
/// The input buffer received a byte while the receive fifo is already full.
/// Devices with no fifo fill overrun as soon as a second byte arrives.
Overrun,
/// A byte with an invalid parity bit was received.
ParityError,
/// The stop bit of our byte was not valid.
FramingError,
/// The break interrupt error will happen when RXD is logic zero for
/// the duration of a full byte.
BreakInterrupt,
};
const WriteError = error{};
pub const Reader = std.io.Reader(Self, ReadError, readSome);
pub const Writer = std.io.Writer(Self, WriteError, writeSome);
fn readSome(self: Self, buffer: []u8) ReadError!usize {
return 0;
}
fn writeSome(self: Self, buffer: []const u8) WriteError!usize {
return 0;
}
};
}

@ -61,14 +61,3 @@ pub const gpio = struct {
}
}
};
// pub const GPIO = extern struct {
// dir: u32, // 0x00
// pad: [3]u32,
// mask: u32, // 0x10
// pin: u32, // 0x14,
// set: u32, // 0x18,
// clr: u32, // 0x1C,
// };
// pub const gpio_base = 0x2009_C000;

@ -6,13 +6,13 @@ pub const panic = micro.panic;
// Configures the led_pin to a hardware pin
const led_pin = switch (@import("builtin").cpu.arch) {
.avr => if (micro.config.has_board)
micro.Pin("D13")
micro.Pin("D13") // Use D13 from Arduino Nano
else
micro.Pin("PB5"),
micro.Pin("PB5"), // Use PB5 on raw ATmega328p
.arm => if (micro.config.has_board)
micro.Pin("LED-1")
micro.Pin("LED-1") // Use LED-1 from mbed LPC1768
else
micro.Pin("P1.18"),
micro.Pin("P1.18"), // Use P1.18 on raw LPC1768
else => @compileError("Unsupported platform!"),
};

@ -0,0 +1,31 @@
const micro = @import("microzig");
// this will instantiate microzig and pull in all dependencies
pub const panic = micro.panic;
// Configures the led_pin to a hardware pin
const uart_txd_pin = micro.Pin("P0.15");
const uart_rxd_pin = micro.Pin("P0.16");
pub const cpu_frequency: u32 = 10_000_000; // 10 MHz
pub fn main() !void {
var debug_port = micro.Uart(0).init(.{
.baud_rate = 9600,
.stop_bits = .one,
.parity = .none, // { none, even, odd, mark, space }
.data_bits = .@"8", // 5, 6, 7, 8, or 9 data bits
});
var out = debug_port.writer();
var in = debug_port.reader();
try out.writeAll("Please enter a sentence:\r\n");
while (true) {
try out.writeAll("> ");
var line_buffer: [64]u8 = undefined;
const line = (try in.readUntilDelimiterOrEof(&line_buffer, '\r')).?;
try out.writeAll(line);
}
}
Loading…
Cancel
Save