From 5ff7abfcb2800ddb5344aeb7b1a82a3b4992562c Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Tue, 20 May 2025 12:46:03 -0700 Subject: [PATCH 1/3] gpio and uart basics for nrf --- examples/nordic/nrf5x/build.zig | 20 +- examples/nordic/nrf5x/src/blinky.zig | 2 +- examples/nordic/nrf5x/src/uart.zig | 30 +++ port/nordic/nrf5x/build.zig | 57 ++-- port/nordic/nrf5x/build.zig.zon | 4 +- port/nordic/nrf5x/patches/nrf52832.zig | 39 +++ port/nordic/nrf5x/src/boards/pca10040.zig | 39 +++ port/nordic/nrf5x/src/hal.zig | 6 +- port/nordic/nrf5x/src/hal/chip.zig | 4 + port/nordic/nrf5x/src/hal/compatibility.zig | 13 + port/nordic/nrf5x/src/hal/gpio.zig | 50 +++- port/nordic/nrf5x/src/hal/uart.zig | 282 ++++++++++++++++++++ port/nordic/nrf5x/src/hal/uarte.zig | 2 + 13 files changed, 507 insertions(+), 41 deletions(-) create mode 100644 examples/nordic/nrf5x/src/uart.zig create mode 100644 port/nordic/nrf5x/patches/nrf52832.zig create mode 100644 port/nordic/nrf5x/src/boards/pca10040.zig create mode 100644 port/nordic/nrf5x/src/hal/chip.zig create mode 100644 port/nordic/nrf5x/src/hal/compatibility.zig create mode 100644 port/nordic/nrf5x/src/hal/uart.zig create mode 100644 port/nordic/nrf5x/src/hal/uarte.zig diff --git a/examples/nordic/nrf5x/build.zig b/examples/nordic/nrf5x/build.zig index fd5a0ef8..3fd6ec10 100644 --- a/examples/nordic/nrf5x/build.zig +++ b/examples/nordic/nrf5x/build.zig @@ -12,15 +12,27 @@ pub fn build(b: *std.Build) void { const mz_dep = b.dependency("microzig", .{}); const mb = MicroBuild.init(b, mz_dep) orelse return; + const nrf52840_dongle = mb.ports.nrf5x.boards.nordic.nrf52840_dongle; + const nrf52840_mdk = mb.ports.nrf5x.boards.nordic.nrf52840_mdk; + const pca10040 = mb.ports.nrf5x.boards.nordic.pca10040; + const available_examples = [_]Example{ - .{ .target = mb.ports.nrf5x.boards.nordic.nrf52840_dongle, .name = "nrf52480-dongle_blinky", .file = "src/blinky.zig" }, - .{ .target = mb.ports.nrf5x.boards.nordic.nrf52840_mdk, .name = "nrf52480-mdk_blinky", .file = "src/blinky.zig" }, + .{ .target = pca10040, .name = "blinky", .file = "src/blinky.zig" }, + .{ .target = nrf52840_dongle, .name = "blinky", .file = "src/blinky.zig" }, + .{ .target = nrf52840_mdk, .name = "blinky", .file = "src/blinky.zig" }, + .{ .target = pca10040, .name = "uart", .file = "src/uart.zig" }, }; for (available_examples) |example| { + const target = example.target; + const name = mb.builder.fmt("{s}_{s}", .{ + if (target.board) |board| board.name else target.chip.name, + example.name, + }); + // If we specify example, only select the ones that match if (maybe_example) |selected_example| - if (!std.mem.containsAtLeast(u8, example.name, 1, selected_example)) + if (!std.mem.containsAtLeast(u8, name, 1, selected_example)) continue; // `add_firmware` basically works like addExecutable, but takes a @@ -29,7 +41,7 @@ pub fn build(b: *std.Build) void { // The target will convey all necessary information on the chip, // cpu and potentially the board as well. const fw = mb.add_firmware(.{ - .name = example.name, + .name = name, .target = example.target, .optimize = optimize, .root_source_file = b.path(example.file), diff --git a/examples/nordic/nrf5x/src/blinky.zig b/examples/nordic/nrf5x/src/blinky.zig index 33538b60..ea2d39c5 100644 --- a/examples/nordic/nrf5x/src/blinky.zig +++ b/examples/nordic/nrf5x/src/blinky.zig @@ -5,7 +5,7 @@ const board = microzig.board; fn delay(cycles: u32) void { var i: u32 = 0; while (i < cycles) : (i += 1) { - asm volatile ("nop"); + std.mem.doNotOptimizeAway(i); } } diff --git a/examples/nordic/nrf5x/src/uart.zig b/examples/nordic/nrf5x/src/uart.zig new file mode 100644 index 00000000..08f7715a --- /dev/null +++ b/examples/nordic/nrf5x/src/uart.zig @@ -0,0 +1,30 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const board = microzig.board; +const nrf = microzig.hal; + +const uart = nrf.uart.num(0); + +pub fn main() !void { + board.init(); + + uart.apply(.{ + .tx_pin = board.uart_tx, + .rx_pin = board.uart_rx, + .control_flow = .{ + .cts_pin = board.uart_cts, + .rts_pin = board.uart_rts, + }, + .baud_rate = .@"115200", + }); + + nrf.uart.init_logger(uart); + std.log.info("Hello world, I will send back bytes you send me", .{}); + + // now echo any bytes sent + var buf: [1]u8 = undefined; + while (true) { + uart.read_blocking(&buf); + uart.write_blocking(buf[0..]); + } +} diff --git a/port/nordic/nrf5x/build.zig b/port/nordic/nrf5x/build.zig index 786eea00..0f3ade53 100644 --- a/port/nordic/nrf5x/build.zig +++ b/port/nordic/nrf5x/build.zig @@ -4,14 +4,15 @@ const microzig = @import("microzig/build-internals"); const Self = @This(); chips: struct { - nrf52840: *const microzig.Target, nrf52832: *const microzig.Target, + nrf52840: *const microzig.Target, }, boards: struct { nordic: struct { nrf52840_dongle: *const microzig.Target, nrf52840_mdk: *const microzig.Target, + pca10040: *const microzig.Target, }, }, @@ -24,7 +25,7 @@ pub fn init(dep: *std.Build.Dependency) Self { .root_source_file = b.path("src/hal.zig"), }; - const chip_nrf52840: microzig.Target = .{ + const chip_nrf52832: microzig.Target = .{ .dep = dep, .preferred_binary_format = .elf, .zig_target = .{ @@ -34,27 +35,22 @@ pub fn init(dep: *std.Build.Dependency) Self { .abi = .eabi, }, .chip = .{ - .name = "nrf52840", - .url = "https://www.nordicsemi.com/products/nrf52840", + .name = "nrf52", + .url = "https://www.nordicsemi.com/products/nrf52832", .register_definition = .{ - .svd = nrfx.path("mdk/nrf52840.svd"), + // TODO: does this determine the name of the chips/x.zig? + .svd = nrfx.path("mdk/nrf52.svd"), }, .memory_regions = &.{ - .{ .offset = 0x00000000, .length = 0x100000, .kind = .flash }, - .{ .offset = 0x20000000, .length = 0x40000, .kind = .ram }, - - // EXTFLASH - .{ .offset = 0x12000000, .length = 0x8000000, .kind = .flash }, - - // CODE_RAM - .{ .offset = 0x800000, .length = 0x40000, .kind = .ram }, + .{ .offset = 0x00000000, .length = 0x80000, .kind = .flash }, + .{ .offset = 0x20000000, .length = 0x10000, .kind = .ram }, }, - .patches = @import("patches/nrf52840.zig").patches, + .patches = @import("patches/nrf52832.zig").patches, }, - .hal = hal, + .hal = .{ .root_source_file = b.path("src/hal.zig") }, }; - const chip_nrf52832: microzig.Target = .{ + const chip_nrf52840: microzig.Target = .{ .dep = dep, .preferred_binary_format = .elf, .zig_target = .{ @@ -64,22 +60,30 @@ pub fn init(dep: *std.Build.Dependency) Self { .abi = .eabi, }, .chip = .{ - .name = "nrf52", - .url = "https://www.nordicsemi.com/products/nrf52832", + .name = "nrf52840", + .url = "https://www.nordicsemi.com/products/nrf52840", .register_definition = .{ - .svd = nrfx.path("mdk/nrf52.svd"), + .svd = nrfx.path("mdk/nrf52840.svd"), }, .memory_regions = &.{ - .{ .offset = 0x00000000, .length = 0x80000, .kind = .flash }, - .{ .offset = 0x20000000, .length = 0x10000, .kind = .ram }, + .{ .offset = 0x00000000, .length = 0x100000, .kind = .flash }, + .{ .offset = 0x20000000, .length = 0x40000, .kind = .ram }, + + // EXTFLASH + .{ .offset = 0x12000000, .length = 0x8000000, .kind = .flash }, + + // CODE_RAM + .{ .offset = 0x800000, .length = 0x40000, .kind = .ram }, }, + .patches = @import("patches/nrf52840.zig").patches, }, + .hal = hal, }; return .{ .chips = .{ - .nrf52840 = chip_nrf52840.derive(.{}), .nrf52832 = chip_nrf52832.derive(.{}), + .nrf52840 = chip_nrf52840.derive(.{}), }, .boards = .{ .nordic = .{ @@ -93,10 +97,17 @@ pub fn init(dep: *std.Build.Dependency) Self { .nrf52840_mdk = chip_nrf52840.derive(.{ .board = .{ .name = "nRF52840 MDK USB Dongle", - .url = "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/introduction/", + .url = "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle", .root_source_file = b.path("src/boards/nrf52840-mdk.zig"), }, }), + .pca10040 = chip_nrf52832.derive(.{ + .board = .{ + .name = "PCA10040", + .url = "https://www.nordicsemi.com/Products/Development-hardware/nRF52-DK", + .root_source_file = b.path("src/boards/pca10040.zig"), + }, + }), }, }, }; diff --git a/port/nordic/nrf5x/build.zig.zon b/port/nordic/nrf5x/build.zig.zon index eb8c2d97..7030f498 100644 --- a/port/nordic/nrf5x/build.zig.zon +++ b/port/nordic/nrf5x/build.zig.zon @@ -5,8 +5,8 @@ .dependencies = .{ .@"microzig/build-internals" = .{ .path = "../../../build-internals" }, .nrfx = .{ - .url = "https://github.com/NordicSemiconductor/nrfx/archive/refs/tags/v3.9.0.tar.gz", - .hash = "N-V-__8AAL14nQqnG5u7x0tgCPSFD6MxfgtRMqGawtXN3C0S", + .url = "https://github.com/NordicSemiconductor/nrfx/archive/refs/tags/v3.11.0.tar.gz", + .hash = "N-V-__8AABC-kgxbmC3Prd8fgisfbLs1giU34ofX1vz9bwaA", }, }, .paths = .{ diff --git a/port/nordic/nrf5x/patches/nrf52832.zig b/port/nordic/nrf5x/patches/nrf52832.zig new file mode 100644 index 00000000..25c72d12 --- /dev/null +++ b/port/nordic/nrf5x/patches/nrf52832.zig @@ -0,0 +1,39 @@ +const Patch = @import("microzig/build-internals").Patch; + +pub const patches: []const Patch = &.{ + .{ + .add_enum = .{ + .parent = "types.peripherals.P0", + .@"enum" = .{ + .name = "Pull", + .bitsize = 2, + .fields = &.{ + .{ .value = 0x0, .name = "disabled" }, + .{ .value = 0x1, .name = "down" }, + .{ .value = 0x2, .name = "up" }, + }, + }, + }, + }, + .{ .set_enum_type = .{ .of = "types.peripherals.P0.PIN_CNF.PULL", .to = "types.peripherals.P0.Pull" } }, + .{ + .add_enum = .{ + .parent = "types.peripherals.P0", + .@"enum" = .{ + .name = "DriveStrength", + .bitsize = 3, + .fields = &.{ + .{ .value = 0x0, .name = "SOS1" }, + .{ .value = 0x1, .name = "HOS1" }, + .{ .value = 0x2, .name = "SOH1" }, + .{ .value = 0x3, .name = "HOH1" }, + .{ .value = 0x4, .name = "DOS1" }, + .{ .value = 0x5, .name = "DOH1" }, + .{ .value = 0x6, .name = "SOD1" }, + .{ .value = 0x7, .name = "HOD1" }, + }, + }, + }, + }, + .{ .set_enum_type = .{ .of = "types.peripherals.P0.PIN_CNF.DRIVE", .to = "types.peripherals.P0.DriveStrength" } }, +}; diff --git a/port/nordic/nrf5x/src/boards/pca10040.zig b/port/nordic/nrf5x/src/boards/pca10040.zig new file mode 100644 index 00000000..dbdfd405 --- /dev/null +++ b/port/nordic/nrf5x/src/boards/pca10040.zig @@ -0,0 +1,39 @@ +const microzig = @import("microzig"); +const nrf = microzig.hal; +const gpio = nrf.gpio; + +pub const led_active_state = 0; +pub const button_active_state = 0; +pub const button_pull = .pullup; + +pub const leds: []const gpio.Pin = &.{ led1, led2, led3, led4 }; +pub const led1 = gpio.num(0, 17); +pub const led2 = gpio.num(0, 18); +pub const led3 = gpio.num(0, 19); +pub const led4 = gpio.num(0, 20); + +pub const buttons: []const gpio.Pin = &.{ button1, button2, button3, button4 }; +pub const button1 = gpio.num(0, 13); +pub const button2 = gpio.num(0, 14); +pub const button3 = gpio.num(0, 15); +pub const button4 = gpio.num(0, 16); + +// UART +pub const uart_rts = gpio.num(0, 5); +pub const uart_tx = gpio.num(0, 6); +pub const uart_cts = gpio.num(0, 7); +pub const uart_rx = gpio.num(0, 8); +pub const hwfc = true; + +pub fn init() void { + for (leds) |led| + led.set_direction(.out); + + for (buttons) |button| + button.set_direction(.in); + + uart_rx.set_direction(.in); + uart_cts.set_direction(.in); + uart_rts.set_direction(.out); + uart_tx.set_direction(.out); +} diff --git a/port/nordic/nrf5x/src/hal.zig b/port/nordic/nrf5x/src/hal.zig index 87cb9e67..9edd2a4d 100644 --- a/port/nordic/nrf5x/src/hal.zig +++ b/port/nordic/nrf5x/src/hal.zig @@ -1,5 +1,9 @@ +const microzig = @import("microzig"); + +pub const compatibility = @import("hal/compatibility.zig"); pub const gpio = @import("hal/gpio.zig"); -// TODO: uart, adc, timers, pwm, rng, rtc, spi, interrupts, i2c, wdt, wifi, nfc, bt, zigbee +pub const uart = @import("hal/uart.zig"); +// TODO: adc, timers, pwm, rng, rtc, spi, interrupts, i2c, wdt, wifi, nfc, bt, zigbee test "hal tests" { _ = gpio; diff --git a/port/nordic/nrf5x/src/hal/chip.zig b/port/nordic/nrf5x/src/hal/chip.zig new file mode 100644 index 00000000..b073b9c7 --- /dev/null +++ b/port/nordic/nrf5x/src/hal/chip.zig @@ -0,0 +1,4 @@ +pub const Chip = enum { + nrf52, + nrf52840, +}; diff --git a/port/nordic/nrf5x/src/hal/compatibility.zig b/port/nordic/nrf5x/src/hal/compatibility.zig new file mode 100644 index 00000000..72b137ed --- /dev/null +++ b/port/nordic/nrf5x/src/hal/compatibility.zig @@ -0,0 +1,13 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const Chip = @import("chip.zig").Chip; + +pub const chip: Chip = blk: { + if (std.mem.eql(u8, microzig.config.chip_name, "nrf52")) { + break :blk .nrf52; + } else if (std.mem.eql(u8, microzig.config.chip_name, "nrf52840")) { + break :blk .nrf52840; + } else { + @compileError(std.fmt.comptimePrint("Unsupported chip for nRF52 HAL: \"{s}\"", .{microzig.config.chip_name})); + } +}; diff --git a/port/nordic/nrf5x/src/hal/gpio.zig b/port/nordic/nrf5x/src/hal/gpio.zig index dc67e485..e0965538 100644 --- a/port/nordic/nrf5x/src/hal/gpio.zig +++ b/port/nordic/nrf5x/src/hal/gpio.zig @@ -2,12 +2,27 @@ const std = @import("std"); const microzig = @import("microzig"); const peripherals = microzig.chip.peripherals; +const compatibility = @import("compatibility.zig"); pub const Direction = enum(u1) { in, out, }; +pub const Sense = enum(u2) { + disabled = 0x0, + /// sense high level + high = 0x2, + /// sense low level + low = 0x3, + _, +}; + +pub const InputBuffer = enum(u1) { + connect = 0x0, + disconnect = 0x1, +}; + pub const Pull = microzig.chip.types.peripherals.P0.Pull; pub const DriveStrength = microzig.chip.types.peripherals.P0.DriveStrength; @@ -22,10 +37,13 @@ pub const Pin = enum(u6) { // TODO: Add support for LATCH, DETECTMODE fn get_regs(pin: Pin) @TypeOf(peripherals.P0) { - return if (@intFromEnum(pin) <= 31) - peripherals.P0 - else - peripherals.P1; + return switch (compatibility.chip) { + .nrf52 => peripherals.P0, + .nrf52840 => if (@intFromEnum(pin) <= 31) + peripherals.P0 + else + peripherals.P1, + }; } /// Get the index of the pin, relative to its bank @@ -35,8 +53,8 @@ pub const Pin = enum(u6) { } /// Get a bitmask of the pin, appropriate for registers in its bank - pub fn mask(pin: Pin) u31 { - return @as(u31, 1) << pin.index(); + pub fn mask(pin: Pin) u32 { + return @as(u32, 1) << pin.index(); } pub fn set_pull(pin: Pin, pull: Pull) void { @@ -44,6 +62,7 @@ pub const Pin = enum(u6) { regs.PIN_CNF[pin.index()].modify(.{ .PULL = pull }); } + /// Set GPIO pin as input or output pub fn set_direction(pin: Pin, direction: Direction) void { const regs = pin.get_regs(); switch (direction) { @@ -52,6 +71,20 @@ pub const Pin = enum(u6) { } } + pub inline fn set_sense(pin: Pin, sense: Sense) void { + const regs = pin.get_regs(); + regs.PIN_CNF[@intFromEnum(pin)].modify(.{ + .SENSE = @bitCast(sense), + }); + } + + pub inline fn set_input_buffer(pin: Pin, input_buffer: InputBuffer) void { + const regs = pin.get_regs(); + regs.PIN_CNF[@intFromEnum(pin)].modify(.{ + .INPUT = @bitCast(input_buffer), + }); + } + pub inline fn put(pin: Pin, value: u1) void { const regs = pin.get_regs(); switch (value) { @@ -67,10 +100,7 @@ pub const Pin = enum(u6) { pub inline fn read(pin: Pin) u1 { const regs = pin.get_regs(); - return if ((regs.IN.raw & pin.mask()) != 0) - 1 - else - 0; + return @truncate(regs.in.raw >> @intFromEnum(pin)); } pub fn set_drive_strength(pin: Pin, drive_strength: DriveStrength) void { diff --git a/port/nordic/nrf5x/src/hal/uart.zig b/port/nordic/nrf5x/src/hal/uart.zig new file mode 100644 index 00000000..6bfa8126 --- /dev/null +++ b/port/nordic/nrf5x/src/hal/uart.zig @@ -0,0 +1,282 @@ +const std = @import("std"); +const microzig = @import("microzig"); +const peripherals = microzig.chip.peripherals; +const types = microzig.chip.types; + +const UART_Regs = types.peripherals.UART0; + +const gpio = @import("gpio.zig"); + +var uart_logger: ?UART.Writer = null; + +pub fn num(n: u1) UART { + return @enumFromInt(n); +} + +/// Set a specific uart instance to be used for logging. +/// +/// Allows system logging over uart via: +/// pub const microzig_options = .{ +/// .logFn = hal.uart.logFn, +/// }; +pub fn init_logger(uart: UART) void { + uart_logger = uart.writer(); + uart_logger.?.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; +} + +pub fn deinit_logger() void { + uart_logger = null; +} + +pub const Config = struct { + rx_pin: gpio.Pin, + tx_pin: gpio.Pin, + control_flow: ?struct { + cts_pin: gpio.Pin, + rts_pin: gpio.Pin, + } = null, + parity: Parity = .exclude, + baud_rate: BaudRate = .@"9600", +}; + +pub const Parity = enum { + include, + exclude, +}; + +pub const BaudRate = enum { + @"1200", + @"2400", + @"4800", + @"9600", + @"14400", + @"19200", + @"28800", + @"31250", + @"38400", + @"56000", + @"57600", + @"76800", + @"115200", + @"230400", + @"250000", + @"460800", + @"921600", + @"1000000", +}; + +pub const UART = enum(u1) { + _, + + pub const Writer = std.io.GenericWriter(UART, TransmitError, generic_writer_fn); + pub const Reader = std.io.GenericReader(UART, ReceiveError, generic_reader_fn); + + const TransmitError = error{}; + const ReceiveError = error{}; + + inline fn get_regs(uart: UART) *volatile UART_Regs { + return switch (@intFromEnum(uart)) { + 0 => peripherals.UART0, + else => unreachable, + }; + } + + pub fn apply(uart: UART, comptime config: Config) void { + uart.disable(); + defer uart.enable(); + + uart.set_txd(config.tx_pin); + uart.set_rxd(config.rx_pin); + const hwfc = if (config.control_flow) |cf| blk: { + uart.set_cts(cf.cts_pin); + uart.set_rts(cf.rts_pin); + break :blk true; + } else false; + + uart.set_baud_rate(config.baud_rate); + + const regs = uart.get_regs(); + regs.CONFIG.write(.{ + .HWFC = if (hwfc) + .Enabled + else + .Disabled, + .PARITY = switch (config.parity) { + .include => .Included, + .exclude => .Excluded, + }, + }); + + uart.start_rx_task(); + uart.start_tx_task(); + } + + fn set_txd(uart: UART, pin: gpio.Pin) void { + const regs = uart.get_regs(); + regs.PSELTXD.write(.{ .PSELTXD = @enumFromInt(@intFromEnum(pin)) }); + } + + fn set_rxd(uart: UART, pin: gpio.Pin) void { + const regs = uart.get_regs(); + regs.PSELRXD.write(.{ .PSELRXD = @enumFromInt(@intFromEnum(pin)) }); + } + + fn set_cts(uart: UART, pin: gpio.Pin) void { + const regs = uart.get_regs(); + regs.PSELCTS.write(.{ .PSELCTS = @enumFromInt(@intFromEnum(pin)) }); + } + + fn set_rts(uart: UART, pin: gpio.Pin) void { + const regs = uart.get_regs(); + regs.PSELRTS.write(.{ .PSELRTS = @enumFromInt(@intFromEnum(pin)) }); + } + + pub fn set_baud_rate(uart: UART, baud_rate: BaudRate) void { + const regs = uart.get_regs(); + regs.BAUDRATE.write(.{ + .BAUDRATE = switch (baud_rate) { + .@"1200" => .Baud1200, + .@"2400" => .Baud2400, + .@"4800" => .Baud4800, + .@"9600" => .Baud9600, + .@"14400" => .Baud14400, + .@"19200" => .Baud19200, + .@"28800" => .Baud28800, + .@"31250" => .Baud31250, + .@"38400" => .Baud38400, + .@"56000" => .Baud56000, + .@"57600" => .Baud57600, + .@"76800" => .Baud76800, + .@"115200" => .Baud115200, + .@"230400" => .Baud230400, + .@"250000" => .Baud250000, + .@"460800" => .Baud460800, + .@"921600" => .Baud921600, + .@"1000000" => .Baud1M, + }, + }); + } + + pub fn enable(uart: UART) void { + const regs = uart.get_regs(); + regs.ENABLE.write(.{ .ENABLE = .Enabled }); + } + + pub fn disable(uart: UART) void { + const regs = uart.get_regs(); + regs.ENABLE.write(.{ .ENABLE = .Disabled }); + } + + pub fn read_blocking(uart: UART, buffer: []u8) void { + for (buffer) |*b| { + while (!uart.have_rx_rdy_event()) {} + + uart.clear_rx_rdy_event(); + b.* = uart.read_rxd(); + } + } + + pub fn write_blocking(uart: UART, buffer: []const u8) void { + while (!uart.have_tx_rdy_event()) {} + for (buffer) |b| { + uart.write_txd(b); + uart.start_tx_task(); + + while (!uart.have_tx_rdy_event()) {} + } + } + + pub fn reader(uart: UART) Reader { + return .{ .context = uart }; + } + + pub fn writer(uart: UART) Writer { + return .{ .context = uart }; + } + + fn generic_writer_fn(uart: UART, buffer: []const u8) TransmitError!usize { + uart.write_blocking(buffer); + return buffer.len; + } + + fn generic_reader_fn(uart: UART, buffer: []u8) ReceiveError!usize { + uart.read_blocking(buffer); + return buffer.len; + } + + pub fn read_rxd(uart: UART) u8 { + return uart.get_regs().RXD.read().RXD; + } + + pub fn write_txd(uart: UART, byte: u8) void { + return uart.get_regs().TXD.write(.{ + .TXD = byte, + }); + } + + pub fn start_rx_task(uart: UART) void { + const regs = uart.get_regs(); + regs.TASKS_STARTRX.write(.{ .TASKS_STARTRX = .Trigger }); + } + + pub fn stop_rx_task(uart: UART) void { + const regs = uart.get_regs(); + regs.TASKS_STOPRX.write(.{ .TASKS_STOPRX = .Trigger }); + } + + pub fn start_tx_task(uart: UART) void { + const regs = uart.get_regs(); + regs.TASKS_STARTTX.write(.{ .TASKS_STARTTX = .Trigger }); + } + + pub fn stop_tx_task(uart: UART) void { + const regs = uart.get_regs(); + regs.TASKS_STOPTX.write(.{ .TASKS_STOPTX = .Trigger }); + } + + pub fn suspend_task(uart: UART) void { + const regs = uart.get_regs(); + regs.TASKS_SUSPEND.write(.{ .TASKS_SUSPEND = .Trigger }); + } + + pub fn have_rx_rdy_event(uart: UART) bool { + return uart.get_regs().EVENTS_RXDRDY.read().EVENTS_RXDRDY == .Generated; + } + + pub fn clear_rx_rdy_event(uart: UART) void { + uart.get_regs().EVENTS_RXDRDY.raw = 0; + } + + pub fn have_tx_rdy_event(uart: UART) bool { + return uart.get_regs().EVENTS_TXDRDY.read().EVENTS_TXDRDY == .Generated; + } + + pub fn clear_tx_rdy_event(uart: UART) void { + uart.get_regs().EVENTS_TXDRDY.raw = 0; + } + + pub fn have_rx_timeout_event(uart: UART) bool { + return uart.get_regs().EVENTS_RXTO.read().EVENTS_RXTO == .Generated; + } + + pub fn clear_rx_timeout_event(uart: UART) void { + uart.get_regs().EVENTS_RXTO.raw = 0; + } +}; + +pub fn log_fn( + comptime level: std.log.Level, + comptime scope: @TypeOf(.EnumLiteral), + comptime format: []const u8, + args: anytype, +) void { + const level_prefix = comptime level.asText(); + const prefix = comptime level_prefix ++ switch (scope) { + .default => ": ", + else => " (" ++ @tagName(scope) ++ "): ", + }; + + if (uart_logger) |uart| { + uart.print(prefix ++ format ++ "\r\n", args) catch {}; + } +} diff --git a/port/nordic/nrf5x/src/hal/uarte.zig b/port/nordic/nrf5x/src/hal/uarte.zig new file mode 100644 index 00000000..909b1b71 --- /dev/null +++ b/port/nordic/nrf5x/src/hal/uarte.zig @@ -0,0 +1,2 @@ +const microzig = @import("microzig"); +const UARTE = microzig.chip.peripherals.UARTE; From 05695261182e85811207f367784c54aa36218a0b Mon Sep 17 00:00:00 2001 From: Grazfather Date: Wed, 21 May 2025 00:15:49 -0400 Subject: [PATCH 2/3] fix LXP example readme --- examples/nxp/lpc/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/nxp/lpc/README.md b/examples/nxp/lpc/README.md index d6146545..6382804a 100644 --- a/examples/nxp/lpc/README.md +++ b/examples/nxp/lpc/README.md @@ -1,5 +1,3 @@ # Examples for the Port `nxp-lpc` -- [Blinky](src/blinky.zig) on [nRF52840 Dongle](https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle) - TODO: Implement this! - +- [Blinky](src/blinky.zig) on [mbed LPD1768](https://os.mbed.com/platforms/mbed-LPC1768/) From 1cd857582fe50ce0a546d23a5f36e4ee3f36c5e1 Mon Sep 17 00:00:00 2001 From: Grazfather Date: Wed, 21 May 2025 11:50:44 -0400 Subject: [PATCH 3/3] Fix gpio set_sense and set_input_buffer --- port/nordic/nrf5x/src/hal/gpio.zig | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/port/nordic/nrf5x/src/hal/gpio.zig b/port/nordic/nrf5x/src/hal/gpio.zig index e0965538..f081dbd6 100644 --- a/port/nordic/nrf5x/src/hal/gpio.zig +++ b/port/nordic/nrf5x/src/hal/gpio.zig @@ -11,11 +11,8 @@ pub const Direction = enum(u1) { pub const Sense = enum(u2) { disabled = 0x0, - /// sense high level high = 0x2, - /// sense low level low = 0x3, - _, }; pub const InputBuffer = enum(u1) { @@ -74,14 +71,21 @@ pub const Pin = enum(u6) { pub inline fn set_sense(pin: Pin, sense: Sense) void { const regs = pin.get_regs(); regs.PIN_CNF[@intFromEnum(pin)].modify(.{ - .SENSE = @bitCast(sense), + .SENSE = switch (sense) { + .disabled => .Disabled, + .high => .High, + .low => .Low, + }, }); } pub inline fn set_input_buffer(pin: Pin, input_buffer: InputBuffer) void { const regs = pin.get_regs(); regs.PIN_CNF[@intFromEnum(pin)].modify(.{ - .INPUT = @bitCast(input_buffer), + .INPUT = switch (input_buffer) { + .connect => .Connect, + .disconnect => .Disconnect, + }, }); }