diff --git a/build.zig b/build.zig index 9ac67b6..93e8250 100644 --- a/build.zig +++ b/build.zig @@ -4,16 +4,13 @@ const Build = std.Build; const MicroZig = @import("microzig/build"); const atsam = @import("microzig/bsp/microchip/atsam"); -pub const py_badge: MicroZig.Target = .{ - .preferred_format = .elf, - .chip = atsam.chips.atsamd51j19, - .hal = null, -}; - fn sycl_badge_microzig_target(d: *Build.Dependency) MicroZig.Target { + var atsamd51j19_chip_with_fpu = atsam.chips.atsamd51j19.chip; + atsamd51j19_chip_with_fpu.cpu.target.cpu_features_add = std.Target.arm.featureSet(&.{.vfp4d16sp}); + atsamd51j19_chip_with_fpu.cpu.target.abi = .eabihf; return .{ .preferred_format = .elf, - .chip = atsam.chips.atsamd51j19.chip, + .chip = atsamd51j19_chip_with_fpu, .hal = .{ .root_source_file = d.builder.path("src/hal.zig"), }, diff --git a/samples/feature_test.zig b/samples/feature_test.zig index 5bbd965..458fa2d 100644 --- a/samples/feature_test.zig +++ b/samples/feature_test.zig @@ -66,11 +66,11 @@ export fn update() void { for (0..cart.screen_height) |y| { for (0..cart.screen_width) |x| { - cart.framebuffer[y * cart.screen_width + x] = .{ + cart.framebuffer[x][y].setColor(.{ .r = @intFromFloat(@as(f32, @floatFromInt(x)) / cart.screen_width * 31), .g = green_565, .b = @intFromFloat(@as(f32, @floatFromInt(y)) / cart.screen_height * 31), - }; + }); } } diff --git a/showcase/carts/metalgear-timer/src/metalgear-timer.zig b/showcase/carts/metalgear-timer/src/metalgear-timer.zig index 3f9cd09..f07f164 100644 --- a/showcase/carts/metalgear-timer/src/metalgear-timer.zig +++ b/showcase/carts/metalgear-timer/src/metalgear-timer.zig @@ -39,7 +39,7 @@ fn r(x: usize, y: usize, w: usize, h: usize) void { const y1 = y0 + sy * h; for (y0..y1) |yi| { for (x0..x1) |xi| { - cart.framebuffer[yi * cart.screen_width + xi] = color; + cart.framebuffer[xi][yi].setColor(color); } } } diff --git a/showcase/carts/plasma/src/plasma.zig b/showcase/carts/plasma/src/plasma.zig index aa23b9b..d615901 100644 --- a/showcase/carts/plasma/src/plasma.zig +++ b/showcase/carts/plasma/src/plasma.zig @@ -24,7 +24,7 @@ const hue_colors = init_hue_colors: { var plasma_buffer = init_plasma_buffer: { @setEvalBranchQuota(100000); - var initial_plasma_buffer: [cart.framebuffer.len]u8 = undefined; + var initial_plasma_buffer: [cart.screen_width][cart.screen_height]u8 = undefined; var y: usize = 0; while (y < cart.screen_height) : (y += 1) { var x: usize = 0; @@ -37,16 +37,18 @@ var plasma_buffer = init_plasma_buffer: { value += @sin(@sqrt(fx * fx + fy * fy) / 8.0); // shift range from -4 .. 4 to 0 .. 255 value = std.math.clamp((value + 4) * 32, 0, 255); - initial_plasma_buffer[y * cart.screen_width + x] = @intFromFloat(value); + initial_plasma_buffer[x][y] = @intFromFloat(value); } } break :init_plasma_buffer initial_plasma_buffer; }; fn updatePlasma() void { - for (0..cart.framebuffer.len) |i| { - plasma_buffer[i] +%= 2; - cart.framebuffer[i] = hue_colors[plasma_buffer[i]]; + for (cart.framebuffer, &plasma_buffer) |*fb_col, *plasma_col| { + for (fb_col, plasma_col) |*fb_pix, *plasma_pix| { + plasma_pix.* +%= 2; + fb_pix.setColor(hue_colors[plasma_pix.*]); + } } } diff --git a/showcase/carts/raytracer/src/camera.zig b/showcase/carts/raytracer/src/camera.zig index fd8a967..c7fae26 100644 --- a/showcase/carts/raytracer/src/camera.zig +++ b/showcase/carts/raytracer/src/camera.zig @@ -40,8 +40,7 @@ w: Vec3, defocus_disk_u: Vec3, defocus_disk_v: Vec3, -pub fn init(position: Vec3) Camera { - var self: Camera = undefined; +pub fn init(self: *Camera, position: Vec3) void { self.lookfrom = position; self.camera_center = self.lookfrom; @@ -68,8 +67,6 @@ pub fn init(position: Vec3) Camera { self.defocus_disk_u = self.u.mul_scalar(defocus_radius); self.defocus_disk_v = self.v.mul_scalar(defocus_radius); - - return self; } fn pixel_sample_square(self: *Camera) Vec3 { @@ -111,13 +108,12 @@ pub fn render(self: *Camera, world: *HittableList) !void { const samples: f32 = @floatFromInt(self.samples); col = col.div_scalar(samples); - const index: usize = i + j * image_width; const color = vec.color3_to_color(col); - cart.framebuffer[index] = .{ + cart.framebuffer[i][j].setColor(.{ .r = @truncate(color.rgb.r >> 3), .g = @truncate(color.rgb.g >> 2), .b = @truncate(color.rgb.b >> 3), - }; + }); } } //std.debug.print("Done!\n", .{}); diff --git a/showcase/carts/raytracer/src/main.zig b/showcase/carts/raytracer/src/main.zig index 13313b8..df44303 100644 --- a/showcase/carts/raytracer/src/main.zig +++ b/showcase/carts/raytracer/src/main.zig @@ -41,7 +41,8 @@ pub fn main_program() !void { const x = radius * std.math.sin(angle_rad); const y = radius * std.math.cos(angle_rad); - var camera = Camera.init(Vec3.init(x, 2, y)); + var camera: Camera = undefined; + camera.init(Vec3.init(x, 2, y)); var a: i32 = -5; while (a < 5) : (a += 1) { diff --git a/showcase/carts/zeroman/src/Renderer.zig b/showcase/carts/zeroman/src/Renderer.zig index 84d3f0c..acecd17 100644 --- a/showcase/carts/zeroman/src/Renderer.zig +++ b/showcase/carts/zeroman/src/Renderer.zig @@ -69,7 +69,7 @@ pub const Sprite = struct { const index = (y + src_y0) * sprite.width + (if (flip_x) @abs(src_rect.w) - 1 - x else x) + src_x0; const color = sprite.colors[sprite.indices.get(index)]; if (color.r == 31 and color.g == 0 and color.b == 31) continue; - cart.framebuffer[@as(usize, @intCast(dst_y * cart.screen_width + dst_x))] = color; + cart.framebuffer[@intCast(dst_x)][@intCast(dst_y)].setColor(color); } } } @@ -95,7 +95,7 @@ pub const Tilemap = struct { const src_y = (tile_index / 16) * tile_size + (y % tile_size); const color = tiles.colors[tiles.indices.get(src_y * tiles.width + src_x)]; if (color.r == 31 and color.g == 0 and color.b == 31) continue; - cart.framebuffer[@as(usize, @intCast((dst_y) * cart.screen_width + dst_x))] = color; + cart.framebuffer[@intCast(dst_x)][@intCast(dst_y)].setColor(color); } } } @@ -104,5 +104,11 @@ pub const Tilemap = struct { pub fn init() void {} pub fn clear() void { - @memset(cart.framebuffer, .{ .r = 0, .g = 0, .b = 0 }); + cart.rect(.{ + .x = 0, + .y = 0, + .width = cart.screen_width, + .height = cart.screen_height, + .fill_color = .{ .r = 0, .g = 0, .b = 0 }, + }); } diff --git a/simulator/src/runtime.ts b/simulator/src/runtime.ts index 389a73a..7b24118 100644 --- a/simulator/src/runtime.ts +++ b/simulator/src/runtime.ts @@ -129,6 +129,8 @@ export class Runtime { read_flash: this.read_flash.bind(this), write_flash_page: this.write_flash_page.bind(this), + rand: this.rand.bind(this), + trace: this.trace.bind(this), }; @@ -207,6 +209,10 @@ export class Runtime { console.log(str); } + rand (): number { + return ~~(Math.random() * 4294967296.0); + } + trace (strUtf8Ptr: number, byteLength: number) { const strUtf8 = new Uint8Array(this.memory.buffer, strUtf8Ptr, byteLength); const str = new TextDecoder().decode(strUtf8); diff --git a/src/badge.zig b/src/badge.zig index 9a70698..1eea34b 100644 --- a/src/badge.zig +++ b/src/badge.zig @@ -33,11 +33,10 @@ const MPU = chip.peripherals.MPU; const cart = @import("badge/cart.zig"); -const led_pin = board.D13; +const led_pin = board.A5_D13; -const Lcd = board.Lcd; +const lcd = board.lcd; const ButtonPoller = board.ButtonPoller; -const light_sensor_pin = microzig.board.A7_LIGHT; const audio = board.audio; const adc = hal.adc.num(0); @@ -52,6 +51,7 @@ pub const microzig_options = .{ }; pub fn main() !void { + // Enable safety traps SystemControl.CCR.modify(.{ .NONBASETHRDENA = 0, .USERSETMPEND = 0, @@ -60,11 +60,7 @@ pub fn main() !void { .BFHFNMIGN = 0, .STKALIGN = .{ .value = .VALUE_1 }, }); - SystemControl.SHCSR.modify(.{ - .MEMFAULTENA = 1, - .BUSFAULTENA = 1, - .USGFAULTENA = 1, - }); + // Enable FPU access. SystemControl.CPACR.write(.{ .reserved20 = 0, .CP10 = .{ .value = .FULL }, @@ -82,9 +78,10 @@ pub fn main() !void { }); NVMCTRL.CTRLA.modify(.{ .AUTOWS = 1 }); - clocks.gclk.reset_blocking(); microzig.cpu.dmb(); + clocks.gclk.reset_blocking(); + MPU.RBAR.write(.{ .REGION = 0, .VALID = 1, @@ -220,50 +217,26 @@ pub fn main() !void { timer.init(); audio.init(); - init_frame_sync(); // Light sensor adc - light_sensor_pin.set_mux(.B); + microzig.board.A6_LIGHT.set_mux(.B); const state = clocks.get_state(); const freqs = clocks.Frequencies.get(state); _ = freqs; - const lcd = Lcd.init(.{ - .spi = sercom.spi.Master.init(.SERCOM4, .{ - .cpha = .LEADING_EDGE, - .cpol = .IDLE_LOW, - .dord = .MSB, - .dopo = .PAD2, - .ref_freq_hz = 120_000_000, - .baud_freq_hz = 12_000_000, - }), - .pins = .{ - .rst = board.TFT_RST, - .lite = board.TFT_LITE, - .dc = board.TFT_DC, - .cs = board.TFT_CS, - .sck = board.TFT_SCK, - .mosi = board.TFT_MOSI, - }, - .fb = .{ - .bpp16 = @ptrCast(cart.api.framebuffer), - }, - }); - - lcd.clear_screen(.{ .r = 0, .g = 0, .b = 0 }); + lcd.init(.bpp16, @ptrCast(cart.api.framebuffer)); const neopixels = board.Neopixels.init(board.D8_NEOPIX); - adc.init(); + adc.init(.DIV16); + adc.set_input(.AIN6, .GND, .single_ended, .stop); + adc.enable(); const poller = ButtonPoller.init(); led_pin.set_dir(.out); cart.start(); while (true) { - //if (!frame_is_ready()) - // continue; - - const light_reading = adc.single_shot_blocking(.AIN6); + const light_reading = adc.single_shot_blocking(); cart.api.light_level.* = @intCast(light_reading); const buttons = poller.read_from_port(); @@ -280,6 +253,7 @@ pub fn main() !void { }; cart.tick(); + var pixels: [5]board.NeopixelColor = undefined; for (&pixels, cart.api.neopixels) |*local, pixel| local.* = .{ @@ -287,125 +261,6 @@ pub fn main() !void { .g = pixel.g, .b = pixel.b, }; - neopixels.write(&pixels); - led_pin.write(if (cart.api.red_led.*) .high else .low); - lcd.set_window(0, 0, 160, 128); - lcd.send_colors(@ptrCast(cart.api.framebuffer)); } } - -pub fn init_frame_sync() void { - TC4.COUNT16.CTRLA.write(.{ - .SWRST = 0, - .ENABLE = 0, - .MODE = .{ .raw = 0 }, - .PRESCSYNC = .{ .raw = 0 }, - .RUNSTDBY = 0, - .ONDEMAND = 0, - .PRESCALER = .{ .raw = 0 }, - .ALOCK = 0, - .reserved16 = 0, - .CAPTEN0 = 0, - .CAPTEN1 = 0, - .reserved20 = 0, - .COPEN0 = 0, - .COPEN1 = 0, - .reserved24 = 0, - .CAPTMODE0 = .{ .raw = 0 }, - .reserved27 = 0, - .CAPTMODE1 = .{ .raw = 0 }, - .padding = 0, - }); - while (TC4.COUNT16.SYNCBUSY.read().ENABLE != 0) {} - - TC4.COUNT16.CTRLA.write(.{ - .SWRST = 1, - .ENABLE = 0, - .MODE = .{ .raw = 0 }, - .PRESCSYNC = .{ .raw = 0 }, - .RUNSTDBY = 0, - .ONDEMAND = 0, - .PRESCALER = .{ .raw = 0 }, - .ALOCK = 0, - .reserved16 = 0, - .CAPTEN0 = 0, - .CAPTEN1 = 0, - .reserved20 = 0, - .COPEN0 = 0, - .COPEN1 = 0, - .reserved24 = 0, - .CAPTMODE0 = .{ .raw = 0 }, - .reserved27 = 0, - .CAPTMODE1 = .{ .raw = 0 }, - .padding = 0, - }); - while (TC4.COUNT16.SYNCBUSY.read().SWRST != 0) {} - TC4.COUNT16.CTRLA.write(.{ - .SWRST = 0, - .ENABLE = 0, - .MODE = .{ .value = .COUNT16 }, - .PRESCSYNC = .{ .value = .PRESC }, - .RUNSTDBY = 0, - .ONDEMAND = 0, - .PRESCALER = .{ .value = .DIV64 }, - .ALOCK = 0, - .reserved16 = 0, - .CAPTEN0 = 0, - .CAPTEN1 = 0, - .reserved20 = 0, - .COPEN0 = 0, - .COPEN1 = 0, - .reserved24 = 0, - .CAPTMODE0 = .{ .raw = 0 }, - .reserved27 = 0, - .CAPTMODE1 = .{ .raw = 0 }, - .padding = 0, - }); - TC4.COUNT16.WAVE.write(.{ .WAVEGEN = .{ .value = .MFRQ }, .padding = 0 }); - TC4.COUNT16.CC[0].write(.{ .CC = @divExact(8_467_200, 64 * 60) - 1 }); - while (TC4.COUNT16.SYNCBUSY.read().CC0 != 0) {} - TC4.COUNT16.CTRLA.write(.{ - .SWRST = 0, - .ENABLE = 1, - .MODE = .{ .value = .COUNT16 }, - .PRESCSYNC = .{ .value = .PRESC }, - .RUNSTDBY = 0, - .ONDEMAND = 0, - .PRESCALER = .{ .value = .DIV64 }, - .ALOCK = 0, - .reserved16 = 0, - .CAPTEN0 = 0, - .CAPTEN1 = 0, - .reserved20 = 0, - .COPEN0 = 0, - .COPEN1 = 0, - .reserved24 = 0, - .CAPTMODE0 = .{ .raw = 0 }, - .reserved27 = 0, - .CAPTMODE1 = .{ .raw = 0 }, - .padding = 0, - }); - while (TC4.COUNT16.SYNCBUSY.read().ENABLE != 0) {} - TC4.COUNT16.CTRLBSET.write(.{ - .DIR = 0, - .LUPD = 0, - .ONESHOT = 0, - .reserved5 = 0, - .CMD = .{ .value = .RETRIGGER }, - }); - while (TC4.COUNT16.SYNCBUSY.read().CTRLB != 0) {} -} - -pub fn frame_is_ready() bool { - if (TC4.COUNT16.INTFLAG.read().OVF != 1) return false; - TC4.COUNT16.INTFLAG.write(.{ - .OVF = 1, - .ERR = 0, - .reserved4 = 0, - .MC0 = 0, - .MC1 = 0, - .padding = 0, - }); - return true; -} diff --git a/src/badge/cart.zig b/src/badge/cart.zig index 68ca243..bef1a85 100644 --- a/src/badge/cart.zig +++ b/src/badge/cart.zig @@ -1,7 +1,10 @@ const std = @import("std"); const microzig = @import("microzig"); +const chip = microzig.chip; +const FPU = chip.peripherals.FPU; const board = microzig.board; const audio = board.audio; +const lcd = board.lcd; const timer = microzig.hal.timer; pub const api = @import("../cart/api.zig"); @@ -14,7 +17,10 @@ const libcart = struct { extern fn start() void; extern fn update() void; - extern fn __return_thunk__() noreturn; + export fn __return_thunk__() linksection(".text.cart") noreturn { + asm volatile (" svc #12"); + unreachable; + } }; pub fn svcall_handler() callconv(.Naked) void { @@ -30,8 +36,8 @@ pub fn svcall_handler() callconv(.Naked) void { \\ cmp r3, #0xDF \\ bne 12f \\ ldrb r3, [r2, #0 * 1] - \\ cmp r3, #11 - \\ bhi 12f + \\ cmp r3, #12 + \\ bhi 13f \\ tbb [pc, r3] \\0: \\ .byte (0f - 0b) / 2 @@ -45,8 +51,9 @@ pub fn svcall_handler() callconv(.Naked) void { \\ .byte (8f - 0b) / 2 \\ .byte (9f - 0b) / 2 \\ .byte (10f - 0b) / 2 - \\12: \\ .byte (11f - 0b) / 2 + \\13: + \\ .byte (12f - 0b) / 2 \\ .byte 0xDE \\ .align 1 \\0: @@ -80,13 +87,15 @@ pub fn svcall_handler() callconv(.Naked) void { \\ ldm r1, {r0-r1} \\ b %[write_flash_page:P] \\10: + \\ b %[rand:P] + \\11: \\ ldm r1, {r0-r1} \\ b %[trace:P] - \\11: + \\12: \\ lsrs r0, #31 \\ msr control, r0 \\ it eq - \\ popeq {r3, r5-r11, pc} + \\ popeq {r4-r11, pc} \\ subs r0, #1 - 0xFFFFFFFD \\ push {r4-r11, lr} \\ movs r4, #0 @@ -109,6 +118,7 @@ pub fn svcall_handler() callconv(.Naked) void { [tone] "X" (&tone), [read_flash] "X" (&read_flash), [write_flash_page] "X" (&write_flash_page), + [rand] "X" (&rand), [trace] "X" (&trace), ); } @@ -118,14 +128,7 @@ pub const HSRAM = struct { }; pub fn start() void { - @memset(@as(*[0x19A0]u8, @ptrFromInt(0x20000000)), 0); - api.neopixels.* = .{ - .{ .r = 0, .g = 0, .b = 0 }, - .{ .r = 0, .g = 0, .b = 0 }, - .{ .r = 0, .g = 0, .b = 0 }, - .{ .r = 0, .g = 0, .b = 0 }, - .{ .r = 0, .g = 0, .b = 0 }, - }; + @memset(@as(*[0xA020]u8, @ptrFromInt(0x20000000)), 0); // fill .bss with zeroes { @@ -149,14 +152,14 @@ pub fn start() void { call(&libcart.start); } pub fn tick() void { - // TODO: check if frame is ready - - // read gamepad - //if (SYSTEM_FLAGS.* & SYSTEM_PRESERVE_FRAMEBUFFER == 0) @memset(FRAMEBUFFER, 0b00_00_00_00); + // non-rendering logic could go here + lcd.vsync(); call(&libcart.update); + lcd.update(); } fn call(func: *const fn () callconv(.C) void) void { + // initialize new context const process_stack = HSRAM.ADDR[HSRAM.SIZE - @divExact( HSRAM.SIZE, 3 * 2, @@ -168,21 +171,36 @@ fn call(func: *const fn () callconv(.C) void) void { frame[7] = 1 << 24; asm volatile ( \\ msr psp, %[process_stack] - \\ svc #11 + \\ svc #12 : : [process_stack] "r" (frame.ptr), : "memory" ); + // delete fp context + FPU.FPCCR.write(.{ + .LSPACT = 0, + .USER = 0, + .reserved3 = 0, + .THREAD = 0, + .HFRDY = 0, + .MMRDY = 0, + .BFRDY = 0, + .reserved8 = 0, + .MONRDY = 0, + .reserved30 = 0, + .LSPEN = 1, + .ASPEN = 1, + }); } fn User(comptime T: type) type { return extern struct { const Self = @This(); - const suffix = switch (@sizeOf(T)) { - 1 => "b", - 2 => "h", - 4 => "", - else => @compileError("loadUser doesn't support " ++ @typeName(T)), + const suffix = switch (@bitSizeOf(T)) { + 8 => "b", + 16 => "h", + 32 => "", + else => @compileError("User doesn't support " ++ @typeName(T)), }; unsafe: T, @@ -204,14 +222,10 @@ fn User(comptime T: type) type { }; } -fn point(x: usize, y: usize, color: api.DisplayColor) void { - api.framebuffer[y * api.screen_width + x] = color; -} - -fn pointUnclipped(x: i32, y: i32, color: api.DisplayColor) void { - if (x >= 0 and x < api.screen_width and y >= 0 and y < api.screen_height) { - point(@intCast(x), @intCast(y), color); - } +fn clipPixel(x: i32, y: i32, pixel: api.Pixel) void { + if (x < 0 or x >= api.screen_width) return; + if (y < 0 or y >= api.screen_height) return; + api.framebuffer[@intCast(x)][@intCast(y)] = pixel; } fn blit( @@ -268,7 +282,7 @@ fn blit( const index = sy * stride + sx; - point(tx, ty, sprite[index].load()); + api.framebuffer[tx][ty].setColor(sprite[index].load()); } } } @@ -293,8 +307,9 @@ fn line( const sy: i32 = if (y0 < y1) 1 else -1; var err = dx + dy; + const pixel = api.Pixel.fromColor(color); while (true) { - pointUnclipped(x0, y0, color); + clipPixel(x0, y0, pixel); if (x0 == x1 and y0 == y1) break; const e2 = 2 * err; @@ -351,12 +366,16 @@ fn oval( a = 8 * a2; b1 = 8 * b2; + const stroke_pixel = if (stroke_color.unwrap()) |sc| + api.Pixel.fromColor(sc) + else + null; while (true) { - if (stroke_color.unwrap()) |sc| { - pointUnclipped(east, north, sc); // I. Quadrant - pointUnclipped(west, north, sc); // II. Quadrant - pointUnclipped(west, south, sc); // III. Quadrant - pointUnclipped(east, south, sc); // IV. Quadrant + if (stroke_pixel) |sp| { + clipPixel(east, north, sp); // I. Quadrant + clipPixel(west, north, sp); // II. Quadrant + clipPixel(west, south, sp); // III. Quadrant + clipPixel(east, south, sp); // IV. Quadrant } const oval_start = west + 1; @@ -388,14 +407,14 @@ fn oval( if (!(west <= east)) break; } - if (stroke_color.unwrap()) |sc| { + if (stroke_pixel) |sp| { // Make sure north and south have moved the entire way so top/bottom aren't missing while (north - south < signed_height) { - pointUnclipped(west - 1, north, sc); // II. Quadrant - pointUnclipped(east + 1, north, sc); // I. Quadrant + clipPixel(west - 1, north, sp); // II. Quadrant + clipPixel(east + 1, north, sp); // I. Quadrant north += 1; - pointUnclipped(west - 1, south, sc); // III. Quadrant - pointUnclipped(east + 1, south, sc); // IV. Quadrant + clipPixel(west - 1, south, sp); // III. Quadrant + clipPixel(east + 1, south, sp); // IV. Quadrant south -= 1; } } @@ -415,18 +434,36 @@ fn rect( const stroke_color = rest.stroke_color.load().unwrap(); const fill_color = rest.fill_color.load().unwrap(); - if (stroke_color) |sc| { - hline(x, y, width, sc); - hline(x, y + @as(i32, @intCast(height)), width + 1, sc); + if (stroke_color == null and fill_color == null) return; + if (width == 0 or height == 0 or x >= api.screen_width or y >= api.screen_height) return; + const end_x = x +| @min(width, std.math.maxInt(i32)); + const end_y = y +| @min(height, std.math.maxInt(i32)); + if (end_x <= 0 or end_y <= 0) return; - vline(x, y, height, sc); - vline(x + @as(i32, @intCast(width)), y, height, sc); - } + const min_x: usize = @intCast(@max(x, 0)); + const min_y: usize = @intCast(@max(y, 0)); + const max_x: usize = @intCast(@min(end_x, api.screen_width)); + const max_y: usize = @intCast(@min(end_y, api.screen_height)); - if (fill_color) |fc| { - for (@as(u32, @intCast(y)) + 1..@as(u32, @intCast(y)) + height) |yy| { - hline(x + 1, @intCast(yy), width - 1, fc); + if (stroke_color) |sc| { + const stroke_pixel = api.Pixel.fromColor(sc); + if (x >= 0) @memset(api.framebuffer[min_x][min_y..max_y], stroke_pixel); + if (width > 1 and end_x <= api.screen_width) @memset(api.framebuffer[max_x - 1][min_y..max_y], stroke_pixel); + if (width > 2) { + if (y >= 0) { + for (api.framebuffer[min_x + 1 .. max_x - 1]) |*col| col[min_y] = stroke_pixel; + } + if (height > 1 and end_y <= api.screen_height) { + for (api.framebuffer[min_x + 1 .. max_x - 1]) |*col| col[max_y - 1] = stroke_pixel; + } + if (height > 2) if (fill_color) |fc| { + const fill_pixel = api.Pixel.fromColor(fc); + for (api.framebuffer[min_x + 1 .. max_x - 2]) |*col| @memset(col[min_y + 1 .. max_y - 2], fill_pixel); + }; } + } else if (fill_color) |fc| { + const fill_pixel = api.Pixel.fromColor(fc); + for (api.framebuffer[min_x..max_x]) |*col| @memset(col[min_y..max_y], fill_pixel); } } @@ -447,11 +484,13 @@ fn text( const text_color = rest.text_color.load(); const background_color = rest.background_color.load(); - const colors = &[_]api.DisplayColor.Optional{ text_color, background_color }; - var char_x_offset = x; var char_y_offset = y; + const pixels = [_]?api.Pixel{ + if (text_color.unwrap()) |c| api.Pixel.fromColor(c) else null, + if (background_color.unwrap()) |c| api.Pixel.fromColor(c) else null, + }; for (0..str_len) |char_idx| { const char = str_ptr[char_idx].load(); @@ -465,10 +504,9 @@ fn text( for (0..8) |x_offset| { const dst_x = char_x_offset + @as(i32, @intCast(x_offset)); - const color = colors[std.mem.readPackedIntNative(u1, &font, base + y_offset * 8 + (7 - x_offset))]; - if (color.unwrap()) |dc| { + if (pixels[std.mem.readPackedIntNative(u1, &font, base + y_offset * 8 + (7 - x_offset))]) |pixel| { // TODO: this is slow; check bounds once instead - pointUnclipped(dst_x, dst_y, dc); + clipPixel(dst_x, dst_y, pixel); } } } @@ -486,13 +524,12 @@ fn hline( len: u32, color: api.DisplayColor, ) callconv(.C) void { - if (y < 0 or y >= api.screen_height) return; + if (len == 0 or y < 0 or y >= api.screen_height or x >= api.screen_width) return; + const end_x = x +| @min(len, std.math.maxInt(i32)); + if (end_x <= 0) return; - const clamped_x: u32 = @intCast(std.math.clamp(x, 0, @as(i32, @intCast(api.screen_width - 1)))); - const clamped_len = @min(clamped_x + len, api.screen_width) - clamped_x; - - const y_offset = api.screen_width * @as(u32, @intCast(y)); - @memset(api.framebuffer[y_offset + clamped_x ..][0..clamped_len], color); + const pixel = api.Pixel.fromColor(color); + for (api.framebuffer[@max(x, 0)..@intCast(@min(end_x, api.screen_width))]) |*col| col[@intCast(y)] = pixel; } fn vline( @@ -501,14 +538,12 @@ fn vline( len: u32, color: api.DisplayColor, ) callconv(.C) void { - if (y + @as(i32, @intCast(len)) <= 0 or x < 0 or x >= @as(i32, @intCast(api.screen_width))) return; - - const start_y: u32 = @intCast(@max(0, y)); - const end_y: u32 = @intCast(@min(api.screen_height, y + @as(i32, @intCast(len)))); + if (len == 0 or x < 0 or x >= api.screen_width or y >= api.screen_height) return; + const end_y = y +| @min(len, std.math.maxInt(i32)); + if (end_y <= 0) return; - for (start_y..end_y) |yy| { - point(@intCast(x), yy, color); - } + const pixel = api.Pixel.fromColor(color); + @memset(api.framebuffer[@intCast(x)][@max(y, 0)..@intCast(@min(end_y, api.screen_height))], pixel); } fn tone( @@ -618,6 +653,10 @@ fn write_flash_page( _ = src; } +fn rand() callconv(.C) u32 { + return 0; +} + fn trace( str_ptr: [*]const User(u8), str_len: usize, diff --git a/src/badge/demos/audio.zig b/src/badge/demos/audio.zig index a4e74b1..e7f88bb 100644 --- a/src/badge/demos/audio.zig +++ b/src/badge/demos/audio.zig @@ -6,8 +6,8 @@ const mclk = hal.clocks.mclk; const timer = hal.timer; const spkr_en_pin = microzig.board.SPKR_EN; -const analog_out_pin = microzig.board.A0; -const led_pin = microzig.board.D13; +const analog_out_pin = microzig.board.A0_SPKR; +const led_pin = microzig.board.A5_D13; pub fn main() !void { spkr_en_pin.set_dir(.out); diff --git a/src/badge/demos/blinky.zig b/src/badge/demos/blinky.zig index 125a860..ebb2c32 100644 --- a/src/badge/demos/blinky.zig +++ b/src/badge/demos/blinky.zig @@ -1,6 +1,6 @@ const microzig = @import("microzig"); -const led_pin = microzig.board.D13; +const led_pin = microzig.board.A5_D13; pub fn main() !void { // Initialize pins diff --git a/src/badge/demos/buttons.zig b/src/badge/demos/buttons.zig index eee42e9..3f4be6b 100644 --- a/src/badge/demos/buttons.zig +++ b/src/badge/demos/buttons.zig @@ -4,7 +4,7 @@ const board = microzig.board; // pins const ButtonPoller = board.ButtonPoller; -const led_pin = board.D13; +const led_pin = board.A5_D13; const Symbol = enum { dot, diff --git a/src/badge/demos/lcd.zig b/src/badge/demos/lcd.zig index 864b88d..caa2952 100644 --- a/src/badge/demos/lcd.zig +++ b/src/badge/demos/lcd.zig @@ -15,9 +15,9 @@ const tft_dc_pin = board.TFT_DC; const tft_cs_pin = board.TFT_CS; const tft_sck_pin = board.TFT_SCK; const tft_mosi_pin = board.TFT_MOSI; -const Lcd = board.Lcd; +const lcd = board.lcd; -var fb: [Lcd.width][Lcd.height]Lcd.Color16 = undefined; +var fb: [lcd.width][lcd.height]lcd.Color16 = undefined; pub fn main() !void { tft_rst_pin.set_dir(.out); @@ -46,36 +46,8 @@ pub fn main() !void { }); timer.init(); - var lcd = Lcd.init(.{ - .spi = sercom.spi.Master.init(.SERCOM4, .{ - .cpha = .LEADING_EDGE, - .cpol = .IDLE_LOW, - .dord = .MSB, - .dopo = .PAD2, - .ref_freq_hz = 48_000_000, - .baud_freq_hz = 4_000_000, - }), - .pins = .{ - .rst = tft_rst_pin, - .lite = tft_lite_pin, - .dc = tft_dc_pin, - .cs = tft_cs_pin, - .sck = tft_sck_pin, - .mosi = tft_mosi_pin, - }, - .fb = .{ - .bpp16 = &fb, - }, - }); - - lcd.clear_screen(.{ - .r = 31, - .g = 0, - .b = 0, - }); - lcd.set_window(0, 0, 10, 10); + lcd.init(.bpp16, @ptrCast(&fb)); - //Lcd.fill16(red16); timer.delay_us(5 * std.time.us_per_s); lcd.invert(); while (true) {} diff --git a/src/badge/demos/light_sensor.zig b/src/badge/demos/light_sensor.zig index 829ff67..ed96990 100644 --- a/src/badge/demos/light_sensor.zig +++ b/src/badge/demos/light_sensor.zig @@ -9,38 +9,49 @@ const timer = hal.timer; const adc0 = hal.adc.num(0); const board = microzig.board; -const led_pin = microzig.board.D13; -const light_sensor_pin = microzig.board.A7_LIGHT; +const led_pin = microzig.board.A5_D13; pub fn main() !void { // enable pins led_pin.set_dir(.out); - light_sensor_pin.set_mux(.B); + microzig.board.A6_LIGHT.set_mux(.B); + microzig.board.A7_VCC.set_mux(.B); // enable clocks gclk.enable_generator(.GCLK1, .DFLL, .{ .divsel = .DIV1, .div = 48, }); + gclk.set_peripheral_clk_gen(.GCLK_TC0_TC1, .GCLK1); + gclk.set_peripheral_clk_gen(.GCLK_ADC0, .GCLK1); + mclk.set_apb_mask(.{ + .TC0 = .enabled, + .TC1 = .enabled, + .ADC0 = .enabled, + }); - mclk.set_apb_mask(.{ .ADC0 = .enabled }); - gclk.set_peripheral_clk_gen(.GCLK_ADC0, .GCLK0); - - // configure ADC - adc0.init(); timer.init(); - while (true) { - const reading = adc0.single_shot_blocking(.AIN6); + adc0.init(.DIV16); + adc0.set_input(.AIN6, .GND, .single_ended, .stop); + adc0.enable(); + var reading: u12 = 0; + reading = reading; + while (true) { + timer.start_delay_us(@as(u32, ~reading)); led_pin.write(.high); - timer.delay_us(@as(u32, 100) * reading); + adc0.start_conversion(); + timer.finish_delay(); + timer.start_delay_us(@as(u32, reading)); led_pin.write(.low); - timer.delay_us(@as(u32, 100) * reading); + adc0.wait_for_result(); + reading = @intCast(adc0.get_result()); + timer.finish_delay(); } } -fn delay_count(count: u32) void { - var i: u32 = 0; - while (i < count) : (i += 1) {} -} +const ADC0 = microzig.chip.peripherals.ADC0; +const NVMCTRL = struct { + pub const SW0: *volatile microzig.chip.types.peripherals.FUSES.SW0_FUSES = @ptrFromInt(0x00800080); +}; diff --git a/src/badge/demos/neopixels.zig b/src/badge/demos/neopixels.zig index efe9ae9..d23fb20 100644 --- a/src/badge/demos/neopixels.zig +++ b/src/badge/demos/neopixels.zig @@ -1,8 +1,8 @@ const cart = @import("cart-api"); -pub export fn start() void {} +export fn start() void {} -pub export fn update() void { +export fn update() void { cart.neopixels.* = if (cart.controls.a) .{ .{ .r = 31, .g = 0, .b = 0 }, .{ .r = 31, .g = 0, .b = 0 }, diff --git a/src/badge/demos/song.zig b/src/badge/demos/song.zig index 9d5c50a..33240cd 100644 --- a/src/badge/demos/song.zig +++ b/src/badge/demos/song.zig @@ -177,10 +177,10 @@ var time: f32 = 0.0; var channels_note_index = [1]usize{0} ** song.len; var channels_note_start = [1]f32{0.0} ** song.len; -pub export fn start() void {} +export fn start() void {} -pub export fn update() void { - time += 1.0 / 10.0; // TODO: should be higher fps once lcd is dma'd +export fn update() void { + time += 1.0 / 11.5; // TODO: should be higher fps once lcd is dma'd for ( 0.., &channels_note_index, diff --git a/src/board.zig b/src/board.zig index a76cada..cbea9b2 100644 --- a/src/board.zig +++ b/src/board.zig @@ -14,16 +14,17 @@ const port = hal.port; pub const NeopixelColor = @import("board/neopixel.zig").Color; pub const Neopixels = @import("board/neopixel.zig").Group(5); -pub const Lcd = @import("board/lcd.zig").Lcd; +pub const lcd = @import("board/lcd.zig"); pub const audio = @import("board/audio.zig"); pub const TFT_RST = port.pin(.a, 0); pub const TFT_LITE = port.pin(.a, 1); -pub const A0 = port.pin(.a, 2); -pub const AVCC = port.pin(.a, 3); -pub const A6_VMEAS = port.pin(.a, 4); -pub const D13 = port.pin(.a, 5); -pub const A7_LIGHT = port.pin(.a, 6); +pub const A0_SPKR = port.pin(.a, 2); +pub const A1_VCC = port.pin(.a, 3); +pub const A4_VMEAS = port.pin(.a, 4); +pub const A5_D13 = port.pin(.a, 5); +pub const A6_LIGHT = port.pin(.a, 6); +pub const A7_VCC = port.pin(.a, 7); pub const qspi = [_]port.Pin{ port.pin(.a, 8), diff --git a/src/board/audio.zig b/src/board/audio.zig index c0f623a..cd532ff 100644 --- a/src/board/audio.zig +++ b/src/board/audio.zig @@ -24,17 +24,21 @@ pub const Channel = struct { pub fn init() void { @setCold(true); - board.A0.set_dir(.out); - board.AVCC.set_dir(.in); + board.A0_SPKR.set_dir(.out); + board.A1_VCC.set_dir(.in); board.SPKR_EN.set_dir(.out); board.SPKR_EN.write(.low); clocks.gclk.set_peripheral_clk_gen(.GCLK_DAC, .GCLK3); DAC.CTRLA.write(.{ .SWRST = 1, .ENABLE = 0, .padding = 0 }); while (DAC.SYNCBUSY.read().SWRST != 0) {} - board.A0.set_mux(.B); - board.AVCC.set_mux(.B); - DAC.CTRLB.write(.{ .DIFF = 0, .REFSEL = .{ .value = .VREFPU }, .padding = 0 }); + board.A0_SPKR.set_mux(.B); + board.A1_VCC.set_mux(.B); + DAC.CTRLB.write(.{ + .DIFF = 0, + .REFSEL = .{ .value = .VREFPU }, + .padding = 0, + }); DAC.EVCTRL.write(.{ .STARTEI0 = 1, .STARTEI1 = 0, @@ -283,464 +287,6 @@ const channels: *volatile [4]Channel = &channels_storage; var sample_buffer_storage: [2][512]u16 = .{.{0} ** 512} ** 2; -pub const dma = struct { - pub fn init_audio() void { - dma.init(); - DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ - .SWRST = 0, - .ENABLE = 0, - .reserved6 = 0, - .RUNSTDBY = 0, - .reserved8 = 0, - .TRIGSRC = .{ .raw = 0 }, - .reserved20 = 0, - .TRIGACT = .{ .raw = 0 }, - .reserved24 = 0, - .BURSTLEN = .{ .raw = 0 }, - .THRESHOLD = .{ .raw = 0 }, - .padding = 0, - }); - while (DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.read().ENABLE != 0) {} - DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ - .SWRST = 1, - .ENABLE = 0, - .reserved6 = 0, - .RUNSTDBY = 0, - .reserved8 = 0, - .TRIGSRC = .{ .raw = 0 }, - .reserved20 = 0, - .TRIGACT = .{ .raw = 0 }, - .reserved24 = 0, - .BURSTLEN = .{ .raw = 0 }, - .THRESHOLD = .{ .raw = 0 }, - .padding = 0, - }); - while (DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.read().SWRST != 0) {} - DMAC.CHANNEL[CHANNEL.AUDIO].CHINTENSET.write(.{ - .TERR = 0, - .TCMPL = 1, - .SUSP = 0, - .padding = 0, - }); - const len0 = @sizeOf(@TypeOf(audio.sample_buffer[0])); - desc[DESC.AUDIO0].BTCTRL.write(.{ - .VALID = 1, - .EVOSEL = .{ .value = .DISABLE }, - .BLOCKACT = .{ .value = .INT }, - .reserved8 = 0, - .BEATSIZE = .{ .value = .HWORD }, - .SRCINC = 1, - .DSTINC = 0, - .STEPSEL = .{ .value = .SRC }, - .STEPSIZE = .{ .value = .X1 }, - }); - desc[DESC.AUDIO0].BTCNT.write(.{ .BTCNT = @divExact(len0, 2) }); - desc[DESC.AUDIO0].SRCADDR.write(.{ .SRCADDR = @intFromPtr(&audio.sample_buffer[0]) + len0 }); - desc[DESC.AUDIO0].DSTADDR.write(.{ .CHKINIT = @intFromPtr(&DAC.DATABUF[0]) }); - desc[DESC.AUDIO0].DESCADDR.write(.{ .DESCADDR = @intFromPtr(&desc[DESC.AUDIO1]) }); - const len1 = @sizeOf(@TypeOf(audio.sample_buffer[1])); - desc[DESC.AUDIO1].BTCTRL.write(.{ - .VALID = 1, - .EVOSEL = .{ .value = .DISABLE }, - .BLOCKACT = .{ .value = .INT }, - .reserved8 = 0, - .BEATSIZE = .{ .value = .HWORD }, - .SRCINC = 1, - .DSTINC = 0, - .STEPSEL = .{ .value = .SRC }, - .STEPSIZE = .{ .value = .X1 }, - }); - desc[DESC.AUDIO1].BTCNT.write(.{ .BTCNT = @divExact(len1, 2) }); - desc[DESC.AUDIO1].SRCADDR.write(.{ .SRCADDR = @intFromPtr(&audio.sample_buffer[1]) + len1 }); - desc[DESC.AUDIO1].DSTADDR.write(.{ .CHKINIT = @intFromPtr(&DAC.DATABUF[0]) }); - desc[DESC.AUDIO1].DESCADDR.write(.{ .DESCADDR = @intFromPtr(&desc[DESC.AUDIO0]) }); - microzig.cpu.dmb(); - DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ - .SWRST = 0, - .ENABLE = 1, - .reserved6 = 0, - .RUNSTDBY = 0, - .reserved8 = 0, - .TRIGSRC = .{ .raw = TRIGSRC.DAC_EMPTY0 }, - .reserved20 = 0, - .TRIGACT = .{ .value = .BURST }, - .reserved24 = 0, - .BURSTLEN = .{ .value = .SINGLE }, - .THRESHOLD = .{ .value = .@"1BEAT" }, - .padding = 0, - }); - } - - pub fn get_audio_part() usize { - return (desc_wb[DESC.AUDIO0].SRCADDR.read().SRCADDR - @intFromPtr(audio.sample_buffer) - 1) / - @sizeOf(@TypeOf(audio.sample_buffer[0])); - } - - pub fn ack_audio() void { - DMAC.CHANNEL[CHANNEL.AUDIO].CHINTFLAG.write(.{ - .TERR = 0, - .TCMPL = 1, - .SUSP = 0, - .padding = 0, - }); - } - - pub fn wait_audio(i: usize) void { - while (@intFromBool(desc_wb[DESC.AUDIO0].SRCADDR.read().SRCADDR > @intFromPtr(&audio.buffer[1])) == i) {} - } - - fn init() void { - if (initialized) return; - DMAC.CTRL.write(.{ - .SWRST = 0, - .DMAENABLE = 0, - .reserved8 = 0, - .LVLEN0 = 0, - .LVLEN1 = 0, - .LVLEN2 = 0, - .LVLEN3 = 0, - .padding = 0, - }); - while (DMAC.CTRL.read().DMAENABLE != 0) {} - DMAC.CRCSTATUS.write(.{ - .CRCBUSY = 1, - .CRCZERO = 0, - .CRCERR = 0, - .padding = 0, - }); - while (DMAC.CRCSTATUS.read().CRCBUSY != 0) {} - DMAC.CTRL.write(.{ - .SWRST = 1, - .DMAENABLE = 0, - .reserved8 = 0, - .LVLEN0 = 0, - .LVLEN1 = 0, - .LVLEN2 = 0, - .LVLEN3 = 0, - .padding = 0, - }); - while (DMAC.CTRL.read().SWRST != 0) {} - DMAC.BASEADDR.write(.{ .BASEADDR = @intFromPtr(&desc) }); - DMAC.WRBADDR.write(.{ .WRBADDR = @intFromPtr(&desc_wb) }); - DMAC.CTRL.write(.{ - .SWRST = 0, - .DMAENABLE = 1, - .reserved8 = 0, - .LVLEN0 = 1, - .LVLEN1 = 0, - .LVLEN2 = 0, - .LVLEN3 = 0, - .padding = 0, - }); - while (DMAC.CTRL.read().DMAENABLE == 0) {} - initialized = true; - } - - const CHANNEL = struct { - const LCD = 0; - const AUDIO = 1; - }; - - const DESC = struct { - const LCD = 0; - const AUDIO0 = 1; - const AUDIO1 = 2; - }; - - const TRIGSRC = enum(u7) { - const DISABLE = 0x00; - const RTC_TIMESTAMP = 0x01; - const DSU_DCC0 = 0x02; - const DSU_DCC1 = 0x03; - const SERCOM0_RX = 0x04; - const SERCOM0_TX = 0x05; - const SERCOM1_RX = 0x06; - const SERCOM1_TX = 0x07; - const SERCOM2_RX = 0x08; - const SERCOM2_TX = 0x09; - const SERCOM3_RX = 0x0A; - const SERCOM3_TX = 0x0B; - const SERCOM4_RX = 0x0C; - const SERCOM4_TX = 0x0D; - const SERCOM5_RX = 0x0E; - const SERCOM5_TX = 0x0F; - const SERCOM6_RX = 0x10; - const SERCOM6_TX = 0x11; - const SERCOM7_RX = 0x12; - const SERCOM7_TX = 0x13; - const CAN0_DEBUG = 0x14; - const CAN1_DEBUG = 0x15; - const TCC0_OVF = 0x16; - const TCC0_MC0 = 0x17; - const TCC0_MC1 = 0x18; - const TCC0_MC2 = 0x19; - const TCC0_MC3 = 0x1A; - const TCC0_MC4 = 0x1B; - const TCC0_MC5 = 0x1C; - const TCC1_OVF = 0x1D; - const TCC1_MC0 = 0x1E; - const TCC1_MC1 = 0x1F; - const TCC1_MC2 = 0x20; - const TCC1_MC3 = 0x21; - const TCC2_OVF = 0x22; - const TCC2_MC0 = 0x23; - const TCC2_MC1 = 0x24; - const TCC2_MC2 = 0x25; - const TCC3_OVF = 0x26; - const TCC3_MC0 = 0x27; - const TCC3_MC1 = 0x28; - const TCC4_OVF = 0x29; - const TCC4_MC0 = 0x2A; - const TCC4_MC1 = 0x2B; - const TC0_OVF = 0x2C; - const TC0_MC0 = 0x2D; - const TC0_MC1 = 0x2E; - const TC1_OVF = 0x2F; - const TC1_MC0 = 0x30; - const TC1_MC1 = 0x31; - const TC2_OVF = 0x32; - const TC2_MC0 = 0x33; - const TC2_MC1 = 0x34; - const TC3_OVF = 0x35; - const TC3_MC0 = 0x36; - const TC3_MC1 = 0x37; - const TC4_OVF = 0x38; - const TC4_MC0 = 0x39; - const TC4_MC1 = 0x3A; - const TC5_OVF = 0x3B; - const TC5_MC0 = 0x3C; - const TC5_MC1 = 0x3D; - const TC6_OVF = 0x3E; - const TC6_MC0 = 0x3F; - const TC6_MC1 = 0x40; - const TC7_OVF = 0x41; - const TC7_MC0 = 0x42; - const TC7_MC1 = 0x43; - const ADC0_RESRDY = 0x44; - const ADC0_SEQ = 0x45; - const ADC1_RESRDY = 0x46; - const ADC1_SEQ = 0x47; - const DAC_EMPTY0 = 0x48; - const DAC_EMPTY1 = 0x49; - const DAC_RESRDY0 = 0x4A; - const DAC_RESRDY1 = 0x4B; - const I2S_RX0 = 0x4C; - const IS2_RX1 = 0x4D; - const I2S_TX0 = 0x4E; - const IS2_TX1 = 0x4F; - const PCC_RX = 0x50; - const AES_WR = 0x51; - const AES_RD = 0x52; - const QSPI_RX = 0x53; - const QSPI_TX = 0x54; - }; - - var initialized = false; - var desc: [3]DMAC_DESCRIPTOR align(8) = .{.{ - .BTCTRL = .{ .raw = 0 }, - .BTCNT = .{ .raw = 0 }, - .SRCADDR = .{ .raw = 0 }, - .DSTADDR = .{ .raw = 0 }, - .DESCADDR = .{ .raw = 0 }, - }} ** 3; - var desc_wb: [2]DMAC_DESCRIPTOR align(8) = undefined; -}; - -pub const evsys = struct { - pub const CHANNEL = struct { - pub const AUDIO = 12; - }; - pub const EVGEN = struct { - pub const NONE = 0x00; - pub const OSCCTRL_XOSC_FAIL0 = 0x01; - pub const OSCCTRL_XOSC_FAIL1 = 0x02; - pub const OSC32KCTRL_XOSC32K_FAIL = 0x03; - pub const RTC_PER0 = 0x04; - pub const RTC_PER1 = 0x05; - pub const RTC_PER2 = 0x06; - pub const RTC_PER3 = 0x07; - pub const RTC_PER4 = 0x08; - pub const RTC_PER5 = 0x09; - pub const RTC_PER6 = 0x0A; - pub const RTC_PER7 = 0x0B; - pub const RTC_CMP0 = 0x0C; - pub const RTC_CMP1 = 0x0D; - pub const RTC_CMP2 = 0x0E; - pub const RTC_CMP3 = 0x0F; - pub const RTC_TAMPER = 0x10; - pub const RTC_OVF = 0x11; - pub const EIC_EXTENT0 = 0x12; - pub const EIC_EXTENT1 = 0x13; - pub const EIC_EXTENT2 = 0x14; - pub const EIC_EXTENT3 = 0x15; - pub const EIC_EXTENT4 = 0x16; - pub const EIC_EXTENT5 = 0x17; - pub const EIC_EXTENT6 = 0x18; - pub const EIC_EXTENT7 = 0x19; - pub const EIC_EXTENT8 = 0x1A; - pub const EIC_EXTENT9 = 0x1B; - pub const EIC_EXTENT10 = 0x1C; - pub const EIC_EXTENT11 = 0x1D; - pub const EIC_EXTENT12 = 0x1E; - pub const EIC_EXTENT13 = 0x1F; - pub const EIC_EXTENT14 = 0x20; - pub const EIC_EXTENT15 = 0x21; - pub const DMAC_CH0 = 0x22; - pub const DMAC_CH1 = 0x23; - pub const DMAC_CH2 = 0x24; - pub const DMAC_CH3 = 0x25; - pub const PAC_ACCERR = 0x26; - pub const TCC0_OVF = 0x29; - pub const TCC0_TRG = 0x2A; - pub const TCC0_CNT = 0x2B; - pub const TCC0_MC0 = 0x2C; - pub const TCC0_MC1 = 0x2D; - pub const TCC0_MC2 = 0x2E; - pub const TCC0_MC3 = 0x2F; - pub const TCC0_MC4 = 0x30; - pub const TCC0_MC5 = 0x31; - pub const TCC1_OVF = 0x32; - pub const TCC1_TRG = 0x33; - pub const TCC1_CNT = 0x34; - pub const TCC1_MC0 = 0x35; - pub const TCC1_MC1 = 0x36; - pub const TCC1_MC2 = 0x37; - pub const TCC1_MC3 = 0x38; - pub const TCC2_OVF = 0x39; - pub const TCC2_TRG = 0x3A; - pub const TCC2_CNT = 0x3B; - pub const TCC2_MC0 = 0x3C; - pub const TCC2_MC1 = 0x3D; - pub const TCC2_MC2 = 0x3E; - pub const TCC3_OVF = 0x3F; - pub const TCC3_TRG = 0x40; - pub const TCC3_CNT = 0x41; - pub const TCC3_MC0 = 0x42; - pub const TCC3_MC1 = 0x43; - pub const TCC4_OVF = 0x44; - pub const TCC4_TRG = 0x45; - pub const TCC4_CNT = 0x46; - pub const TCC4_MC0 = 0x47; - pub const TCC4_MC1 = 0x48; - pub const TC0_OVF = 0x49; - pub const TC0_MC0 = 0x4A; - pub const TC0_MC1 = 0x4B; - pub const TC1_OVF = 0x4C; - pub const TC1_MC0 = 0x4D; - pub const TC1_MC1 = 0x4E; - pub const TC2_OVF = 0x4F; - pub const TC2_MC0 = 0x50; - pub const TC2_MC1 = 0x51; - pub const TC3_OVF = 0x52; - pub const TC3_MC0 = 0x53; - pub const TC3_MC1 = 0x54; - pub const TC4_OVF = 0x55; - pub const TC4_MC0 = 0x56; - pub const TC4_MC1 = 0x57; - pub const TC5_OVF = 0x58; - pub const TC5_MC0 = 0x59; - pub const TC5_MC1 = 0x5A; - pub const TC6_OVF = 0x5B; - pub const TC6_MC0 = 0x5C; - pub const TC6_MC1 = 0x5D; - pub const TC7_OVF = 0x5E; - pub const TC7_MC0 = 0x5F; - pub const TC7_MC1 = 0x60; - pub const PDEC_OVF = 0x61; - pub const PDEC_ERR = 0x62; - pub const PDEC_DIR = 0x63; - pub const PDEC_VLC = 0x64; - pub const PDEC_MC0 = 0x65; - pub const PDEC_MC1 = 0x66; - pub const ADC0_RESRDY = 0x67; - pub const ADC0_WINMON = 0x68; - pub const ADC1_RESRDY = 0x69; - pub const ADC1_WINMON = 0x6A; - pub const AC_COMP0 = 0x6B; - pub const AC_COMP1 = 0x6C; - pub const AC_WIN = 0x6D; - pub const DAC_EMPTY0 = 0x6E; - pub const DAC_EMPTY1 = 0x6F; - pub const DAC_RESRDY0 = 0x70; - pub const DAC_RESRDY1 = 0x71; - pub const GMAC_TSU_CMP = 0x72; - pub const TRNG_READY = 0x73; - pub const CCL_LUTOUT0 = 0x74; - pub const CCL_LUTOUT1 = 0x75; - pub const CCL_LUTOUT2 = 0x76; - pub const CCL_LUTOUT3 = 0x77; - }; - pub const USER = struct { - pub const RTC_TAMPER = 0; - pub const PORT_EV0 = 1; - pub const PORT_EV1 = 2; - pub const PORT_EV2 = 3; - pub const PORT_EV3 = 4; - pub const DMA_CH0 = 5; - pub const DMA_CH1 = 6; - pub const DMA_CH2 = 7; - pub const DMA_CH3 = 8; - pub const DMA_CH4 = 9; - pub const DMA_CH5 = 10; - pub const DMA_CH6 = 11; - pub const DMA_CH7 = 12; - pub const CM4_TRACE_START = 14; - pub const CM4_TRACE_STOP = 15; - pub const CM4_TRACE_TRIG = 16; - pub const TCC0_EV0 = 17; - pub const TCC0_EV1 = 18; - pub const TCC0_MC0 = 19; - pub const TCC0_MC1 = 20; - pub const TCC0_MC2 = 21; - pub const TCC0_MC3 = 22; - pub const TCC0_MC4 = 23; - pub const TCC0_MC5 = 24; - pub const TCC1_EV0 = 25; - pub const TCC1_EV1 = 26; - pub const TCC1_MC0 = 27; - pub const TCC1_MC1 = 28; - pub const TCC1_MC2 = 29; - pub const TCC1_MC3 = 30; - pub const TCC2_EV0 = 31; - pub const TCC2_EV1 = 32; - pub const TCC2_MC0 = 33; - pub const TCC2_MC1 = 34; - pub const TCC2_MC2 = 35; - pub const TCC3_EV0 = 36; - pub const TCC3_EV1 = 37; - pub const TCC3_MC0 = 38; - pub const TCC3_MC1 = 39; - pub const TCC4_EV0 = 40; - pub const TCC4_EV1 = 41; - pub const TCC4_MC0 = 42; - pub const TCC4_MC1 = 43; - pub const TC0_EVU = 44; - pub const TC1_EVU = 45; - pub const TC2_EVU = 46; - pub const TC3_EVU = 47; - pub const TC4_EVU = 48; - pub const TC5_EVU = 49; - pub const TC6_EVU = 50; - pub const TC7_EVU = 51; - pub const PDEC_EVU0 = 52; - pub const PDEC_EVU1 = 53; - pub const PDEC_EVU2 = 54; - pub const ADC0_START = 55; - pub const ADC0_SYNC = 56; - pub const ADC1_START = 57; - pub const ADC1_SYNC = 58; - pub const AC_SOC0 = 59; - pub const AC_SOC1 = 60; - pub const DAC_START0 = 61; - pub const DAC_START1 = 62; - pub const CCL_LUTIN0 = 63; - pub const CCL_LUTIN1 = 64; - pub const CCL_LUTIN2 = 65; - pub const CCL_LUTIN3 = 66; - }; -}; - -const audio = @This(); const board = @import("../board.zig"); const std = @import("std"); const microzig = @import("microzig"); @@ -749,8 +295,8 @@ const port = hal.port; const clocks = hal.clocks; const chip = microzig.chip; const DAC = chip.peripherals.DAC; -const DMAC = chip.peripherals.DMAC; -const DMAC_DESCRIPTOR = chip.types.peripherals.DMAC.DMAC_DESCRIPTOR; const TC5 = chip.peripherals.TC5; const NVIC = chip.peripherals.NVIC; const EVSYS = chip.peripherals.EVSYS; +const dma = @import("dma.zig"); +const evsys = @import("evsys.zig"); diff --git a/src/board/dma.zig b/src/board/dma.zig new file mode 100644 index 0000000..828873f --- /dev/null +++ b/src/board/dma.zig @@ -0,0 +1,368 @@ +pub fn init_lcd(bpp: lcd.Bpp, fb: *const volatile lcd.FrameBuffer) void { + @setCold(true); + + init(); + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.write(.{ + .SWRST = 0, + .ENABLE = 0, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = 0 }, + .reserved20 = 0, + .TRIGACT = .{ .raw = 0 }, + .reserved24 = 0, + .BURSTLEN = .{ .raw = 0 }, + .THRESHOLD = .{ .raw = 0 }, + .padding = 0, + }); + while (DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.read().ENABLE != 0) {} + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.write(.{ + .SWRST = 1, + .ENABLE = 0, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = 0 }, + .reserved20 = 0, + .TRIGACT = .{ .raw = 0 }, + .reserved24 = 0, + .BURSTLEN = .{ .raw = 0 }, + .THRESHOLD = .{ .raw = 0 }, + .padding = 0, + }); + while (DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.read().SWRST != 0) {} + desc[DESC.LCD].BTCTRL.write(.{ + .VALID = 1, + .EVOSEL = .{ .value = .DISABLE }, + .BLOCKACT = .{ .value = .BOTH }, + .reserved8 = 0, + .BEATSIZE = .{ .value = .BYTE }, + .SRCINC = 1, + .DSTINC = 0, + .STEPSEL = .{ .value = .SRC }, + .STEPSIZE = .{ .value = .X1 }, + }); + switch (bpp) { + inline else => |tag| { + const len = @sizeOf(std.meta.FieldType(lcd.FrameBuffer, tag)); + desc[DESC.LCD].BTCNT.write(.{ .BTCNT = @divExact(len, 1) }); + desc[DESC.LCD].SRCADDR.write(.{ .SRCADDR = @intFromPtr(&@field(fb, @tagName(tag))) + len }); + }, + } + desc[DESC.LCD].DSTADDR.write(.{ .CHKINIT = @intFromPtr(&SERCOM4.SPIM.DATA) }); + desc[DESC.LCD].DESCADDR.write(.{ .DESCADDR = @intFromPtr(&desc[DESC.LCD]) }); + microzig.cpu.dmb(); + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.write(.{ + .SWRST = 0, + .ENABLE = 1, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = TRIGSRC.SERCOM4_TX }, + .reserved20 = 0, + .TRIGACT = .{ .value = .BURST }, + .reserved24 = 0, + .BURSTLEN = .{ .value = .SINGLE }, + .THRESHOLD = .{ .value = .@"1BEAT" }, + .padding = 0, + }); +} + +pub fn start_lcd() void { + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.modify(.{ .ENABLE = 1 }); + while (DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.read().ENABLE != 1) {} +} + +pub fn stop_lcd() void { + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.modify(.{ .ENABLE = 0 }); + while (DMAC.CHANNEL[CHANNEL.LCD].CHCTRLA.read().ENABLE != 0) {} +} + +pub fn poll_ack_lcd() void { + while (DMAC.CHANNEL[CHANNEL.LCD].CHINTFLAG.read().TCMPL == 0) {} + DMAC.CHANNEL[CHANNEL.LCD].CHINTFLAG.write(.{ + .TERR = 0, + .TCMPL = 1, + .SUSP = 0, + .padding = 0, + }); +} + +pub fn resume_lcd() void { + DMAC.CHANNEL[CHANNEL.LCD].CHCTRLB.write(.{ + .CMD = .{ .value = .RESUME }, + .padding = 0, + }); +} + +pub fn init_audio() void { + init(); + DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ + .SWRST = 0, + .ENABLE = 0, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = 0 }, + .reserved20 = 0, + .TRIGACT = .{ .raw = 0 }, + .reserved24 = 0, + .BURSTLEN = .{ .raw = 0 }, + .THRESHOLD = .{ .raw = 0 }, + .padding = 0, + }); + while (DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.read().ENABLE != 0) {} + DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ + .SWRST = 1, + .ENABLE = 0, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = 0 }, + .reserved20 = 0, + .TRIGACT = .{ .raw = 0 }, + .reserved24 = 0, + .BURSTLEN = .{ .raw = 0 }, + .THRESHOLD = .{ .raw = 0 }, + .padding = 0, + }); + while (DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.read().SWRST != 0) {} + DMAC.CHANNEL[CHANNEL.AUDIO].CHINTENSET.write(.{ + .TERR = 0, + .TCMPL = 1, + .SUSP = 0, + .padding = 0, + }); + const len0 = @sizeOf(@TypeOf(audio.sample_buffer[0])); + desc[DESC.AUDIO0].BTCTRL.write(.{ + .VALID = 1, + .EVOSEL = .{ .value = .DISABLE }, + .BLOCKACT = .{ .value = .INT }, + .reserved8 = 0, + .BEATSIZE = .{ .value = .HWORD }, + .SRCINC = 1, + .DSTINC = 0, + .STEPSEL = .{ .value = .SRC }, + .STEPSIZE = .{ .value = .X1 }, + }); + desc[DESC.AUDIO0].BTCNT.write(.{ .BTCNT = @divExact(len0, 2) }); + desc[DESC.AUDIO0].SRCADDR.write(.{ .SRCADDR = @intFromPtr(&audio.sample_buffer[0]) + len0 }); + desc[DESC.AUDIO0].DSTADDR.write(.{ .CHKINIT = @intFromPtr(&DAC.DATABUF[0]) }); + desc[DESC.AUDIO0].DESCADDR.write(.{ .DESCADDR = @intFromPtr(&desc[DESC.AUDIO1]) }); + const len1 = @sizeOf(@TypeOf(audio.sample_buffer[1])); + desc[DESC.AUDIO1].BTCTRL.write(.{ + .VALID = 1, + .EVOSEL = .{ .value = .DISABLE }, + .BLOCKACT = .{ .value = .INT }, + .reserved8 = 0, + .BEATSIZE = .{ .value = .HWORD }, + .SRCINC = 1, + .DSTINC = 0, + .STEPSEL = .{ .value = .SRC }, + .STEPSIZE = .{ .value = .X1 }, + }); + desc[DESC.AUDIO1].BTCNT.write(.{ .BTCNT = @divExact(len1, 2) }); + desc[DESC.AUDIO1].SRCADDR.write(.{ .SRCADDR = @intFromPtr(&audio.sample_buffer[1]) + len1 }); + desc[DESC.AUDIO1].DSTADDR.write(.{ .CHKINIT = @intFromPtr(&DAC.DATABUF[0]) }); + desc[DESC.AUDIO1].DESCADDR.write(.{ .DESCADDR = @intFromPtr(&desc[DESC.AUDIO0]) }); + microzig.cpu.dmb(); + DMAC.CHANNEL[CHANNEL.AUDIO].CHCTRLA.write(.{ + .SWRST = 0, + .ENABLE = 1, + .reserved6 = 0, + .RUNSTDBY = 0, + .reserved8 = 0, + .TRIGSRC = .{ .raw = TRIGSRC.DAC_EMPTY0 }, + .reserved20 = 0, + .TRIGACT = .{ .value = .BURST }, + .reserved24 = 0, + .BURSTLEN = .{ .value = .SINGLE }, + .THRESHOLD = .{ .value = .@"1BEAT" }, + .padding = 0, + }); +} + +pub fn get_audio_part() usize { + return (desc_wb[DESC.AUDIO0].SRCADDR.read().SRCADDR - @intFromPtr(audio.sample_buffer) - 1) / + @sizeOf(@TypeOf(audio.sample_buffer[0])); +} + +pub fn ack_audio() void { + DMAC.CHANNEL[CHANNEL.AUDIO].CHINTFLAG.write(.{ + .TERR = 0, + .TCMPL = 1, + .SUSP = 0, + .padding = 0, + }); +} + +pub fn wait_audio(i: usize) void { + while (@intFromBool(desc_wb[DESC.AUDIO0].SRCADDR.read().SRCADDR > @intFromPtr(&audio.buffer[1])) == i) {} +} + +fn init() void { + if (initialized) return; + DMAC.CTRL.write(.{ + .SWRST = 0, + .DMAENABLE = 0, + .reserved8 = 0, + .LVLEN0 = 0, + .LVLEN1 = 0, + .LVLEN2 = 0, + .LVLEN3 = 0, + .padding = 0, + }); + while (DMAC.CTRL.read().DMAENABLE != 0) {} + DMAC.CRCSTATUS.write(.{ + .CRCBUSY = 1, + .CRCZERO = 0, + .CRCERR = 0, + .padding = 0, + }); + while (DMAC.CRCSTATUS.read().CRCBUSY != 0) {} + DMAC.CTRL.write(.{ + .SWRST = 1, + .DMAENABLE = 0, + .reserved8 = 0, + .LVLEN0 = 0, + .LVLEN1 = 0, + .LVLEN2 = 0, + .LVLEN3 = 0, + .padding = 0, + }); + while (DMAC.CTRL.read().SWRST != 0) {} + DMAC.BASEADDR.write(.{ .BASEADDR = @intFromPtr(&desc) }); + DMAC.WRBADDR.write(.{ .WRBADDR = @intFromPtr(&desc_wb) }); + DMAC.CTRL.write(.{ + .SWRST = 0, + .DMAENABLE = 1, + .reserved8 = 0, + .LVLEN0 = 1, + .LVLEN1 = 0, + .LVLEN2 = 0, + .LVLEN3 = 0, + .padding = 0, + }); + while (DMAC.CTRL.read().DMAENABLE == 0) {} + initialized = true; +} + +const CHANNEL = struct { + const LCD = 0; + const AUDIO = 1; +}; + +const DESC = struct { + const LCD = 0; + const AUDIO0 = 1; + const AUDIO1 = 2; +}; + +const TRIGSRC = enum(u7) { + const DISABLE = 0x00; + const RTC_TIMESTAMP = 0x01; + const DSU_DCC0 = 0x02; + const DSU_DCC1 = 0x03; + const SERCOM0_RX = 0x04; + const SERCOM0_TX = 0x05; + const SERCOM1_RX = 0x06; + const SERCOM1_TX = 0x07; + const SERCOM2_RX = 0x08; + const SERCOM2_TX = 0x09; + const SERCOM3_RX = 0x0A; + const SERCOM3_TX = 0x0B; + const SERCOM4_RX = 0x0C; + const SERCOM4_TX = 0x0D; + const SERCOM5_RX = 0x0E; + const SERCOM5_TX = 0x0F; + const SERCOM6_RX = 0x10; + const SERCOM6_TX = 0x11; + const SERCOM7_RX = 0x12; + const SERCOM7_TX = 0x13; + const CAN0_DEBUG = 0x14; + const CAN1_DEBUG = 0x15; + const TCC0_OVF = 0x16; + const TCC0_MC0 = 0x17; + const TCC0_MC1 = 0x18; + const TCC0_MC2 = 0x19; + const TCC0_MC3 = 0x1A; + const TCC0_MC4 = 0x1B; + const TCC0_MC5 = 0x1C; + const TCC1_OVF = 0x1D; + const TCC1_MC0 = 0x1E; + const TCC1_MC1 = 0x1F; + const TCC1_MC2 = 0x20; + const TCC1_MC3 = 0x21; + const TCC2_OVF = 0x22; + const TCC2_MC0 = 0x23; + const TCC2_MC1 = 0x24; + const TCC2_MC2 = 0x25; + const TCC3_OVF = 0x26; + const TCC3_MC0 = 0x27; + const TCC3_MC1 = 0x28; + const TCC4_OVF = 0x29; + const TCC4_MC0 = 0x2A; + const TCC4_MC1 = 0x2B; + const TC0_OVF = 0x2C; + const TC0_MC0 = 0x2D; + const TC0_MC1 = 0x2E; + const TC1_OVF = 0x2F; + const TC1_MC0 = 0x30; + const TC1_MC1 = 0x31; + const TC2_OVF = 0x32; + const TC2_MC0 = 0x33; + const TC2_MC1 = 0x34; + const TC3_OVF = 0x35; + const TC3_MC0 = 0x36; + const TC3_MC1 = 0x37; + const TC4_OVF = 0x38; + const TC4_MC0 = 0x39; + const TC4_MC1 = 0x3A; + const TC5_OVF = 0x3B; + const TC5_MC0 = 0x3C; + const TC5_MC1 = 0x3D; + const TC6_OVF = 0x3E; + const TC6_MC0 = 0x3F; + const TC6_MC1 = 0x40; + const TC7_OVF = 0x41; + const TC7_MC0 = 0x42; + const TC7_MC1 = 0x43; + const ADC0_RESRDY = 0x44; + const ADC0_SEQ = 0x45; + const ADC1_RESRDY = 0x46; + const ADC1_SEQ = 0x47; + const DAC_EMPTY0 = 0x48; + const DAC_EMPTY1 = 0x49; + const DAC_RESRDY0 = 0x4A; + const DAC_RESRDY1 = 0x4B; + const I2S_RX0 = 0x4C; + const IS2_RX1 = 0x4D; + const I2S_TX0 = 0x4E; + const IS2_TX1 = 0x4F; + const PCC_RX = 0x50; + const AES_WR = 0x51; + const AES_RD = 0x52; + const QSPI_RX = 0x53; + const QSPI_TX = 0x54; +}; + +var initialized = false; +var desc: [3]DMAC_DESCRIPTOR align(8) = .{.{ + .BTCTRL = .{ .raw = 0 }, + .BTCNT = .{ .raw = 0 }, + .SRCADDR = .{ .raw = 0 }, + .DSTADDR = .{ .raw = 0 }, + .DESCADDR = .{ .raw = 0 }, +}} ** 3; +var desc_wb: [2]DMAC_DESCRIPTOR align(8) = undefined; + +const std = @import("std"); +const audio = @import("audio.zig"); +const DMAC = chip.peripherals.DMAC; +const DMAC_DESCRIPTOR = chip.types.peripherals.DMAC.DMAC_DESCRIPTOR; +const DAC = chip.peripherals.DAC; +const microzig = @import("microzig"); +const chip = microzig.chip; +const lcd = @import("lcd.zig"); +const SERCOM4 = chip.peripherals.SERCOM4; diff --git a/src/board/evsys.zig b/src/board/evsys.zig new file mode 100644 index 0000000..9af8d90 --- /dev/null +++ b/src/board/evsys.zig @@ -0,0 +1,191 @@ +pub const CHANNEL = struct { + pub const AUDIO = 12; +}; +pub const EVGEN = struct { + pub const NONE = 0x00; + pub const OSCCTRL_XOSC_FAIL0 = 0x01; + pub const OSCCTRL_XOSC_FAIL1 = 0x02; + pub const OSC32KCTRL_XOSC32K_FAIL = 0x03; + pub const RTC_PER0 = 0x04; + pub const RTC_PER1 = 0x05; + pub const RTC_PER2 = 0x06; + pub const RTC_PER3 = 0x07; + pub const RTC_PER4 = 0x08; + pub const RTC_PER5 = 0x09; + pub const RTC_PER6 = 0x0A; + pub const RTC_PER7 = 0x0B; + pub const RTC_CMP0 = 0x0C; + pub const RTC_CMP1 = 0x0D; + pub const RTC_CMP2 = 0x0E; + pub const RTC_CMP3 = 0x0F; + pub const RTC_TAMPER = 0x10; + pub const RTC_OVF = 0x11; + pub const EIC_EXTENT0 = 0x12; + pub const EIC_EXTENT1 = 0x13; + pub const EIC_EXTENT2 = 0x14; + pub const EIC_EXTENT3 = 0x15; + pub const EIC_EXTENT4 = 0x16; + pub const EIC_EXTENT5 = 0x17; + pub const EIC_EXTENT6 = 0x18; + pub const EIC_EXTENT7 = 0x19; + pub const EIC_EXTENT8 = 0x1A; + pub const EIC_EXTENT9 = 0x1B; + pub const EIC_EXTENT10 = 0x1C; + pub const EIC_EXTENT11 = 0x1D; + pub const EIC_EXTENT12 = 0x1E; + pub const EIC_EXTENT13 = 0x1F; + pub const EIC_EXTENT14 = 0x20; + pub const EIC_EXTENT15 = 0x21; + pub const DMAC_CH0 = 0x22; + pub const DMAC_CH1 = 0x23; + pub const DMAC_CH2 = 0x24; + pub const DMAC_CH3 = 0x25; + pub const PAC_ACCERR = 0x26; + pub const TCC0_OVF = 0x29; + pub const TCC0_TRG = 0x2A; + pub const TCC0_CNT = 0x2B; + pub const TCC0_MC0 = 0x2C; + pub const TCC0_MC1 = 0x2D; + pub const TCC0_MC2 = 0x2E; + pub const TCC0_MC3 = 0x2F; + pub const TCC0_MC4 = 0x30; + pub const TCC0_MC5 = 0x31; + pub const TCC1_OVF = 0x32; + pub const TCC1_TRG = 0x33; + pub const TCC1_CNT = 0x34; + pub const TCC1_MC0 = 0x35; + pub const TCC1_MC1 = 0x36; + pub const TCC1_MC2 = 0x37; + pub const TCC1_MC3 = 0x38; + pub const TCC2_OVF = 0x39; + pub const TCC2_TRG = 0x3A; + pub const TCC2_CNT = 0x3B; + pub const TCC2_MC0 = 0x3C; + pub const TCC2_MC1 = 0x3D; + pub const TCC2_MC2 = 0x3E; + pub const TCC3_OVF = 0x3F; + pub const TCC3_TRG = 0x40; + pub const TCC3_CNT = 0x41; + pub const TCC3_MC0 = 0x42; + pub const TCC3_MC1 = 0x43; + pub const TCC4_OVF = 0x44; + pub const TCC4_TRG = 0x45; + pub const TCC4_CNT = 0x46; + pub const TCC4_MC0 = 0x47; + pub const TCC4_MC1 = 0x48; + pub const TC0_OVF = 0x49; + pub const TC0_MC0 = 0x4A; + pub const TC0_MC1 = 0x4B; + pub const TC1_OVF = 0x4C; + pub const TC1_MC0 = 0x4D; + pub const TC1_MC1 = 0x4E; + pub const TC2_OVF = 0x4F; + pub const TC2_MC0 = 0x50; + pub const TC2_MC1 = 0x51; + pub const TC3_OVF = 0x52; + pub const TC3_MC0 = 0x53; + pub const TC3_MC1 = 0x54; + pub const TC4_OVF = 0x55; + pub const TC4_MC0 = 0x56; + pub const TC4_MC1 = 0x57; + pub const TC5_OVF = 0x58; + pub const TC5_MC0 = 0x59; + pub const TC5_MC1 = 0x5A; + pub const TC6_OVF = 0x5B; + pub const TC6_MC0 = 0x5C; + pub const TC6_MC1 = 0x5D; + pub const TC7_OVF = 0x5E; + pub const TC7_MC0 = 0x5F; + pub const TC7_MC1 = 0x60; + pub const PDEC_OVF = 0x61; + pub const PDEC_ERR = 0x62; + pub const PDEC_DIR = 0x63; + pub const PDEC_VLC = 0x64; + pub const PDEC_MC0 = 0x65; + pub const PDEC_MC1 = 0x66; + pub const ADC0_RESRDY = 0x67; + pub const ADC0_WINMON = 0x68; + pub const ADC1_RESRDY = 0x69; + pub const ADC1_WINMON = 0x6A; + pub const AC_COMP0 = 0x6B; + pub const AC_COMP1 = 0x6C; + pub const AC_WIN = 0x6D; + pub const DAC_EMPTY0 = 0x6E; + pub const DAC_EMPTY1 = 0x6F; + pub const DAC_RESRDY0 = 0x70; + pub const DAC_RESRDY1 = 0x71; + pub const GMAC_TSU_CMP = 0x72; + pub const TRNG_READY = 0x73; + pub const CCL_LUTOUT0 = 0x74; + pub const CCL_LUTOUT1 = 0x75; + pub const CCL_LUTOUT2 = 0x76; + pub const CCL_LUTOUT3 = 0x77; +}; +pub const USER = struct { + pub const RTC_TAMPER = 0; + pub const PORT_EV0 = 1; + pub const PORT_EV1 = 2; + pub const PORT_EV2 = 3; + pub const PORT_EV3 = 4; + pub const DMA_CH0 = 5; + pub const DMA_CH1 = 6; + pub const DMA_CH2 = 7; + pub const DMA_CH3 = 8; + pub const DMA_CH4 = 9; + pub const DMA_CH5 = 10; + pub const DMA_CH6 = 11; + pub const DMA_CH7 = 12; + pub const CM4_TRACE_START = 14; + pub const CM4_TRACE_STOP = 15; + pub const CM4_TRACE_TRIG = 16; + pub const TCC0_EV0 = 17; + pub const TCC0_EV1 = 18; + pub const TCC0_MC0 = 19; + pub const TCC0_MC1 = 20; + pub const TCC0_MC2 = 21; + pub const TCC0_MC3 = 22; + pub const TCC0_MC4 = 23; + pub const TCC0_MC5 = 24; + pub const TCC1_EV0 = 25; + pub const TCC1_EV1 = 26; + pub const TCC1_MC0 = 27; + pub const TCC1_MC1 = 28; + pub const TCC1_MC2 = 29; + pub const TCC1_MC3 = 30; + pub const TCC2_EV0 = 31; + pub const TCC2_EV1 = 32; + pub const TCC2_MC0 = 33; + pub const TCC2_MC1 = 34; + pub const TCC2_MC2 = 35; + pub const TCC3_EV0 = 36; + pub const TCC3_EV1 = 37; + pub const TCC3_MC0 = 38; + pub const TCC3_MC1 = 39; + pub const TCC4_EV0 = 40; + pub const TCC4_EV1 = 41; + pub const TCC4_MC0 = 42; + pub const TCC4_MC1 = 43; + pub const TC0_EVU = 44; + pub const TC1_EVU = 45; + pub const TC2_EVU = 46; + pub const TC3_EVU = 47; + pub const TC4_EVU = 48; + pub const TC5_EVU = 49; + pub const TC6_EVU = 50; + pub const TC7_EVU = 51; + pub const PDEC_EVU0 = 52; + pub const PDEC_EVU1 = 53; + pub const PDEC_EVU2 = 54; + pub const ADC0_START = 55; + pub const ADC0_SYNC = 56; + pub const ADC1_START = 57; + pub const ADC1_SYNC = 58; + pub const AC_SOC0 = 59; + pub const AC_SOC1 = 60; + pub const DAC_START0 = 61; + pub const DAC_START1 = 62; + pub const CCL_LUTIN0 = 63; + pub const CCL_LUTIN1 = 64; + pub const CCL_LUTIN2 = 65; + pub const CCL_LUTIN3 = 66; +}; diff --git a/src/board/lcd.zig b/src/board/lcd.zig index a75f0a5..db1abc4 100644 --- a/src/board/lcd.zig +++ b/src/board/lcd.zig @@ -1,298 +1,187 @@ -const std = @import("std"); - -const microzig = @import("microzig"); -const hal = microzig.hal; -const sercom = hal.sercom; -const port = hal.port; -const timer = hal.timer; -const clocks = hal.clocks; - -pub const Lcd = struct { - spi: sercom.spi.Master, - pins: Pins, - inverted: bool = false, - fb: FrameBuffer, - - pub const FrameBuffer = union(enum) { - bpp12: *[width][@divExact(height, 2)]Color12, - bpp16: *[width][height]Color16, - bpp24: *[width][height]Color24, - }; - - pub const Color12 = extern struct { - b0_g0: packed struct(u8) { b0: u4, g0: u4 }, - r0_b1: packed struct(u8) { r0: u4, b1: u4 }, - g1_r1: packed struct(u8) { g1: u4, r1: u4 }, - }; - - pub const Color16 = packed struct(u16) { b: u5, g: u6, r: u5 }; - pub const Color24 = extern struct { b: u8, g: u8, r: u8 }; - pub const Rect = struct { x: u8, y: u8, width: u8, height: u8 }; - - pub const width = 160; - pub const height = 128; - - pub const Pins = struct { - rst: port.Pin, - lite: port.Pin, - dc: port.Pin, - cs: port.Pin, - sck: port.Pin, - mosi: port.Pin, - }; - - pub const InitOptions = struct { - spi: sercom.spi.Master, - pins: Pins, - fb: FrameBuffer, - }; - - pub fn init(opts: InitOptions) Lcd { - // initialize pins - const lcd = Lcd{ - .spi = opts.spi, - .pins = opts.pins, - .fb = opts.fb, - }; - - // TODO: I think this has to be initialized before init atm - lcd.pins.rst.set_dir(.out); - lcd.pins.lite.set_dir(.out); - lcd.pins.dc.set_dir(.out); - lcd.pins.cs.set_dir(.out); - lcd.pins.sck.set_dir(.out); - lcd.pins.mosi.set_dir(.out); - - // TODO: signal multiplexing - lcd.pins.mosi.set_mux(.C); - lcd.pins.sck.set_mux(.C); - - lcd.pins.cs.write(.high); - lcd.pins.dc.write(.high); - - lcd.pins.lite.write(.high); - lcd.pins.rst.write(.low); - timer.delay_us(20 * std.time.us_per_ms); - lcd.pins.rst.write(.high); - timer.delay_us(20 * std.time.us_per_ms); - - // TODO: analyze this from the circuitpython repo: - // uint8_t display_init_sequence[] = { - // 0x01, 0 | DELAY, 150, // SWRESET - lcd.send_cmd(ST7735.SWRESET, &.{}); - timer.delay_us(150 * std.time.us_per_ms); - // 0x11, 0 | DELAY, 255, // SLPOUT - lcd.send_cmd(ST7735.SLPOUT, &.{}); - timer.delay_us(255 * std.time.us_per_ms); - // 0xb1, 3, 0x01, 0x2C, 0x2D, // _FRMCTR1 - // 0xb2, 3, 0x01, 0x2C, 0x2D, // - // 0xb3, 6, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, - lcd.send_cmd(ST7735.FRMCTR1, &.{ 0x01, 0x2C, 0x2D }); - lcd.send_cmd(ST7735.FRMCTR2, &.{ 0x01, 0x2C, 0x2D }); - lcd.send_cmd(ST7735.FRMCTR3, &.{ 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D }); - // 0xb4, 1, 0x07, // _INVCTR line inversion - lcd.send_cmd(ST7735.INVCTR, &.{0x07}); - // 0xc0, 3, 0xa2, 0x02, 0x84, // _PWCTR1 GVDD = 4.7V, 1.0uA - lcd.send_cmd(ST7735.PWCTR1, &.{ 0xA2, 0x02, 0x84 }); - // 0xc1, 1, 0xc5, // _PWCTR2 VGH=14.7V, VGL=-7.35V - lcd.send_cmd(ST7735.PWCTR2, &.{0xC5}); - // 0xc2, 2, 0x0a, 0x00, // _PWCTR3 Opamp current small, Boost frequency - lcd.send_cmd(ST7735.PWCTR3, &.{ 0x0A, 0x00 }); - // 0xc3, 2, 0x8a, 0x2a, - lcd.send_cmd(ST7735.PWCTR4, &.{ 0x8A, 0x2A }); - // 0xc4, 2, 0x8a, 0xee, - lcd.send_cmd(ST7735.PWCTR5, &.{ 0x8A, 0xEE }); - // 0xc5, 1, 0x0e, // _VMCTR1 VCOMH = 4V, VOML = -1.1V - lcd.send_cmd(ST7735.VMCTR1, &.{0x0E}); - // 0x2a, 0, // _INVOFF - lcd.send_cmd(ST7735.INVOFF, &.{}); - // 0x36, 1, 0b10100000, // _MADCTL for rotation 0 - // // 1 clk cycle nonoverlap, 2 cycle gate rise, 3 cycle osc equalie, - // // fix on VTL - lcd.send_cmd(ST7735.MADCTL, &.{0b10100000}); - // 0x3a, 1, 0x05, // COLMOD - 16bit color - lcd.send_cmd(ST7735.COLMOD, &.{0x05}); - // 0xe0, 16, 0x02, 0x1c, 0x07, 0x12, // _GMCTRP1 Gamma - // 0x37, 0x32, 0x29, 0x2d, - // 0x29, 0x25, 0x2B, 0x39, - // 0x00, 0x01, 0x03, 0x10, - lcd.send_cmd(ST7735.GMCTRP1, &.{ - 0x02, 0x1c, 0x07, 0x12, - 0x37, 0x32, 0x29, 0x2d, - 0x29, 0x25, 0x2B, 0x39, - 0x00, 0x01, 0x03, 0x10, - }); - // 0xe1, 16, 0x03, 0x1d, 0x07, 0x06, // _GMCTRN1 - // 0x2E, 0x2C, 0x29, 0x2D, - // 0x2E, 0x2E, 0x37, 0x3F, - // 0x00, 0x00, 0x02, 0x10, - lcd.send_cmd(ST7735.GMCTRN1, &.{ - 0x03, 0x1d, 0x07, 0x06, - 0x2E, 0x2C, 0x29, 0x2D, - 0x2E, 0x2E, 0x37, 0x3F, - 0x00, 0x00, 0x02, 0x10, - }); - // 0x2a, 3, 0x02, 0x00, 0x81, // _CASET XSTART = 2, XEND = 129 - lcd.send_cmd(ST7735.CASET, &.{ 0x02, 0x00, 0x81 }); - // 0x2b, 3, 0x02, 0x00, 0x81, // _RASET XSTART = 2, XEND = 129 - lcd.send_cmd(ST7735.RASET, &.{ 0x02, 0x00, 0x81 }); - // 0x13, 0 | DELAY, 10, // _NORON - lcd.send_cmd(ST7735.NORON, &.{}); - timer.delay_us(10 * std.time.us_per_ms); - // 0x29, 0 | DELAY, 100, // _DISPON - lcd.send_cmd(ST7735.DISPON, &.{}); - timer.delay_us(100 * std.time.us_per_ms); - - return lcd; - } - - fn send_cmd(lcd: Lcd, cmd: u8, params: []const u8) void { - lcd.pins.cs.write(.low); - lcd.pins.dc.write(.low); - - lcd.spi.write_blocking(cmd); - - lcd.pins.dc.write(.high); - - if (params.len > 0) - lcd.spi.write_all_blocking(params); - - lcd.pins.cs.write(.high); - } - - pub fn invert(lcd: *Lcd) void { - lcd.stop(); - defer lcd.start(); - - lcd.inverted = !lcd.inverted; - lcd.send_cmd(switch (lcd.inverted) { - false => ST7735.INVOFF, - true => ST7735.INVON, - }, &.{}); - timer.delay_us(1); - } - - pub fn send_color(lcd: Lcd, color: Color16, count: u32) void { - timer.delay_us(1); - lcd.pins.cs.write(.low); - lcd.pins.dc.write(.low); - timer.delay_us(1); - lcd.spi.write_blocking(ST7735.RAMWR); - timer.delay_us(1); - lcd.pins.dc.write(.high); - for (0..count) |_| { - const raw: u16 = @bitCast(color); - lcd.spi.write_blocking(@truncate(raw >> 8)); - lcd.spi.write_blocking(@truncate(raw)); - } - - timer.delay_us(1); - lcd.pins.cs.write(.high); - timer.delay_us(1); - } - - pub fn send_colors(lcd: Lcd, colors: []const Color16) void { - timer.delay_us(1); - lcd.pins.cs.write(.low); - lcd.pins.dc.write(.low); - timer.delay_us(1); - lcd.spi.write_blocking(ST7735.RAMWR); - timer.delay_us(1); - lcd.pins.dc.write(.high); - for (colors) |color| { - const raw: u16 = @bitCast(color); - lcd.spi.write_blocking(@truncate(raw >> 8)); - lcd.spi.write_blocking(@truncate(raw)); - } - - timer.delay_us(1); - lcd.pins.cs.write(.high); - timer.delay_us(1); - } - - pub fn clear_screen(lcd: Lcd, color: Color16) void { - lcd.set_window(0, 0, 128, 160); - lcd.send_color(color, 128 * 160); - } - - pub fn set_window(lcd: Lcd, x0: u8, y0: u8, x1: u8, y1: u8) void { - lcd.send_cmd(ST7735.CASET, &.{ 0x00, x0, 0x00, x1 }); - timer.delay_us(1); - lcd.send_cmd(ST7735.RASET, &.{ 0x00, y0, 0x00, y1 }); - timer.delay_us(1); - } - - pub fn fill16(lcd: Lcd, color: Color16) void { - for (&lcd.fb.bpp16) |*col| @memset(col, color); - } - - pub fn fill24(lcd: Lcd, color: Color24) void { - for (&lcd.fb.bpp24) |*col| @memset(col, color); - } - - pub fn rect16(lcd: Lcd, rect: Rect, fill: Color16, line: Color16) void { - for (0..rect.height) |yo| { - lcd.fb.bpp16[rect.x][rect.y + yo] = line; - } - for (0..rect.width) |xo| { - lcd.fb.bpp16[rect.x + xo][rect.y] = line; - @memset(lcd.fb.bpp16[rect.x + xo][rect.y + 1 .. rect.y + rect.height - 1], fill); - lcd.fb.bpp16[rect.x + xo][rect.y + rect.height - 1] = line; - } - for (0..rect.height) |yo| { - lcd.fb.bpp16[rect.x + rect.width - 1][rect.y + yo] = line; - } - } - - pub fn rect24(lcd: Lcd, rect: Rect, fill: Color24, line: Color24) void { - for (0..rect.height) |yo| { - lcd.fb.bpp24[rect.x][rect.y + yo] = line; - } - for (1..rect.width - 1) |xo| { - lcd.fb.bpp24[rect.x + xo][rect.y] = line; - @memset(lcd.fb.bpp24[rect.x + xo][rect.y + 1 .. rect.y + rect.height - 1], fill); - lcd.fb.bpp24[rect.x + xo][rect.y + rect.height - 1] = line; - } - for (0..rect.height) |yo| { - lcd.fb.bpp24[rect.x + rect.width - 1][rect.y + yo] = line; - } - } - - pub fn blit12(lcd: Lcd) void { - //if (!dma.enable) - lcd.send_cmd(ST7735.RAMWR, std.mem.asBytes(&lcd.fb.bpp12), 1); - } - - pub fn blit16(lcd: Lcd) void { - //if (!dma.enable) - lcd.send_cmd(ST7735.RAMWR, std.mem.asBytes(&lcd.bpp16), 1); - } - - pub fn blit24(lcd: Lcd) void { - //if (!dma.enable) - lcd.send_cmd(ST7735.RAMWR, std.mem.asBytes(&lcd.bpp24), 1); - } - - fn start(lcd: Lcd) void { - _ = lcd; - //if (dma.enable) { - // send_cmd(ST7735.RAMWR, &.{}, 1); - // Port.TFT_CS.write(.low); - // timer.delay(1); - // dma.start_lcd(); - //} - } - - fn stop(lcd: Lcd) void { - _ = lcd; - //if (dma.enable) { - // dma.stop_lcd(); - // timer.delay(1); - // Port.TFT_CS.write(.high); - // timer.delay(1); - //} - } +pub const FrameBuffer = extern union { + bpp12: [width][@divExact(height, 2)]Color12, + bpp16: [width][height]Color16, + bpp24: [width][height]Color24, }; +pub const Bpp = std.meta.FieldEnum(FrameBuffer); +pub const Color12 = extern struct { + b0_g0: packed struct(u8) { b0: u4, g0: u4 }, + r0_b1: packed struct(u8) { r0: u4, b1: u4 }, + g1_r1: packed struct(u8) { g1: u4, r1: u4 }, +}; +pub const Color16 = packed struct(u16) { b: u5, g: u6, r: u5 }; +pub const Color24 = extern struct { b: u8, g: u8, r: u8 }; +pub const Rect = struct { x: u8, y: u8, width: u8, height: u8 }; + +pub const width = 160; +pub const height = 128; + +pub const black16: Color16 = .{ .r = 0x00, .g = 0x00, .b = 0x00 }; +pub const red16: Color16 = .{ .r = 0x1f, .g = 0x00, .b = 0x00 }; +pub const green16: Color16 = .{ .r = 0x00, .g = 0x3f, .b = 0x00 }; +pub const blue16: Color16 = .{ .r = 0x00, .g = 0x00, .b = 0x1f }; +pub const white16: Color16 = .{ .r = 0x1f, .g = 0x3f, .b = 0x1f }; + +pub const black24: Color24 = .{ .r = 0x00, .g = 0x00, .b = 0x00 }; +pub const red24: Color24 = .{ .r = 0xff, .g = 0x00, .b = 0x00 }; +pub const green24: Color24 = .{ .r = 0x00, .g = 0xff, .b = 0x00 }; +pub const blue24: Color24 = .{ .r = 0x00, .g = 0x00, .b = 0xff }; +pub const white24: Color24 = .{ .r = 0xff, .g = 0xff, .b = 0xff }; + +pub fn init(bpp: Bpp, fb: *const volatile FrameBuffer) void { + @setCold(true); + + board.TFT_RST.set_dir(.out); + board.TFT_LITE.set_dir(.out); + board.TFT_DC.set_dir(.out); + board.TFT_CS.set_dir(.out); + board.TFT_SCK.set_dir(.out); + board.TFT_MOSI.set_dir(.out); + + board.TFT_CS.write(.high); + board.TFT_DC.write(.high); + board.TFT_SCK.write(.high); + board.TFT_MOSI.write(.high); + + board.TFT_LITE.write(.high); + board.TFT_RST.write(.low); + timer.delay_us(20 * std.time.ms_per_s); + board.TFT_RST.write(.high); + timer.delay_us(20 * std.time.ms_per_s); + + SERCOM4.SPIM.CTRLA.write(.{ + .SWRST = 1, + .ENABLE = 0, + .MODE = .{ .raw = 0 }, + .reserved7 = 0, + .RUNSTDBY = 0, + .IBON = 0, + .reserved16 = 0, + .DOPO = .{ .raw = 0 }, + .reserved20 = 0, + .DIPO = .{ .raw = 0 }, + .reserved24 = 0, + .FORM = .{ .raw = 0 }, + .CPHA = .{ .raw = 0 }, + .CPOL = .{ .raw = 0 }, + .DORD = .{ .raw = 0 }, + .padding = 0, + }); + while (SERCOM4.SPIM.SYNCBUSY.read().SWRST != 0) {} + board.TFT_SCK.set_mux(.C); + board.TFT_MOSI.set_mux(.C); + SERCOM4.SPIM.BAUD.write(.{ .BAUD = 3 }); + SERCOM4.SPIM.CTRLA.write(.{ + .SWRST = 0, + .ENABLE = 1, + .MODE = .{ .value = .SPI_MASTER }, + .reserved7 = 0, + .RUNSTDBY = 0, + .IBON = 0, + .reserved16 = 0, + .DOPO = .{ .value = .PAD2 }, + .reserved20 = 0, + .DIPO = .{ .value = .PAD0 }, + .reserved24 = 0, + .FORM = .{ .value = .SPI_FRAME }, + .CPHA = .{ .value = .LEADING_EDGE }, + .CPOL = .{ .value = .IDLE_LOW }, + .DORD = .{ .value = .MSB }, + .padding = 0, + }); + while (SERCOM4.SPIM.SYNCBUSY.read().ENABLE != 0) {} + + send_cmd(ST7735.SWRESET, &.{}, 120 * std.time.us_per_ms); + send_cmd(ST7735.SLPOUT, &.{}, 120 * std.time.us_per_ms); + send_cmd(ST7735.INVOFF, &.{}, 1); + send_cmd(ST7735.COLMOD, &.{@intFromEnum(@as(ST7735.COLMOD_PARAM0, switch (bpp) { + .bpp12 => .@"12BPP", + .bpp16 => .@"16BPP", + .bpp24 => .@"24BPP", + }))}, 1); + var ca: [4]u8 = undefined; + std.mem.writeInt(u16, ca[0..2], 0, .big); + std.mem.writeInt(u16, ca[2..4], height - 1, .big); + send_cmd(ST7735.CASET, &ca, 1); + var ra: [4]u8 = undefined; + std.mem.writeInt(u16, ra[0..2], 0, .big); + std.mem.writeInt(u16, ra[2..4], width - 1, .big); + send_cmd(ST7735.RASET, &ra, 1); + send_cmd(ST7735.MADCTL, &.{@bitCast(ST7735.MADCTL_PARAM0{ + .MH = .LEFT_TO_RIGHT, + .RGB = .RGB, + .ML = .TOP_TO_BOTTOM, + .MV = false, + .MX = false, + .MY = true, + })}, 1); + send_cmd(ST7735.FRMCTR1, &.{ 15, 24, 24 }, 1); + send_cmd(ST7735.GMCTRP1, &.{ + 0x02, 0x1c, 0x07, 0x12, + 0x37, 0x32, 0x29, 0x2d, + 0x29, 0x25, 0x2B, 0x39, + 0x00, 0x01, 0x03, 0x10, + }, 1); + send_cmd(ST7735.NORON, &.{}, 10 * std.time.us_per_ms); + send_cmd(ST7735.DISPON, &.{}, 10 * std.time.us_per_ms); + send_cmd(ST7735.RAMWR, &.{}, 1); + + board.TFT_CS.write(.low); + timer.delay_us(1); + dma.init_lcd(bpp, fb); +} + +fn send_cmd(cmd: u8, params: []const u8, delay_us: u32) void { + timer.delay_us(1); + board.TFT_CS.write(.low); + board.TFT_DC.write(.low); + timer.delay_us(1); + SERCOM4.SPIM.DATA.write(.{ .DATA = cmd }); + while (SERCOM4.SPIM.INTFLAG.read().TXC == 0) {} + timer.delay_us(1); + board.TFT_DC.write(.high); + for (params) |param| { + while (SERCOM4.SPIM.INTFLAG.read().DRE == 0) {} + SERCOM4.SPIM.DATA.write(.{ .DATA = param }); + } + while (SERCOM4.SPIM.INTFLAG.read().TXC == 0) {} + timer.delay_us(1); + board.TFT_CS.write(.high); + timer.delay_us(delay_us); +} + +var inverted = false; +pub fn invert() void { + stop(); + inverted = !inverted; + send_cmd(switch (inverted) { + false => ST7735.INVOFF, + true => ST7735.INVON, + }, &.{}, 1); + start(); +} + +fn start() void { + send_cmd(ST7735.RAMWR, &.{}, 1); + board.TFT_CS.write(.low); + timer.delay_us(1); + dma.start_lcd(); +} + +fn stop() void { + dma.stop_lcd(); + timer.delay_us(1); + board.TFT_CS.write(.high); + timer.delay_us(1); +} + +pub fn vsync() void { + dma.poll_ack_lcd(); +} + +pub fn update() void { + dma.resume_lcd(); +} const ST7735 = struct { const NOP = 0x00; @@ -364,3 +253,14 @@ const ST7735 = struct { const GMCTRP1 = 0xE0; const GMCTRN1 = 0xE1; }; + +const board = @import("../board.zig"); +const dma = @import("dma.zig"); +const microzig = @import("microzig"); +const hal = microzig.hal; +const timer = hal.timer; +const clocks = hal.clocks; +const chip = microzig.chip; +const std = @import("std"); +const SERCOM4 = chip.peripherals.SERCOM4; +const NVIC = chip.peripherals.NVIC; diff --git a/src/cart.ld b/src/cart.ld index 2c231b6..bc4e833 100644 --- a/src/cart.ld +++ b/src/cart.ld @@ -12,8 +12,8 @@ MEMORY bootloader (rx!w) : ORIGIN = 0x00000000, LENGTH = 0x00004000 runtime_flash (rx!w) : ORIGIN = 0x00004000, LENGTH = 0x0002C000 cart_flash (rx!w) : ORIGIN = 0x00030000, LENGTH = 0x00080000 - cart_fixed (rw!x) : ORIGIN = 0x20000000, LENGTH = 0x0000A01E - cart_ram (rw!x) : ORIGIN = 0x2000A01E, LENGTH = 0x00015FE2 + cart_fixed (rw!x) : ORIGIN = 0x20000000, LENGTH = 0x0000A020 + cart_ram (rw!x) : ORIGIN = 0x2000A020, LENGTH = 0x00015FE0 runtime_ram (rw!x) : ORIGIN = 0x20020000, LENGTH = 0x00008000 cart_stack (rw!x) : ORIGIN = 0x20028000, LENGTH = 0x00004000 runtime_stack (rw!x) : ORIGIN = 0x2002C000, LENGTH = 0x00004000 @@ -27,6 +27,7 @@ SECTIONS *libcart.a:*(.text*) *libc.a:*(.text*) *libcompiler_rt.a:*(.text*) + *(.text.cart) } >cart_flash .rodata.cart : { diff --git a/src/cart/api.zig b/src/cart/api.zig index 8a8255a..640fdc5 100644 --- a/src/cart/api.zig +++ b/src/cart/api.zig @@ -45,6 +45,20 @@ pub const DisplayColor = packed struct(u16) { }; }; +pub const Pixel = extern struct { + bits: u16, + + pub fn fromColor(color: DisplayColor) Pixel { + return .{ .bits = @byteSwap(@as(u16, @bitCast(color))) }; + } + pub fn toColor(pixel: Pixel) DisplayColor { + return @bitCast(@byteSwap(pixel.bits)); + } + pub fn setColor(pixel: *volatile Pixel, color: DisplayColor) void { + pixel.* = fromColor(color); + } +}; + pub const Controls = packed struct(u9) { /// START button start: bool, @@ -73,7 +87,8 @@ pub const controls: *Controls = @ptrFromInt(base + 0x04); pub const light_level: *u12 = @ptrFromInt(base + 0x06); pub const neopixels: *[5]NeopixelColor = @ptrFromInt(base + 0x08); pub const red_led: *bool = @ptrFromInt(base + 0x1c); -pub const framebuffer: *[screen_width * screen_height]DisplayColor = @ptrFromInt(base + 0x1e); +pub const battery_level: *u12 = @ptrFromInt(base + 0x1e); +pub const framebuffer: *volatile [screen_width][screen_height]Pixel = @ptrFromInt(base + 0x20); // ┌───────────────────────────────────────────────────────────────────────────┐ // │ │ @@ -81,34 +96,6 @@ pub const framebuffer: *[screen_width * screen_height]DisplayColor = @ptrFromInt // │ │ // └───────────────────────────────────────────────────────────────────────────┘ -const platform_specific = if (builtin.target.isWasm()) - struct { - extern fn blit(sprite: [*]const DisplayColor, x: i32, y: i32, width: u32, height: u32, src_x: u32, src_y: u32, stride: u32, flags: BlitOptions.Flags) void; - extern fn line(color: DisplayColor, x1: i32, y1: i32, x2: i32, y2: i32) void; - extern fn oval(stroke_color: DisplayColor.Optional, fill_color: DisplayColor.Optional, x: i32, y: i32, width: u32, height: u32) void; - extern fn rect(stroke_color: DisplayColor.Optional, fill_color: DisplayColor.Optional, x: i32, y: i32, width: u32, height: u32) void; - extern fn text(text_color: DisplayColor.Optional, background_color: DisplayColor.Optional, str_ptr: [*]const u8, str_len: usize, x: i32, y: i32) void; - extern fn hline(color: DisplayColor, x: i32, y: i32, len: u32) void; - extern fn vline(color: DisplayColor, x: i32, y: i32, len: u32) void; - extern fn tone(frequency: u32, duration: u32, volume: u32, flags: ToneOptions.Flags) void; - extern fn read_flash(offset: u32, dst: [*]u8, len: u32) u32; - extern fn write_flash_page(page: u32, src: [*]const u8) void; - extern fn trace(str_ptr: [*]const u8, str_len: usize) void; - } -else - struct { - export fn __return_thunk__() noreturn { - asm volatile (" svc #11"); - unreachable; - } - }; - -comptime { - if (builtin.target.isWasm() or builtin.output_mode == .Lib) { - _ = platform_specific; - } -} - pub const BlitOptions = struct { pub const Flags = packed struct(u32) { flip_x: bool = false, @@ -133,8 +120,10 @@ pub const BlitOptions = struct { /// Copies pixels to the framebuffer. pub inline fn blit(options: BlitOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.blit( + if (builtin.target.isWasm()) { + struct { + extern fn blit(sprite: [*]const DisplayColor, x: i32, y: i32, width: u32, height: u32, src_x: u32, src_y: u32, stride: u32, flags: BlitOptions.Flags) void; + }.blit( options.sprite, options.x, options.y, @@ -161,8 +150,15 @@ pub inline fn blit(options: BlitOptions) void { .stride = options.stride orelse options.width, .flags = options.flags, }; + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #0" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [sprite] "{r0}" (options.sprite), [x] "{r1}" (options.x), [y] "{r2}" (options.y), @@ -182,8 +178,10 @@ pub const LineOptions = struct { /// Draws a line between two points. pub inline fn line(options: LineOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.line(options.color, options.x1, options.y1, options.x2, options.y2); + if (builtin.target.isWasm()) { + struct { + extern fn line(color: DisplayColor, x1: i32, y1: i32, x2: i32, y2: i32) void; + }.line(options.color, options.x1, options.y1, options.x2, options.y2); } else { const rest: extern struct { y2: i32, @@ -192,8 +190,15 @@ pub inline fn line(options: LineOptions) void { .y2 = options.y2, .color = options.color, }; + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #1" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [x1] "{r0}" (options.x1), [y1] "{r1}" (options.y1), [x2] "{r2}" (options.x2), @@ -214,8 +219,10 @@ pub const OvalOptions = struct { /// Draws an oval (or circle). pub inline fn oval(options: OvalOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.oval( + if (builtin.target.isWasm()) { + struct { + extern fn oval(stroke_color: DisplayColor.Optional, fill_color: DisplayColor.Optional, x: i32, y: i32, width: u32, height: u32) void; + }.oval( DisplayColor.Optional.from(options.stroke_color), DisplayColor.Optional.from(options.fill_color), options.x, @@ -233,8 +240,15 @@ pub inline fn oval(options: OvalOptions) void { .stroke_color = DisplayColor.Optional.from(options.stroke_color), .fill_color = DisplayColor.Optional.from(options.fill_color), }; + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #2" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [x] "{r0}" (options.x), [y] "{r1}" (options.y), [width] "{r2}" (options.width), @@ -255,8 +269,10 @@ pub const RectOptions = struct { /// Draws a rectangle. pub inline fn rect(options: RectOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.rect( + if (builtin.target.isWasm()) { + struct { + extern fn rect(stroke_color: DisplayColor.Optional, fill_color: DisplayColor.Optional, x: i32, y: i32, width: u32, height: u32) void; + }.rect( DisplayColor.Optional.from(options.stroke_color), DisplayColor.Optional.from(options.fill_color), options.x, @@ -274,8 +290,15 @@ pub inline fn rect(options: RectOptions) void { .stroke_color = DisplayColor.Optional.from(options.stroke_color), .fill_color = DisplayColor.Optional.from(options.fill_color), }; + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #3" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [x] "{r0}" (options.x), [y] "{r1}" (options.y), [width] "{r2}" (options.width), @@ -295,8 +318,10 @@ pub const TextOptions = struct { /// Draws text using the built-in system font. pub inline fn text(options: TextOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.text( + if (builtin.target.isWasm()) { + struct { + extern fn text(text_color: DisplayColor.Optional, background_color: DisplayColor.Optional, str_ptr: [*]const u8, str_len: usize, x: i32, y: i32) void; + }.text( DisplayColor.Optional.from(options.text_color), DisplayColor.Optional.from(options.background_color), options.str.ptr, @@ -314,8 +339,15 @@ pub inline fn text(options: TextOptions) void { .text_color = DisplayColor.Optional.from(options.text_color), .background_color = DisplayColor.Optional.from(options.background_color), }; + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #4" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [str_ptr] "{r0}" (options.str.ptr), [str_len] "{r1}" (options.str.len), [x] "{r2}" (options.x), @@ -334,16 +366,25 @@ pub const StraightLineOptions = struct { /// Draws a horizontal line pub inline fn hline(options: StraightLineOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.hline( + if (builtin.target.isWasm()) { + struct { + extern fn hline(color: DisplayColor, x: i32, y: i32, len: u32) void; + }.hline( options.color, options.x, options.y, options.len, ); } else { + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #5" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [x] "{r0}" (options.x), [y] "{r1}" (options.y), [len] "{r2}" (options.len), @@ -355,16 +396,25 @@ pub inline fn hline(options: StraightLineOptions) void { /// Draws a vertical line pub inline fn vline(options: StraightLineOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.vline( + if (builtin.target.isWasm()) { + struct { + extern fn vline(color: DisplayColor, x: i32, y: i32, len: u32) void; + }.vline( options.color, options.x, options.y, options.len, ); } else { + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #6" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [x] "{r0}" (options.x), [y] "{r1}" (options.y), [len] "{r2}" (options.len), @@ -417,16 +467,25 @@ pub const ToneOptions = struct { /// Plays a sound tone. pub inline fn tone(options: ToneOptions) void { - if (comptime builtin.target.isWasm()) { - platform_specific.tone( + if (builtin.target.isWasm()) { + struct { + extern fn tone(frequency: u32, duration: u32, volume: u32, flags: ToneOptions.Flags) void; + }.tone( options.frequency, options.duration, options.volume, options.flags, ); } else { + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; + var clobber_r3: usize = undefined; asm volatile (" svc #7" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), + [clobber_r3] "={r3}" (clobber_r3), : [frequency] "{r0}" (options.frequency), [duration] "{r1}" (options.duration), [volume] "{r2}" (options.volume), @@ -446,26 +505,39 @@ pub const flash_page_count = 8000; /// Attempts to fill `dst`, returns the amount of bytes actually read pub inline fn read_flash(offset: u32, dst: []u8) u32 { - if (comptime builtin.target.isWasm()) { - return platform_specific.read_flash(offset, dst.ptr, dst.len); + if (builtin.target.isWasm()) { + return struct { + extern fn read_flash(offset: u32, dst: [*]u8, len: u32) u32; + }.read_flash(offset, dst.ptr, dst.len); } else { + var clobber_r1: usize = undefined; + var clobber_r2: usize = undefined; return asm volatile (" svc #8" : [result] "={r0}" (-> u32), + [clobber_r1] "={r1}" (clobber_r1), + [clobber_r2] "={r2}" (clobber_r2), : [offset] "{r0}" (offset), [dst_ptr] "{r1}" (dst.ptr), [dst_len] "{r2}" (dst.len), + : "r3" ); } } pub inline fn write_flash_page(page: u16, src: [flash_page_size]u8) void { - if (comptime builtin.target.isWasm()) { - platform_specific.write_flash_page(page, &src); + if (builtin.target.isWasm()) { + struct { + extern fn write_flash_page(page: u32, src: [*]const u8) void; + }.write_flash_page(page, &src); } else { + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; asm volatile (" svc #9" - : + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), : [page] "{r0}" (page), [src] "{r1}" (&src), + : "r2", "r3" ); } } @@ -476,15 +548,36 @@ pub inline fn write_flash_page(page: u16, src: [flash_page_size]u8) void { // │ │ // └───────────────────────────────────────────────────────────────────────────┘ +/// Returns a random number, useful for seeding a faster prng. +pub inline fn rand() u32 { + if (builtin.target.isWasm()) { + return struct { + extern fn rand() u32; + }.rand(); + } else { + return asm volatile (" svc #10" + : [result] "={r0}" (-> u32), + : + : "r1", "r2", "r3" + ); + } +} + /// Prints a message to the debug console. pub inline fn trace(x: []const u8) void { - if (comptime builtin.target.isWasm()) { - platform_specific.trace(x.ptr, x.len); + if (builtin.target.isWasm()) { + struct { + extern fn trace(str_ptr: [*]const u8, str_len: usize) void; + }.trace(x.ptr, x.len); } else { - asm volatile (" svc #10" - : + var clobber_r0: usize = undefined; + var clobber_r1: usize = undefined; + asm volatile (" svc #11" + : [clobber_r0] "={r0}" (clobber_r0), + [clobber_r1] "={r1}" (clobber_r1), : [x_ptr] "{r0}" (x.ptr), [x_len] "{r1}" (x.len), + : "r2", "r3" ); } } diff --git a/src/hal/adc.zig b/src/hal/adc.zig index 33761f9..63aa483 100644 --- a/src/hal/adc.zig +++ b/src/hal/adc.zig @@ -4,8 +4,10 @@ const NVMCTRL = struct { pub const SW0: *volatile microzig.chip.types.peripherals.FUSES.SW0_FUSES = @ptrFromInt(0x00800080); }; +pub const Div = ADC.ADC_CTRLA__PRESCALER; pub const PositiveInput = ADC.ADC_INPUTCTRL__MUXPOS; pub const NegativeInput = ADC.ADC_INPUTCTRL__MUXNEG; +pub const DiffMode = enum { single_ended, differential }; pub const Adc = enum(u1) { ADC0, @@ -18,12 +20,16 @@ pub const Adc = enum(u1) { }; } - pub fn init(adc: Adc) void { + pub fn init(adc: Adc, div: Div) void { + const regs = adc.get_regs(); + adc.wait_for_sync(.SWRST); adc.reset(); - defer adc.enable(); + regs.CTRLA.modify(.{ + .PRESCALER = .{ .value = div }, + }); adc.calibrate(); // CTRLB @@ -82,7 +88,18 @@ pub const Adc = enum(u1) { pub fn reset(adc: Adc) void { const regs = adc.get_regs(); - regs.CTRLA.modify(.{ .SWRST = 1 }); + regs.CTRLA.write(.{ + .SWRST = 1, + .ENABLE = 0, + .reserved3 = 0, + .DUALSEL = .{ .raw = 0 }, + .SLAVEEN = 0, + .RUNSTDBY = 0, + .ONDEMAND = 0, + .PRESCALER = .{ .raw = 0 }, + .reserved15 = 0, + .R2R = 0, + }); adc.wait_for_sync(.SWRST); } @@ -109,10 +126,21 @@ pub const Adc = enum(u1) { }); } - pub fn set_input(adc: Adc, input: PositiveInput) void { + pub fn set_input( + adc: Adc, + pos: PositiveInput, + neg: NegativeInput, + diff_mode: DiffMode, + seq_stop: enum { continuous, stop }, + ) void { const regs = adc.get_regs(); - regs.INPUTCTRL.modify(.{ - .MUXPOS = .{ .value = input }, + regs.INPUTCTRL.write(.{ + .MUXPOS = .{ .value = pos }, + .reserved7 = 0, + .DIFFMODE = @intFromEnum(diff_mode), + .MUXNEG = .{ .value = neg }, + .reserved15 = 0, + .DSEQSTOP = @intFromEnum(seq_stop), }); adc.wait_for_sync(.INPUTCTRL); @@ -120,26 +148,37 @@ pub const Adc = enum(u1) { pub fn start_conversion(adc: Adc) void { const regs = adc.get_regs(); - regs.SWTRIG.modify(.{ + regs.SWTRIG.write(.{ + .FLUSH = 0, .START = 1, + .padding = 0, }); adc.wait_for_sync(.SWTRIG); + while (regs.SWTRIG.read().START != 0) {} } - pub fn wait_for_result_blocking(adc: Adc) void { + pub fn wait_for_result(adc: Adc) void { const regs = adc.get_regs(); - while (regs.INTFLAG.read().RESRDY == 0) {} + while (regs.INTFLAG.read().RESRDY != 1) {} + regs.INTFLAG.write(.{ + .RESRDY = 1, + .OVERRUN = 0, + .WINMON = 0, + .padding = 0, + }); } - pub fn single_shot_blocking(adc: Adc, input: PositiveInput) u16 { - adc.set_input(input); - adc.start_conversion(); - adc.wait_for_result_blocking(); - + pub fn get_result(adc: Adc) u16 { const regs = adc.get_regs(); return regs.RESULT.read().RESULT; } + + pub fn single_shot_blocking(adc: Adc) u16 { + adc.start_conversion(); + adc.wait_for_result(); + return adc.get_result(); + } }; pub fn num(n: u1) Adc { diff --git a/src/hal/timer.zig b/src/hal/timer.zig index 2cb473c..8076cd5 100644 --- a/src/hal/timer.zig +++ b/src/hal/timer.zig @@ -77,7 +77,6 @@ pub fn init() void { .padding = 0, }); while (TC0.COUNT32.SYNCBUSY.read().SWRST != 0) {} - TC1.COUNT32.CTRLA.write(.{ .SWRST = 1, .ENABLE = 0, @@ -100,6 +99,7 @@ pub fn init() void { .padding = 0, }); while (TC1.COUNT32.SYNCBUSY.read().SWRST != 0) {} + TC0.COUNT32.CTRLA.write(.{ .SWRST = 0, .ENABLE = 1, @@ -132,7 +132,7 @@ pub fn init() void { while (TC0.COUNT32.SYNCBUSY.read().CTRLB != 0) {} } -pub fn start_delay(us: u32) void { +pub fn start_delay_us(us: u32) void { TC0.COUNT32.COUNT.write(.{ .COUNT = us }); while (TC0.COUNT32.SYNCBUSY.read().COUNT != 0) {} TC0.COUNT32.CTRLBSET.write(.{ @@ -150,25 +150,6 @@ pub fn finish_delay() void { } pub fn delay_us(us: u32) void { - start_delay(us); + start_delay_us(us); finish_delay(); } - -pub const GCLK = struct { - pub const GEN = struct { - fn Gen(comptime id: u4) type { - const tag = std.fmt.comptimePrint("GCLK{d}", .{id}); - return struct { - pub const ID = id; - pub const SYNCBUSY_GENCTRL = @intFromEnum(@field(microzig.chip.types.peripherals.GCLK.GCLK_SYNCBUSY__GENCTRL, tag)); - pub const PCHCTRL_GEN = @field(microzig.chip.types.peripherals.GCLK.GCLK_PCHCTRL__GEN, tag); - }; - } - pub const @"120MHz" = Gen(0); - pub const @"76.8KHz" = Gen(1); - pub const @"48MHz" = Gen(2); - pub const @"8.4672MHz" = Gen(3); - pub const @"1MHz" = Gen(4); - pub const @"64KHz" = Gen(11); - }; -}; diff --git a/src/lcd.zig b/src/lcd.zig deleted file mode 100644 index 682277d..0000000 --- a/src/lcd.zig +++ /dev/null @@ -1,311 +0,0 @@ -pub var fb: FrameBuffer = .{ .bpp24 = .{.{.{ .r = 0, .g = 0, .b = 0 }} ** height} ** width }; - -pub const FrameBuffer = union { - bpp12: [width][@divExact(height, 2)]Color12, - bpp16: [width][height]Color16, - bpp24: [width][height]Color24, -}; -pub const Bpp = std.meta.FieldEnum(FrameBuffer); -pub const Color12 = extern struct { - b0_g0: packed struct(u8) { b0: u4, g0: u4 }, - r0_b1: packed struct(u8) { r0: u4, b1: u4 }, - g1_r1: packed struct(u8) { g1: u4, r1: u4 }, -}; -pub const Color16 = packed struct(u16) { b: u5, g: u6, r: u5 }; -pub const Color24 = extern struct { b: u8, g: u8, r: u8 }; -pub const Rect = struct { x: u8, y: u8, width: u8, height: u8 }; - -pub const width = 160; -pub const height = 128; - -pub const black16: Color16 = .{ .r = 0x00, .g = 0x00, .b = 0x00 }; -pub const red16: Color16 = .{ .r = 0x1f, .g = 0x00, .b = 0x00 }; -pub const green16: Color16 = .{ .r = 0x00, .g = 0x3f, .b = 0x00 }; -pub const blue16: Color16 = .{ .r = 0x00, .g = 0x00, .b = 0x1f }; -pub const white16: Color16 = .{ .r = 0x1f, .g = 0x3f, .b = 0x1f }; - -pub const black24: Color24 = .{ .r = 0x00, .g = 0x00, .b = 0x00 }; -pub const red24: Color24 = .{ .r = 0xff, .g = 0x00, .b = 0x00 }; -pub const green24: Color24 = .{ .r = 0x00, .g = 0xff, .b = 0x00 }; -pub const blue24: Color24 = .{ .r = 0x00, .g = 0x00, .b = 0xff }; -pub const white24: Color24 = .{ .r = 0xff, .g = 0xff, .b = 0xff }; - -pub fn init(bpp: Bpp) void { - @setCold(true); - - Port.TFT_RST.set_dir(.out); - Port.TFT_LITE.set_dir(.out); - Port.TFT_DC.set_dir(.out); - Port.TFT_CS.set_dir(.out); - Port.TFT_SCK.set_dir(.out); - Port.TFT_MOSI.set_dir(.out); - - Port.TFT_CS.write(.high); - Port.TFT_DC.write(.high); - Port.TFT_SCK.write(.high); - Port.TFT_MOSI.write(.high); - - Port.TFT_LITE.write(.high); - Port.TFT_RST.write(.low); - timer.delay(20 * std.time.ms_per_s); - Port.TFT_RST.write(.high); - timer.delay(20 * std.time.ms_per_s); - - io.MCLK.APBDMASK.modify(.{ .SERCOM4_ = 1 }); - io.SERCOM4.SPIM.CTRLA.write(.{ - .SWRST = 1, - .ENABLE = 0, - .MODE = .{ .raw = 0 }, - .reserved7 = 0, - .RUNSTDBY = 0, - .IBON = 0, - .reserved16 = 0, - .DOPO = .{ .raw = 0 }, - .reserved20 = 0, - .DIPO = .{ .raw = 0 }, - .reserved24 = 0, - .FORM = .{ .raw = 0 }, - .CPHA = .{ .raw = 0 }, - .CPOL = .{ .raw = 0 }, - .DORD = .{ .raw = 0 }, - .padding = 0, - }); - while (io.SERCOM4.SPIM.SYNCBUSY.read().SWRST != 0) {} - Port.TFT_SCK.set_mux(.C); - Port.TFT_MOSI.set_mux(.C); - io.GCLK.PCHCTRL[GCLK.PCH.SERCOM4_CORE].write(.{ - .GEN = .{ .value = GCLK.GEN.@"120MHz".PCHCTRL_GEN }, - .reserved6 = 0, - .CHEN = 1, - .WRTLOCK = 0, - .padding = 0, - }); - io.SERCOM4.SPIM.BAUD.write(.{ .BAUD = 3 }); - io.SERCOM4.SPIM.CTRLA.write(.{ - .SWRST = 0, - .ENABLE = 1, - .MODE = .{ .value = .SPI_MASTER }, - .reserved7 = 0, - .RUNSTDBY = 0, - .IBON = 0, - .reserved16 = 0, - .DOPO = .{ .value = .PAD2 }, - .reserved20 = 0, - .DIPO = .{ .value = .PAD0 }, - .reserved24 = 0, - .FORM = .{ .value = .SPI_FRAME }, - .CPHA = .{ .value = .LEADING_EDGE }, - .CPOL = .{ .value = .IDLE_LOW }, - .DORD = .{ .value = .MSB }, - .padding = 0, - }); - while (io.SERCOM4.SPIM.SYNCBUSY.read().ENABLE != 0) {} - - send_cmd(ST7735.SWRESET, &.{}, 120 * std.time.us_per_ms); - send_cmd(ST7735.SLPOUT, &.{}, 120 * std.time.us_per_ms); - send_cmd(ST7735.INVOFF, &.{}, 1); - send_cmd(ST7735.COLMOD, &.{@intFromEnum(@as(ST7735.COLMOD_PARAM0, switch (bpp) { - .bpp12 => .@"12BPP", - .bpp16 => .@"16BPP", - .bpp24 => .@"24BPP", - }))}, 1); - send_cmd(ST7735.MADCTL, &.{@as(u8, @bitCast(ST7735.MADCTL_PARAM0{ - .MH = .LEFT_TO_RIGHT, - .RGB = .BGR, - .ML = .TOP_TO_BOTTOM, - .MV = false, - .MX = false, - .MY = true, - }))}, 1); - send_cmd(ST7735.GMCTRP1, &.{ - 0x02, 0x1c, 0x07, 0x12, - 0x37, 0x32, 0x29, 0x2d, - 0x29, 0x25, 0x2B, 0x39, - 0x00, 0x01, 0x03, 0x10, - }, 1); - send_cmd(ST7735.NORON, &.{}, 10 * std.time.us_per_ms); - send_cmd(ST7735.DISPON, &.{}, 10 * std.time.us_per_ms); - send_cmd(ST7735.RAMWR, &.{}, 1); - - if (dma.enable) { - Port.TFT_CS.write(.low); - timer.delay(1); - dma.init_lcd(bpp); - } -} - -pub fn invert() void { - stop(); - inverted = !inverted; - send_cmd(switch (inverted) { - false => ST7735.INVOFF, - true => ST7735.INVON, - }, &.{}, 1); - start(); -} - -pub fn fill16(color: Color16) void { - for (&fb.bpp16) |*col| @memset(col, color); -} - -pub fn fill24(color: Color24) void { - for (&fb.bpp24) |*col| @memset(col, color); -} - -pub fn rect16(rect: Rect, fill: Color16, line: Color16) void { - for (0..rect.height) |yo| { - fb.bpp16[rect.x][rect.y + yo] = line; - } - for (0..rect.width) |xo| { - fb.bpp16[rect.x + xo][rect.y] = line; - @memset(fb.bpp16[rect.x + xo][rect.y + 1 .. rect.y + rect.height - 1], fill); - fb.bpp16[rect.x + xo][rect.y + rect.height - 1] = line; - } - for (0..rect.height) |yo| { - fb.bpp16[rect.x + rect.width - 1][rect.y + yo] = line; - } -} - -pub fn rect24(rect: Rect, fill: Color24, line: Color24) void { - for (0..rect.height) |yo| { - fb.bpp24[rect.x][rect.y + yo] = line; - } - for (1..rect.width - 1) |xo| { - fb.bpp24[rect.x + xo][rect.y] = line; - @memset(fb.bpp24[rect.x + xo][rect.y + 1 .. rect.y + rect.height - 1], fill); - fb.bpp24[rect.x + xo][rect.y + rect.height - 1] = line; - } - for (0..rect.height) |yo| { - fb.bpp24[rect.x + rect.width - 1][rect.y + yo] = line; - } -} - -pub fn blit12() void { - if (!dma.enable) send_cmd(ST7735.RAMWR, std.mem.asBytes(&fb.bpp12), 1); -} - -pub fn blit16() void { - if (!dma.enable) send_cmd(ST7735.RAMWR, std.mem.asBytes(&fb.bpp16), 1); -} - -pub fn blit24() void { - if (!dma.enable) send_cmd(ST7735.RAMWR, std.mem.asBytes(&fb.bpp24), 1); -} - -fn send_cmd(cmd: u8, params: []const u8, delay_us: u32) void { - timer.delay(1); - Port.TFT_CS.write(.low); - Port.TFT_DC.write(.low); - timer.delay(1); - io.SERCOM4.SPIM.DATA.write(.{ .DATA = cmd }); - while (io.SERCOM4.SPIM.INTFLAG.read().TXC == 0) {} - timer.delay(1); - Port.TFT_DC.write(.high); - for (params) |param| { - while (io.SERCOM4.SPIM.INTFLAG.read().DRE == 0) {} - io.SERCOM4.SPIM.DATA.write(.{ .DATA = param }); - } - while (io.SERCOM4.SPIM.INTFLAG.read().TXC == 0) {} - timer.delay(1); - Port.TFT_CS.write(.high); - timer.delay(delay_us); -} - -fn start() void { - if (dma.enable) { - send_cmd(ST7735.RAMWR, &.{}, 1); - Port.TFT_CS.write(.low); - timer.delay(1); - dma.start_lcd(); - } -} - -fn stop() void { - if (dma.enable) { - dma.stop_lcd(); - timer.delay(1); - Port.TFT_CS.write(.high); - timer.delay(1); - } -} - -var inverted = false; - -const ST7735 = struct { - const NOP = 0x00; - const SWRESET = 0x01; - const RDDID = 0x04; - const RDDST = 0x09; - - const SLPIN = 0x10; - const SLPOUT = 0x11; - const PTLON = 0x12; - const NORON = 0x13; - - const INVOFF = 0x20; - const INVON = 0x21; - const DISPOFF = 0x28; - const DISPON = 0x29; - const CASET = 0x2A; - const RASET = 0x2B; - const RAMWR = 0x2C; - const RAMRD = 0x2E; - - const PTLAR = 0x30; - const COLMOD = 0x3A; - const COLMOD_PARAM0 = enum(u8) { - @"12BPP" = 0b011, - @"16BPP" = 0b101, - @"24BPP" = 0b110, - }; - const MADCTL = 0x36; - const MADCTL_PARAM0 = packed struct(u8) { - reserved: u2 = 0, - MH: enum(u1) { - LEFT_TO_RIGHT = 0, - RIGHT_TO_LEFT = 1, - }, - RGB: enum(u1) { - RGB = 0, - BGR = 1, - }, - ML: enum(u1) { - TOP_TO_BOTTOM = 0, - BOTTOM_TO_TOP = 1, - }, - MV: bool, - MX: bool, - MY: bool, - }; - - const FRMCTR1 = 0xB1; - const FRMCTR2 = 0xB2; - const FRMCTR3 = 0xB3; - const INVCTR = 0xB4; - const DISSET5 = 0xB6; - - const PWCTR1 = 0xC0; - const PWCTR2 = 0xC1; - const PWCTR3 = 0xC2; - const PWCTR4 = 0xC3; - const PWCTR5 = 0xC4; - const VMCTR1 = 0xC5; - - const RDID1 = 0xDA; - const RDID2 = 0xDB; - const RDID3 = 0xDC; - const RDID4 = 0xDD; - - const PWCTR6 = 0xFC; - - const GMCTRP1 = 0xE0; - const GMCTRN1 = 0xE1; -}; - -const dma = @import("dma.zig"); -const GCLK = @import("chip.zig").GCLK; -const io = microzig.chip.peripherals; -const microzig = @import("microzig"); -const Port = @import("Port.zig"); -const std = @import("std"); -const timer = @import("timer.zig");