From 05a777ac0e31805a8a7287725368de251bcfa224 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 16 May 2024 14:06:58 -0400 Subject: [PATCH 1/2] lcd dma --- build.zig | 12 +- src/badge.zig | 155 +---------- src/badge/cart.zig | 25 +- src/badge/demos/draw.zig | 13 + src/badge/demos/lcd.zig | 34 +-- src/badge/demos/neopixels.zig | 4 +- src/badge/demos/song.zig | 2 +- src/board.zig | 2 +- src/board/audio.zig | 462 +------------------------------- src/board/dma.zig | 368 +++++++++++++++++++++++++ src/board/evsys.zig | 191 +++++++++++++ src/board/lcd.zig | 488 ++++++++++++++-------------------- src/cart.ld | 1 + src/cart/api.zig | 9 +- src/lcd.zig | 311 ---------------------- 15 files changed, 800 insertions(+), 1277 deletions(-) create mode 100644 src/badge/demos/draw.zig create mode 100644 src/board/dma.zig create mode 100644 src/board/evsys.zig delete mode 100644 src/lcd.zig diff --git a/build.zig b/build.zig index 2c36892..28a0ec1 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"), }, @@ -109,6 +106,7 @@ pub fn build(b: *Build) void { } inline for (.{ + "draw", "neopixels", "song", }) |name| { diff --git a/src/badge.zig b/src/badge.zig index 9a70698..cf7683c 100644 --- a/src/badge.zig +++ b/src/badge.zig @@ -35,7 +35,7 @@ const cart = @import("badge/cart.zig"); const led_pin = board.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; @@ -52,6 +52,7 @@ pub const microzig_options = .{ }; pub fn main() !void { + // Enable safety traps SystemControl.CCR.modify(.{ .NONBASETHRDENA = 0, .USERSETMPEND = 0, @@ -60,11 +61,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 }, @@ -220,7 +217,6 @@ pub fn main() !void { timer.init(); audio.init(); - init_frame_sync(); // Light sensor adc light_sensor_pin.set_mux(.B); @@ -229,29 +225,7 @@ pub fn main() !void { 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(); @@ -260,9 +234,6 @@ pub fn main() !void { cart.start(); while (true) { - //if (!frame_is_ready()) - // continue; - const light_reading = adc.single_shot_blocking(.AIN6); cart.api.light_level.* = @intCast(light_reading); @@ -289,123 +260,5 @@ pub fn main() !void { }; 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..88bf38c 100644 --- a/src/badge/cart.zig +++ b/src/badge/cart.zig @@ -2,6 +2,7 @@ const std = @import("std"); const microzig = @import("microzig"); 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 +15,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 #11"); + unreachable; + } }; pub fn svcall_handler() callconv(.Naked) void { @@ -118,7 +122,7 @@ pub const HSRAM = struct { }; pub fn start() void { - @memset(@as(*[0x19A0]u8, @ptrFromInt(0x20000000)), 0); + @memset(@as(*[0xA01E]u8, @ptrFromInt(0x20000000)), 0); api.neopixels.* = .{ .{ .r = 0, .g = 0, .b = 0 }, .{ .r = 0, .g = 0, .b = 0 }, @@ -149,11 +153,10 @@ 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 { @@ -178,11 +181,11 @@ fn call(func: *const fn () callconv(.C) void) void { 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, diff --git a/src/badge/demos/draw.zig b/src/badge/demos/draw.zig new file mode 100644 index 0000000..bf09def --- /dev/null +++ b/src/badge/demos/draw.zig @@ -0,0 +1,13 @@ +const cart = @import("cart-api"); + +pub export fn start() void {} + +var tick: u32 = 0; + +pub export fn update() void { + @memset(cart.framebuffer, @bitCast(@as(u16, @bitCast(switch (@as(u1, @truncate(tick))) { + 0 => cart.DisplayColor{ .r = 0x1f, .g = 0x00, .b = 0x00 }, + 1 => cart.DisplayColor{ .r = 0x00, .g = 0x3f, .b = 0x00 }, + })))); + tick +%= 1; +} 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/neopixels.zig b/src/badge/demos/neopixels.zig index efe9ae9..dbf64ae 100644 --- a/src/badge/demos/neopixels.zig +++ b/src/badge/demos/neopixels.zig @@ -1,8 +1,6 @@ const cart = @import("cart-api"); -pub export fn start() void {} - -pub export fn update() void { +pub export fn render() 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..422a6c1 100644 --- a/src/badge/demos/song.zig +++ b/src/badge/demos/song.zig @@ -180,7 +180,7 @@ var channels_note_start = [1]f32{0.0} ** song.len; pub export fn start() void {} pub export fn update() void { - time += 1.0 / 10.0; // TODO: should be higher fps once lcd is dma'd + 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..393cc03 100644 --- a/src/board.zig +++ b/src/board.zig @@ -14,7 +14,7 @@ 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); diff --git a/src/board/audio.zig b/src/board/audio.zig index c0f623a..06409f1 100644 --- a/src/board/audio.zig +++ b/src/board/audio.zig @@ -283,464 +283,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 +291,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..1bf724f --- /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 = .INT }, + .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..ca65e04 100644 --- a/src/cart.ld +++ b/src/cart.ld @@ -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..1a47408 100644 --- a/src/cart/api.zig +++ b/src/cart/api.zig @@ -73,7 +73,7 @@ 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 framebuffer: *volatile [screen_height * screen_width]DisplayColor = @ptrFromInt(base + 0x1e); // ┌───────────────────────────────────────────────────────────────────────────┐ // │ │ @@ -96,12 +96,7 @@ const platform_specific = if (builtin.target.isWasm()) extern fn trace(str_ptr: [*]const u8, str_len: usize) void; } else - struct { - export fn __return_thunk__() noreturn { - asm volatile (" svc #11"); - unreachable; - } - }; + struct {}; comptime { if (builtin.target.isWasm() or builtin.output_mode == .Lib) { 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"); From ab46c346fe1de0e0c32dda4fb9dd62d574df6db5 Mon Sep 17 00:00:00 2001 From: Aeden McClain Date: Fri, 17 May 2024 18:24:00 +0200 Subject: [PATCH 2/2] Implement missing functions for neopixels demo --- src/badge/demos/neopixels.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/badge/demos/neopixels.zig b/src/badge/demos/neopixels.zig index dbf64ae..efe9ae9 100644 --- a/src/badge/demos/neopixels.zig +++ b/src/badge/demos/neopixels.zig @@ -1,6 +1,8 @@ const cart = @import("cart-api"); -pub export fn render() void { +pub export fn start() void {} + +pub export fn update() void { cart.neopixels.* = if (cart.controls.a) .{ .{ .r = 31, .g = 0, .b = 0 }, .{ .r = 31, .g = 0, .b = 0 },