Continues blinky setup.

wch-ch32v003
Felix (xq) Queißner 3 years ago
parent e68a282981
commit 6cdf641f32

@ -17,11 +17,18 @@ pub fn build(b: *std.build.Builder) void {
BuildConfig{ .name = "chips.lpc1768", .backing = Backing{ .chip = pkgs.chips.lpc1768 } },
};
const Test = struct { name: []const u8, source: []const u8 };
const all_tests = [_]Test{
Test{ .name = "minimal", .source = "tests/minimal.zig" },
Test{ .name = "blinky", .source = "tests/blinky.zig" },
};
inline for (all_backings) |cfg| {
inline for (all_tests) |tst| {
const exe = addEmbeddedExecutable(
b,
"test-minimal-" ++ cfg.name,
"tests/minimal.zig",
"test-" ++ tst.name ++ "-" ++ cfg.name,
tst.source,
cfg.backing,
);
exe.setBuildMode(mode);
@ -30,6 +37,7 @@ pub fn build(b: *std.build.Builder) void {
test_step.dependOn(&exe.step);
}
}
}
fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source: []const u8, backing: Backing) *std.build.LibExeObjStep {
const Pkg = std.build.Pkg;
@ -39,6 +47,8 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
.board => |b| b.chip,
};
const has_board = (backing == .board);
const chip_package = Pkg{
.name = "chip",
.path = chip.path,
@ -81,6 +91,58 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
break :blk builder.dupe(filename);
};
const config_file_name = blk: {
const hash = hash_blk: {
var hasher = std.hash.SipHash128(1, 2).init("abcdefhijklmnopq");
hasher.update(chip.name);
hasher.update(chip.path);
hasher.update(chip.cpu.name);
hasher.update(chip.cpu.path);
if (backing == .board) {
hasher.update(backing.board.name);
hasher.update(backing.board.path);
}
var mac: [16]u8 = undefined;
hasher.final(&mac);
break :hash_blk mac;
};
const file_prefix = "zig-cache/microzig/config-";
const file_suffix = ".zig";
var ld_file_name: [file_prefix.len + 2 * hash.len + file_suffix.len]u8 = undefined;
const filename = std.fmt.bufPrint(&ld_file_name, "{s}{}{s}", .{
file_prefix,
std.fmt.fmtSliceHexLower(&hash),
file_suffix,
}) catch unreachable;
break :blk builder.dupe(filename);
};
{
var config_file = std.fs.cwd().createFile(config_file_name, .{}) catch unreachable;
defer config_file.close();
var writer = config_file.writer();
writer.print("pub const has_board = {};\n", .{has_board}) catch unreachable;
if (has_board) {
writer.print("pub const board_name = \"{}\";\n", .{std.fmt.fmtSliceEscapeUpper(backing.board.name)}) catch unreachable;
}
writer.print("pub const chip_name = \"{}\";\n", .{std.fmt.fmtSliceEscapeUpper(chip.name)}) catch unreachable;
writer.print("pub const cpu_name = \"{}\";\n", .{std.fmt.fmtSliceEscapeUpper(chip.cpu.name)}) catch unreachable;
}
const config_pkg = Pkg{
.name = "microzig-config",
.path = config_file_name,
};
const linkerscript_gen = builder.addExecutable("linkerscript-gen", "src/tools/linkerscript-gen.zig");
linkerscript_gen.addPackage(chip_package);
linkerscript_gen.addPackage(Pkg{
@ -113,24 +175,18 @@ fn addEmbeddedExecutable(builder: *std.build.Builder, name: []const u8, source:
switch (backing) {
.chip => {
exe.addBuildOption(bool, "microzig_has_board", false);
exe.addBuildOption([]const u8, "microzig_chip_name", chip.name);
exe.addBuildOption([]const u8, "microzig_cpu_name", chip.cpu.name);
exe.addPackage(Pkg{
.name = "microzig",
.path = "src/core/microzig.zig",
.dependencies = &[_]Pkg{chip_package},
.dependencies = &[_]Pkg{ config_pkg, chip_package },
});
},
.board => |board| {
exe.addBuildOption(bool, "microzig_has_board", true);
exe.addBuildOption([]const u8, "microzig_board_name", board.name);
exe.addBuildOption([]const u8, "microzig_chip_name", chip.name);
exe.addBuildOption([]const u8, "microzig_cpu_name", chip.cpu.name);
exe.addPackage(Pkg{
.name = "microzig",
.path = "src/core/microzig.zig",
.dependencies = &[_]Pkg{
config_pkg,
chip_package,
Pkg{
.name = "board",

@ -1,2 +1,124 @@
const std = @import("std");
const micro = @import("microzig.zig");
const chip = @import("chip");
pub const Mode = enum {
input,
output,
input_output,
open_drain,
generic,
};
pub const State = enum(u1) {
low = 0,
high = 1,
};
pub const Drive = enum(u1) {
disabled = 0,
enabled = 1,
};
pub const Direction = enum(u1) {
input = 0,
output = 1,
};
pub fn Gpio(comptime pin: type, config: anytype) type {
const mode = @as(Mode, config.mode);
const Generic = struct {
// all pins:
fn init() void {
switch (mode) {
.input, .generic, .input_output => {
setDirection(.input, undefined);
},
.output => {
if (comptime !@hasField(@TypeOf(config), "initial_state"))
@compileError("An output pin requires initial_state to be either .high or .low");
setDirection(.output, switch (config.initial_state) {
.low => State.low,
.high => State.high,
else => @compileError("An output pin requires initial_state to be either .high or .low"),
});
},
.open_drain => {
if (comptime !@hasField(@TypeOf(config), "initial_state"))
@compileError("An open_drain pin requires initial_state to be either .floating or .driven");
setDirection(.input, undefined);
setDrive(switch (config.initial_state) {
.floating => Drive.disabled,
.driven => Drive.enabled,
else => @compileError("An open_drain pin requires initial_state to be either .floating or .driven"),
});
},
}
}
fn read() State {
return @intToEnum(State, chip.gpio.read(pin.source_pin));
}
// outputs:
fn write(state: State) void {
chip.gpio.write(pin.source_pin, @enumToInt(state));
}
fn setToHigh() void {
write(.high);
}
fn setToLow() void {
write(.low);
}
fn toggle() void {
if (comptime @hasDecl(chip.gpio, "toggle")) {
chip.gpio.toggle(pin.source_pin);
} else {
write(switch (read()) {
.low => State.high,
.high => State.low,
});
}
}
// bi-di:
fn setDirection(dir: Direction, output_state: State) void {}
fn getDirection() Direction {}
// open drain
fn setDrive(drive: Drive) void {}
fn getDrive() Drive {}
};
// return only a subset of Generic for the requested pin.
switch (mode) {
.input => return struct {
pub const init = Generic.init;
pub const read = Generic.read;
},
.output => return struct {
pub const init = Generic.init;
pub const read = Generic.read;
pub const write = Generic.write;
pub const setToHigh = Generic.setToHigh;
pub const setToLow = Generic.setToLow;
pub const toggle = Generic.toggle;
},
.input_output => return struct {
pub const init = Generic.init;
pub const read = Generic.read;
pub const write = Generic.write;
pub const setToHigh = Generic.setToHigh;
pub const setToLow = Generic.setToLow;
pub const setDirection = Generic.setDirection;
pub const getDirection = Generic.getDirection;
},
.open_drain => return struct {
pub const init = Generic.init;
pub const read = Generic.read;
pub const setDrive = Generic.setDrive;
pub const getDrive = Generic.getDrive;
},
.generic => Generic,
}
}

@ -1,6 +1,11 @@
const std = @import("std");
const root = @import("root");
/// Contains build-time generated configuration options for microzig.
/// Contains a CPU target description, chip, board and cpu information
/// and so on.
pub const config = @import("microzig-config");
/// Provides access to the low level features of the current microchip.
pub const chip = @import("chip");
@ -10,6 +15,12 @@ pub const cpu = chip.cpu;
/// Module that helps with interrupt handling.
pub const interrupts = @import("interrupts.zig");
const gpio = @import("gpio.zig");
pub const Gpio = gpio.Gpio;
const pin = @import("pin.zig");
pub const Pin = pin.Pin;
/// The microzig panic handler. Will disable interrupts and loop endlessly.
/// Export this symbol from your main file to enable microzig:
/// ```

@ -1,2 +1,34 @@
const std = @import("std");
const micro = @import("microzig.zig");
const chip = @import("chip");
const board = @import("board");
/// Returns a type that will manage the Pin defined by `spec`.
/// Spec is either the pin as named in the datasheet of the chip
/// or, if a board is present, as named on the board.
///
/// When a name conflict happens, pin names can be prefixed with `board:`
/// to force-select a pin from the board and with `chip:` to force-select
/// the pin from the chip.
pub fn Pin(comptime spec: []const u8) type {
// TODO: Depened on board and chip here
// Pins can be namespaced with "Board:" for board and "Chip:" for chip
const pin = if (std.mem.startsWith(u8, spec, "board:"))
chip.parsePin(@field(board.pin_map, spec))
else if (std.mem.startsWith(u8, spec, "chip:"))
chip.parsePin(spec)
else if (micro.config.has_board and @hasField(@TypeOf(board.pin_map), spec))
chip.parsePin(@field(board.pin_map, spec))
else
chip.parsePin(spec);
return struct {
pub const name = spec;
pub const source_pin = pin;
pub fn route(target: pin.Targets) void {
unreachable;
}
};
}

@ -1,6 +1,49 @@
pub const chip = @import("chip");
pub const chip = @import("chip");
pub const pin_map = .{
// TODO: Fill this
// Onboard-LEDs
.@"LED-1" = "P1.18",
.@"LED-2" = "P1.20",
.@"LED-3" = "P1.21",
.@"LED-4" = "P1.23",
.@"LED_LINK" = "P1.25",
.@"LED_SPEED" = "P1.26",
// Ethernet
.@"TD+" = "P1.0",
.@"TD-" = "P1.1",
.@"RD+" = "P1.9",
.@"RD-" = "P1.10",
// USB
.@"D+" = "P0.29",
.@"D-" = "P0.30",
// GPIO pins
.@"DIP5" = "P0.9",
.@"DIP6" = "P0.8",
.@"DIP7" = "P0.7",
.@"DIP8" = "P0.6",
.@"DIP9" = "P0.0",
.@"DIP10" = "P0.1",
.@"DIP11" = "P0.18",
.@"DIP12" = "P0.17",
.@"DIP13" = "P0.15",
.@"DIP14" = "P0.16",
.@"DIP15" = "P0.23",
.@"DIP16" = "P0.24",
.@"DIP17" = "P0.25",
.@"DIP18" = "P0.26",
.@"DIP19" = "P1.30",
.@"DIP20" = "P1.31",
.@"DIP21" = "P2.5",
.@"DIP22" = "P2.4",
.@"DIP23" = "P2.3",
.@"DIP24" = "P2.2",
.@"DIP25" = "P2.1",
.@"DIP26" = "P2.0",
.@"DIP27" = "P0.11",
.@"DIP28" = "P0.10",
.@"DIP29" = "P0.5",
.@"DIP30" = "P0.4",
};

@ -1,3 +1,4 @@
const std = @import("std");
const micro_linker = @import("microzig-linker");
pub const cpu = @import("cpu");
@ -6,3 +7,48 @@ pub const memory_regions = [_]micro_linker.MemoryRegion{
micro_linker.MemoryRegion{ .offset = 0x000000, .length = 32 * 1024, .kind = .flash },
micro_linker.MemoryRegion{ .offset = 0x800100, .length = 2048, .kind = .ram },
};
pub fn parsePin(comptime spec: []const u8) type {
const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}.{Pin}\" scheme.";
if (spec.len != 3)
@compileError(invalid_format_msg);
if (spec[0] != 'P')
@compileError(invalid_format_msg);
return struct {
pub const port: u8 = std.ascii.toUpper(spec[1]) - 'A';
pub const pin: u3 = @intCast(u3, spec[2] - '0');
};
}
pub const gpio = struct {
fn dirReg(comptime pin: type) *volatile u8 {
return @intToPtr(*volatile u8, 0x01);
}
fn portReg(comptime pin: type) *volatile u8 {
return @intToPtr(*volatile u8, 0x01);
}
fn pinReg(comptime pin: type) *volatile u8 {
return @intToPtr(*volatile u8, 0x01);
}
pub fn read(comptime pin: type) u1 {
return if ((pinReg(pin).* & (1 << pin.pin)) != 0)
@as(u1, 1)
else
0;
}
pub fn write(comptime pin: type, state: u1) void {
if (state == 1) {
portReg(pin).* |= (1 << pin.pin);
} else {
portReg(pin).* &= ~@as(u8, 1 << pin.pin);
}
}
pub fn toggle(comptime pin: type) void {
portReg(pin).* ^= (1 << pin.pin);
}
};

@ -1,3 +1,4 @@
const std = @import("std");
const micro_linker = @import("microzig-linker");
pub const cpu = @import("cpu");
@ -7,3 +8,49 @@ pub const memory_regions = [_]micro_linker.MemoryRegion{
micro_linker.MemoryRegion{ .offset = 0x10000000, .length = 32 * 1024, .kind = .ram },
micro_linker.MemoryRegion{ .offset = 0x2007C000, .length = 32 * 1024, .kind = .ram },
};
pub fn parsePin(comptime spec: []const u8) type {
const invalid_format_msg = "The given pin '" ++ spec ++ "' has an invalid format. Pins must follow the format \"P{Port}.{Pin}\" scheme.";
if (spec[0] != 'P')
@compileError(invalid_format_msg);
const index = std.mem.indexOfScalar(u8, spec, '.') orelse @compileError(invalid_format_msg);
return struct {
pub const port: u3 = std.fmt.parseInt(u3, spec[1..index], 10) catch @compileError(invalid_format_msg);
pub const pin: u5 = std.fmt.parseInt(u5, spec[index + 1 ..], 10) catch @compileError(invalid_format_msg);
const gpio_register = @intToPtr(*volatile registers.GPIO, registers.gpio_base + 0x20 * @as(u32, port));
const gpio_mask: u32 = (1 << pin);
};
}
pub const gpio = struct {
pub fn read(comptime pin: type) u1 {
return if ((pin.gpio_register.pin & pin.gpio_mask) != 0)
@as(u1, 1)
else
0;
}
pub fn write(comptime pin: type, state: u1) void {
if (state == 1) {
pin.gpio_register.set = pin.gpio_mask;
} else {
pin.gpio_register.clr = pin.gpio_mask;
}
}
};
pub const registers = 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;
};

@ -0,0 +1,37 @@
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 led_pin = switch (@import("builtin").cpu.arch) {
.avr => if (micro.config.has_board)
micro.Pin("D13")
else
micro.Pin("PB5"),
.arm => if (micro.config.has_board)
micro.Pin("LED-1")
else
micro.Pin("P1.18"),
else => @compileError("Unsupported platform!"),
};
pub fn main() void {
const led = micro.Gpio(led_pin, .{
.mode = .output,
.initial_state = .low,
});
led.init();
while (true) {
busyloop();
led.toggle();
}
}
fn busyloop() void {
var i: u24 = 0;
while (i < 100_000) : (i += 1) {
@import("std").mem.doNotOptimizeAway(i);
}
}
Loading…
Cancel
Save