Merge remote-tracking branch 'avr/main' into merge_avr

wch-ch32v003
Felix "xq" Queißner 9 months ago
commit 5e250056ff

2
.gitignore vendored

@ -0,0 +1,2 @@
zig-cache
zig-out

@ -0,0 +1,19 @@
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
of this software.
Permission is granted to anyone to use this software for any purpose, including
commercial applications, and to alter it and redistribute it freely, subject to
the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product, an
acknowledgment in the product documentation would be appreciated but is not
required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

@ -0,0 +1,24 @@
= Microchip ATmega Hardware Support Package
Note: for testing, renode supports arduino nano 33 BLE
== What version of Zig to use
Right now we are following https://ziglang.org/download/[master], but once 0.11.0 is released, we will be switching to the latest stable version of Zig.
== FYI: LLVM issues
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
----

@ -0,0 +1,84 @@
const std = @import("std");
fn path(comptime suffix: []const u8) std.Build.LazyPath {
return .{
.cwd_relative = comptime ((std.fs.path.dirname(@src().file) orelse ".") ++ suffix),
};
}
const hal = .{
.source_file = path("/src/hals/ATmega328P.zig"),
};
pub const chips = struct {
pub const atmega328p = .{
.preferred_format = .hex,
.chip = .{
.name = "ATmega328P",
.url = "https://www.microchip.com/en-us/product/atmega328p",
.cpu = .avr5,
.register_definition = .{
.json = path("/src/chips/ATmega328P.json"),
},
.memory_regions = &.{
.{ .offset = 0x000000, .length = 32 * 1024, .kind = .flash },
.{ .offset = 0x800100, .length = 2048, .kind = .ram },
},
},
.hal = hal,
};
};
pub const boards = struct {
pub const arduino = struct {
pub const nano = .{
.preferred_format = .hex,
.chip = chips.atmega328p.chip,
.hal = hal,
.board = .{
.name = "Arduino Nano",
.url = "https://docs.arduino.cc/hardware/nano",
.source_file = path("/src/boards/arduino_nano.zig"),
},
};
pub const uno_rev3 = .{
.preferred_format = .hex,
.chip = chips.atmega328p.chip,
.hal = hal,
.board = .{
.name = "Arduino Uno",
.url = "https://docs.arduino.cc/hardware/uno-rev3",
.source_file = path("/src/boards/arduino_uno.zig"),
},
};
};
};
pub fn build(b: *std.build.Builder) void {
_ = b;
// const optimize = b.standardOptimizeOption(.{});
// inline for (@typeInfo(boards).Struct.decls) |decl| {
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(boards, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .board = @field(boards, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
// inline for (@typeInfo(chips).Struct.decls) |decl| {
// const exe = microzig.addEmbeddedExecutable(b, .{
// .name = @field(chips, decl.name).name ++ ".minimal",
// .source_file = .{
// .path = "test/programs/minimal.zig",
// },
// .backing = .{ .chip = @field(chips, decl.name) },
// .optimize = optimize,
// });
// exe.installArtifact(b);
// }
}

@ -0,0 +1,5 @@
.{
.name = "microzig-espressif-esp",
.version = "0.1.0",
.dependencies = .{},
}

@ -0,0 +1,7 @@
const std = @import("std");
const micro = @import("microzig");
const chips = @import("chips.zig");
fn root_dir() []const u8 {
return std.fs.path.dirname(@src().file) orelse unreachable;
}

@ -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",
};

@ -0,0 +1,8 @@
const std = @import("std");
const micro = @import("microzig");
const Chip = micro.Chip;
const MemoryRegion = micro.MemoryRegion;
fn root_dir() []const u8 {
return std.fs.path.dirname(@src().file) orelse ".";
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,190 @@
const std = @import("std");
const micro = @import("microzig");
const peripherals = micro.chip.peripherals;
const USART0 = peripherals.USART0;
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 * @intFromEnum(desc.port) + 0x00;
const dir_addr: u5 = 3 * @intFromEnum(desc.port) + 0x01;
const port_addr: u5 = 3 * @intFromEnum(desc.port) + 0x02;
// ram mapping
const pin = @as(*volatile u8, @ptrFromInt(0x20 + @as(usize, pin_addr)));
const dir = @as(*volatile u8, @ptrFromInt(0x20 + @as(usize, dir_addr)));
const port = @as(*volatile u8, @ptrFromInt(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);
USART0.UCSR0A.modify(.{
.MPCM0 = 0,
.U2X0 = 0,
});
USART0.UCSR0B.write(.{
.TXB80 = 0, // we don't care about these btw
.RXB80 = 0, // we don't care about these btw
.UCSZ02 = @as(u1, @truncate((ucsz & 0x04) >> 2)),
.TXEN0 = 1,
.RXEN0 = 1,
.UDRIE0 = 0, // no interrupts
.TXCIE0 = 0, // no interrupts
.RXCIE0 = 0, // no interrupts
});
USART0.UCSR0C.write(.{
.UCPOL0 = 0, // async mode
.UCSZ0 = @as(u2, @truncate((ucsz & 0x03) >> 0)),
.USBS0 = usbs,
.UPM0 = upm,
.UMSEL0 = umsel,
});
USART0.UBRR0.modify(ubrr_val);
return Self{};
}
pub fn canWrite(self: Self) bool {
_ = self;
return (USART0.UCSR0A.read().UDRE0 == 1);
}
pub fn tx(self: Self, ch: u8) void {
while (!self.canWrite()) {} // Wait for Previous transmission
USART0.UDR0.* = ch; // Load the data to be transmitted
}
pub fn canRead(self: Self) bool {
_ = self;
return (USART0.UCSR0A.read().RXC0 == 1);
}
pub fn rx(self: Self) u8 {
while (!self.canRead()) {} // Wait till the data is received
return USART0.UDR0.*; // Read received data
}
};
}

@ -0,0 +1,5 @@
const micro = @import("microzig");
pub fn main() void {
// This function will contain the application logic.
}
Loading…
Cancel
Save