From 40575cafe477df2ed3779789174a13eae5da187e Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Wed, 18 Dec 2024 00:30:51 -0700 Subject: Initial commit for programming an arduino in Zig. This is a simple collatz blinker program. --- blink.zig | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ build.zig | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ init.zig | 27 ++++++++++++++++++++++ linker.ld | 33 +++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 blink.zig create mode 100644 build.zig create mode 100644 init.zig create mode 100644 linker.ld diff --git a/blink.zig b/blink.zig new file mode 100644 index 0000000..4444427 --- /dev/null +++ b/blink.zig @@ -0,0 +1,66 @@ +const std = @import("std"); + +const DDRB = @as(*volatile u8, @ptrFromInt(0x24)); +const PORTB = @as(*volatile u8, @ptrFromInt(0x25)); + +const DELAY = 100; + +pub export fn delay(n: u32) void { + var i: u32 = 0; + while (i < n) : (i += 1) { + asm volatile ("nop" ::: "memory"); + } +} + +pub export fn blink(n: u32) void { + var i: u32 = 0; + DDRB.* = DDRB.* | (1 << 5); + + while (i < n) : (i += 1) { + // Toggle PB5 + PORTB.* ^= @as(u8, 1 << 5); + delay(100_000); + PORTB.* ^= @as(u8, 1 << 5); + delay(200_000); + } +} + +pub export fn collatz(na: u32) u32 { + var n: u32 = na; + var c: u32 = 0; + + while (n > 1) : (c += 1) { + if (n % 2 == 0) { + n /= 2; + } else { + n = n + n + n + 1; + } + } + + return c; +} + +pub export fn main() void { + var i: u32 = 0; + while (true) : (i += 1) { + const c = collatz(i); + blink(c); + delay(500_000); + } +} + +pub export fn abort() void { + // Set PB5 (pin 13) as output + DDRB.* = DDRB.* | (1 << 5); + + while (true) { + // Toggle PB5 + PORTB.* ^= @as(u8, 1 << 5); + + // Simple delay + var i: usize = 0; + while (i < DELAY) : (i += 1) { + asm volatile ("nop" ::: "memory"); + } + } +} diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..0a65c1f --- /dev/null +++ b/build.zig @@ -0,0 +1,78 @@ +const std = @import("std"); +const Builder = std.Build; + +pub fn build(b: *std.Build) !void { + const uno = std.zig.CrossTarget{ + .cpu_arch = .avr, + .cpu_model = .{ .explicit = &std.Target.avr.cpu.atmega328p }, + .os_tag = .freestanding, + .abi = .none, + }; + + const exe = b.addExecutable(.{ + .name = "blink", + .root_source_file = b.path("blink.zig"), + .target = b.resolveTargetQuery(uno), + .optimize = .ReleaseSafe, + }); + + const init = b.addObject(.{ + .name = "startup", + .root_source_file = b.path("init.zig"), + .target = b.resolveTargetQuery(uno), + .optimize = .ReleaseSafe + }); + + exe.addObject(init); + exe.setLinkerScriptPath(b.path("linker.ld")); + + b.installArtifact(exe); + + const tty = b.option( + []const u8, + "tty", + "Specify the port to which the Arduino is connected (defaults to /dev/ttyACM0)", + ) orelse "/dev/ttyACM0"; + + const bin_path = b.getInstallPath(.{ .custom = exe.installed_path orelse "./bin" }, exe.out_filename); + + const flash_command = blk: { + var tmp = std.ArrayList(u8).init(b.allocator); + try tmp.appendSlice("-Uflash:w:"); + try tmp.appendSlice(bin_path); + try tmp.appendSlice(":e"); + break :blk try tmp.toOwnedSlice(); + }; + + const upload = b.step("upload", "Upload the code to an Arduino device using avrdude"); + const avrdude = b.addSystemCommand(&.{ + "avrdude", + "-carduino", + "-patmega328p", + "-D", + "-P", + tty, + flash_command, + }); + upload.dependOn(&avrdude.step); + avrdude.step.dependOn(&exe.step); + + const objdump = b.step("objdump", "Show dissassembly of the code using avr-objdump"); + const avr_objdump = b.addSystemCommand(&.{ + "avr-objdump", + "-dh", + bin_path, + }); + objdump.dependOn(&avr_objdump.step); + avr_objdump.step.dependOn(&exe.step); + + const monitor = b.step("monitor", "Opens a monitor to the serial output"); + const screen = b.addSystemCommand(&.{ + "screen", + tty, + "115200", + }); + monitor.dependOn(&screen.step); + + b.default_step.dependOn(&exe.step); +} diff --git a/init.zig b/init.zig new file mode 100644 index 0000000..be0bd10 --- /dev/null +++ b/init.zig @@ -0,0 +1,27 @@ +pub export fn _start() linksection(".vectors") callconv(.Naked) void { + asm volatile ( + \\ rjmp reset ; jump to reset + \\ rjmp ext_int0 + ); +} + +pub export const end_of_ram: u16 = 0x8FF; +pub export fn reset() linksection(".vectors") callconv(.Naked) void { + asm volatile ( + \\ sei + \\ rjmp main + ); + // asm volatile ( + // \\ ldi r16, hi8(%[ramend]) + // \\ sts 0x3E, r16 + // \\ ldi r16, lo8(%[ramend]) + // \\ sts 0X3D, r16 + // \\ sei + // \\ jmp main + // : + // : [ramend] "i" (end_of_ram) + // : "r16" + // ); +} + +pub export fn ext_int0() void {} diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..ef5e46b --- /dev/null +++ b/linker.ld @@ -0,0 +1,33 @@ +MEMORY +{ + flash (rx) : ORIGIN = 0, LENGTH = 32K + ram (rw!x) : ORIGIN = 0x100, LENGTH = 2K +} + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + + *(.text*) + } > flash + + .data : + { + __data_start = .; + *(.rodata*) + *(.data*) + __data_end = .; + } > ram AT> flash + + .bss (NOLOAD) : + { + __bss_start = .; + *(.bss*) + __bss_end = .; + } > ram + RAMEND = ORIGIN(ram) + LENGTH(ram); + + __data_load_start = LOADADDR(.data); +} -- cgit