add chips and boards (#1)

wch-ch32v003
Matt Knight 2 years ago committed by GitHub
parent 488cb11650
commit 5fb80ada81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
steps:
- group: Build
steps:
- command: zig build
- command: zig build -Doptimize=ReleaseSmall

@ -1,4 +1,4 @@
Copyright (c) 2022 <name>
Copyright (c) 2022 Zig Embedded Group Contributors
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use

@ -1,6 +1,18 @@
= Hardware Support Package Template
= Microchip ATmega Hardware Support Package
1. Update LICENSE file
2. Update `microzig` submodule under `deps/`
3. Add chips/boards/hals
4. Set up buildkite pipeline
Note: for testing, renode supports arduino nano 33 BLE
Currently LLVM is having trouble lowering AVR when this is built in debug mode:
[source]
----
LLVM Emit Object... Don't know how to custom lower this!
UNREACHABLE executed at /Users/mattnite/code/llvm-project-15/llvm/lib/Target/AVR/AVRISelLowering.cpp:842!
----
for now always build in release small:
[source]
----
zig build -Doptimize=ReleaseSmall
----

2
deps/microzig vendored

@ -1 +1 @@
Subproject commit 97ca5497da0f22d025e18bced9311efed088d893
Subproject commit 2d0ee5c4731de1d81afb9c8e08ba4e8c2c2cfbf3

@ -1,6 +1,19 @@
const std = @import("std");
const microzig = @import("../deps/microzig/src/main.zig");
const micro = @import("../deps/microzig/src/main.zig");
const chips = @import("chips.zig");
fn root_dir() []const u8 {
return std.fs.path.dirname(@src().file) orelse ".";
return std.fs.path.dirname(@src().file) orelse unreachable;
}
pub const arduino_nano = micro.Board{
.name = "Arduino Nano",
.source = .{ .path = root_dir() ++ "/boards/arduino_nano.zig" },
.chip = chips.atmega328p,
};
pub const arduino_uno = micro.Board{
.name = "Arduino Uno",
.source = .{ .path = root_dir() ++ "/boards/arduino_uno.zig" },
.chip = chips.atmega328p,
};

@ -0,0 +1,33 @@
pub const chip = @import("chip");
pub const clock_frequencies = .{
.cpu = 16_000_000,
};
pub const pin_map = .{
// Port A
.D0 = "PD0",
.D1 = "PD1",
.D2 = "PD2",
.D3 = "PD3",
.D4 = "PD4",
.D5 = "PD5",
.D6 = "PD6",
.D7 = "PD7",
// Port B
.D8 = "PB0",
.D9 = "PB1",
.D10 = "PB2",
.D11 = "PB3",
.D12 = "PB4",
.D13 = "PB5",
// Port C (Analog)
.A0 = "PC0",
.A1 = "PC1",
.A2 = "PC2",
.A3 = "PC3",
.A4 = "PC4",
.A5 = "PC5",
.A6 = "ADC6",
.A7 = "ADC7",
};

@ -0,0 +1,32 @@
pub const chip = @import("chip");
pub const clock_frequencies = .{
.cpu = 16_000_000,
};
pub const pin_map = .{
// Port D
.D0 = "PD0",
.D1 = "PD1",
.D2 = "PD2",
.D3 = "PD3",
.D4 = "PD4",
.D5 = "PD5",
.D6 = "PD6",
.D7 = "PD7",
// Port B
.D8 = "PB0",
.D9 = "PB1",
.D10 = "PB2",
.D11 = "PB3",
.D12 = "PB4",
// LED_BUILTIN
.D13 = "PB5",
// Port C (Analog)
.A0 = "PC0",
.A1 = "PC1",
.A2 = "PC2",
.A3 = "PC3",
.A4 = "PC4",
.A5 = "PC5",
};

@ -1,6 +1,17 @@
const std = @import("std");
const microzig = @import("../deps/microzig/src/main.zig");
const micro = @import("../deps/microzig/src/main.zig");
const Chip = micro.Chip;
const MemoryRegion = micro.MemoryRegion;
fn root_dir() []const u8 {
return std.fs.path.dirname(@src().file) orelse ".";
}
pub const atmega328p = Chip.from_standard_paths(root_dir(), .{
.name = "ATmega328P",
.cpu = micro.cpus.avr5,
.memory_regions = &.{
MemoryRegion{ .offset = 0x000000, .length = 32 * 1024, .kind = .flash },
MemoryRegion{ .offset = 0x800100, .length = 2048, .kind = .ram },
},
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,191 @@
const std = @import("std");
const micro = @import("microzig");
pub usingnamespace @import("registers.zig");
const regz = @import("registers.zig").registers;
pub const cpu = micro.cpu;
const Port = enum(u8) {
B = 1,
C = 2,
D = 3,
};
pub const clock = struct {
pub const Domain = enum {
cpu,
};
};
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: Port = std.meta.stringToEnum(Port, spec[1..2]) orelse @compileError(invalid_format_msg);
pub const pin: u3 = std.fmt.parseInt(u3, spec[2..3], 10) catch @compileError(invalid_format_msg);
};
}
pub const gpio = struct {
fn regs(comptime desc: type) type {
return struct {
// io address
const pin_addr: u5 = 3 * @enumToInt(desc.port) + 0x00;
const dir_addr: u5 = 3 * @enumToInt(desc.port) + 0x01;
const port_addr: u5 = 3 * @enumToInt(desc.port) + 0x02;
// ram mapping
const pin = @intToPtr(*volatile u8, 0x20 + @as(usize, pin_addr));
const dir = @intToPtr(*volatile u8, 0x20 + @as(usize, dir_addr));
const port = @intToPtr(*volatile u8, 0x20 + @as(usize, port_addr));
};
}
pub fn setOutput(comptime pin: type) void {
cpu.sbi(regs(pin).dir_addr, pin.pin);
}
pub fn setInput(comptime pin: type) void {
cpu.cbi(regs(pin).dir_addr, pin.pin);
}
pub fn read(comptime pin: type) micro.gpio.State {
return if ((regs(pin).pin.* & (1 << pin.pin)) != 0)
.high
else
.low;
}
pub fn write(comptime pin: type, state: micro.gpio.State) void {
if (state == .high) {
cpu.sbi(regs(pin).port_addr, pin.pin);
} else {
cpu.cbi(regs(pin).port_addr, pin.pin);
}
}
pub fn toggle(comptime pin: type) void {
cpu.sbi(regs(pin).pin_addr, pin.pin);
}
};
pub const uart = struct {
pub const DataBits = enum {
five,
six,
seven,
eight,
nine,
};
pub const StopBits = enum {
one,
two,
};
pub const Parity = enum {
odd,
even,
};
};
pub fn Uart(comptime index: usize, comptime pins: micro.uart.Pins) type {
if (index != 0) @compileError("Atmega328p only has a single uart!");
if (pins.tx != null or pins.rx != null)
@compileError("Atmega328p has fixed pins for uart!");
return struct {
const Self = @This();
fn computeDivider(baud_rate: u32) !u12 {
const pclk = micro.clock.get().cpu;
const divider = ((pclk + (8 * baud_rate)) / (16 * baud_rate)) - 1;
return std.math.cast(u12, divider) orelse return error.UnsupportedBaudRate;
}
fn computeBaudRate(divider: u12) u32 {
return micro.clock.get().cpu / (16 * @as(u32, divider) + 1);
}
pub fn init(config: micro.uart.Config) !Self {
const ucsz: u3 = switch (config.data_bits) {
.five => 0b000,
.six => 0b001,
.seven => 0b010,
.eight => 0b011,
.nine => return error.UnsupportedWordSize, // 0b111
};
const upm: u2 = if (config.parity) |parity| switch (parity) {
.even => @as(u2, 0b10), // even
.odd => @as(u2, 0b11), // odd
} else 0b00; // parity disabled
const usbs: u1 = switch (config.stop_bits) {
.one => 0b0,
.two => 0b1,
};
const umsel: u2 = 0b00; // Asynchronous USART
// baud is computed like this:
// f(osc)
// BAUD = ----------------
// 16 * (UBRRn + 1)
const ubrr_val = try computeDivider(config.baud_rate);
regz.USART0.UCSR0A.modify(.{
.MPCM0 = 0,
.U2X0 = 0,
});
regz.USART0.UCSR0B.write(.{
.TXB80 = 0, // we don't care about these btw
.RXB80 = 0, // we don't care about these btw
.UCSZ02 = @truncate(u1, (ucsz & 0x04) >> 2),
.TXEN0 = 1,
.RXEN0 = 1,
.UDRIE0 = 0, // no interrupts
.TXCIE0 = 0, // no interrupts
.RXCIE0 = 0, // no interrupts
});
regz.USART0.UCSR0C.write(.{
.UCPOL0 = 0, // async mode
.UCSZ0 = @truncate(u2, (ucsz & 0x03) >> 0),
.USBS0 = usbs,
.UPM0 = upm,
.UMSEL0 = umsel,
});
regz.USART0.UBRR0.modify(ubrr_val);
return Self{};
}
pub fn canWrite(self: Self) bool {
_ = self;
return (regz.USART0.UCSR0A.read().UDRE0 == 1);
}
pub fn tx(self: Self, ch: u8) void {
while (!self.canWrite()) {} // Wait for Previous transmission
regz.USART0.UDR0.* = ch; // Load the data to be transmitted
}
pub fn canRead(self: Self) bool {
_ = self;
return (regz.USART0.UCSR0A.read().RXC0 == 1);
}
pub fn rx(self: Self) u8 {
while (!self.canRead()) {} // Wait till the data is received
return regz.USART0.UDR0.*; // Read received data
}
};
}
Loading…
Cancel
Save