From e4c684aaf6fc8aed4502d5a7eff979a780b12b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Fri, 20 Feb 2026 12:07:05 +0100 Subject: [PATCH 1/4] rp2xxx: unique board identifier Existing flash.id() is rp2040 specific. This makes it work on pico2 also. pico sdk reference: https://github.com/raspberrypi/pico-sdk/blob/a1438dff1d38bd9c65dbd693f0e5db4b9ae91779/src/rp2_common/pico_unique_id/include/pico/unique_id.h https://github.com/raspberrypi/pico-sdk/blob/a1438dff1d38bd9c65dbd693f0e5db4b9ae91779/src/rp2_common/pico_unique_id/unique_id.c --- port/raspberrypi/rp2xxx/src/hal.zig | 18 ++++++++++++++++++ port/raspberrypi/rp2xxx/src/hal/rom.zig | 21 +++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/port/raspberrypi/rp2xxx/src/hal.zig b/port/raspberrypi/rp2xxx/src/hal.zig index 853cdb94d..07334d2da 100644 --- a/port/raspberrypi/rp2xxx/src/hal.zig +++ b/port/raspberrypi/rp2xxx/src/hal.zig @@ -144,6 +144,24 @@ pub fn get_cpu_id() u32 { return SIO.CPUID.read().CPUID; } +var board_id: ?[8]u8 = null; + +/// Unique board identifier. +/// On an RP2040-based board, the unique identifier is retrieved from the +/// external NOR flash device +/// On an RP2350-based board, the unique identifier is retrieved from OTP +/// memory. +pub fn get_board_id() [8]u8 { + if (board_id) |b| { + return b; + } + board_id = switch (compatibility.chip) { + .RP2040 => flash.id(), + .RP2350 => rom.get_board_id(), + }; + return board_id.?; +} + test "hal tests" { _ = pio; _ = usb; diff --git a/port/raspberrypi/rp2xxx/src/hal/rom.zig b/port/raspberrypi/rp2xxx/src/hal/rom.zig index 3c25ca48f..ca209dccb 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom.zig @@ -213,3 +213,24 @@ pub fn reset_to_usb_boot() void { }, } } + +pub fn get_sys_info(out_buffer: [*]u32, out_buffer_word_size: u32, flags: u32) void { + switch (chip) { + .RP2040 => unreachable, + .RP2350 => { + const f: *const signatures.get_sys_info = @ptrCast(@alignCast(lookup_function(.get_sys_info))); + const rc = f(out_buffer, out_buffer_word_size, flags); + std.debug.assert(rc == 4); + }, + } +} + +pub fn get_board_id() [8]u8 { + var out: [9]u32 = @splat(0); + get_sys_info(&out, out.len, 0x001); + var buf: [8]u8 = undefined; + for (std.mem.asBytes(out[2..])[0..8], 1..) |b, i| { + buf[8 - i] = b; + } + return buf; +} From 4563c66ece36bc46155f30d14c346c7de0a692c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Fri, 20 Feb 2026 12:14:09 +0100 Subject: [PATCH 2/4] rp2xxx: unique board id example It is no more chip specific. --- examples/raspberrypi/rp2xxx/build.zig | 2 +- .../src/{rp2040_only/flash_id.zig => board_id.zig} | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) rename examples/raspberrypi/rp2xxx/src/{rp2040_only/flash_id.zig => board_id.zig} (66%) diff --git a/examples/raspberrypi/rp2xxx/build.zig b/examples/raspberrypi/rp2xxx/build.zig index 30aca2a77..ea3b8c876 100644 --- a/examples/raspberrypi/rp2xxx/build.zig +++ b/examples/raspberrypi/rp2xxx/build.zig @@ -18,7 +18,6 @@ pub fn build(b: *std.Build) void { // RaspberryPi Boards: .{ .target = raspberrypi.pico, .name = "pico_board_blinky", .file = "src/board_blinky.zig" }, .{ .target = raspberrypi.pico, .name = "pico_flash-program", .file = "src/rp2040_only/flash_program.zig" }, - .{ .target = raspberrypi.pico, .name = "pico_flash-id", .file = "src/rp2040_only/flash_id.zig" }, .{ .target = raspberrypi.pico, .name = "pico_random", .file = "src/rp2040_only/random.zig" }, .{ .target = raspberrypi.pico, .name = "pico_rtc", .file = "src/rp2040_only/rtc.zig" }, .{ .target = raspberrypi.pico, .name = "pico_multicore", .file = "src/blinky_core1.zig" }, @@ -103,6 +102,7 @@ pub fn build(b: *std.Build) void { .{ .name = "net-udp", .file = "src/net/udp.zig" }, .{ .name = "net-tcp_client", .file = "src/net/tcp_client.zig" }, .{ .name = "net-tcp_server", .file = "src/net/tcp_server.zig" }, + .{ .name = "board-id", .file = "src/board_id.zig" }, }; var available_examples: std.array_list.Managed(Example) = .init(b.allocator); diff --git a/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig b/examples/raspberrypi/rp2xxx/src/board_id.zig similarity index 66% rename from examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig rename to examples/raspberrypi/rp2xxx/src/board_id.zig index 894a4b9e5..6581fcd70 100644 --- a/examples/raspberrypi/rp2xxx/src/rp2040_only/flash_id.zig +++ b/examples/raspberrypi/rp2xxx/src/board_id.zig @@ -4,7 +4,6 @@ const microzig = @import("microzig"); const rp2xxx = microzig.hal; const time = rp2xxx.time; const gpio = rp2xxx.gpio; -const flash = rp2xxx.flash; const uart = rp2xxx.uart.instance.num(0); const uart_tx_pin = gpio.num(0); @@ -15,10 +14,11 @@ pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noretu while (true) {} } -pub const std_options = struct { - pub const log_level = .debug; - pub const logFn = rp2xxx.uart.log; +pub const microzig_options = microzig.Options{ + .log_level = .debug, + .logFn = rp2xxx.uart.log, }; +const log = std.log.scoped(.main); pub fn main() !void { // init uart logging @@ -29,9 +29,7 @@ pub fn main() !void { rp2xxx.uart.init_logger(uart); while (true) { - const serial_number = flash.id(); - const hex_serial_number = std.fmt.bytesToHex(&serial_number, .lower); - std.log.info("serial number: {s}", .{hex_serial_number}); + log.info("unique board id: {x}", .{rp2xxx.get_board_id()}); time.sleep_ms(1000); } } From 717fac6efffdb97fd63006579d3d5afad2b20f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Fri, 20 Feb 2026 12:33:21 +0100 Subject: [PATCH 3/4] remove unused imports in touched files As suggested by ci: https://github.com/ZigEmbeddedGroup/microzig/actions/runs/22222166301/job/64279977295?pr=910 --- port/raspberrypi/rp2xxx/src/hal.zig | 1 - port/raspberrypi/rp2xxx/src/hal/rom.zig | 3 --- 2 files changed, 4 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal.zig b/port/raspberrypi/rp2xxx/src/hal.zig index 07334d2da..6e8389e11 100644 --- a/port/raspberrypi/rp2xxx/src/hal.zig +++ b/port/raspberrypi/rp2xxx/src/hal.zig @@ -1,5 +1,4 @@ const builtin = @import("builtin"); -const std = @import("std"); const microzig = @import("microzig"); const SIO = microzig.chip.peripherals.SIO; diff --git a/port/raspberrypi/rp2xxx/src/hal/rom.zig b/port/raspberrypi/rp2xxx/src/hal/rom.zig index ca209dccb..6d72f7192 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom.zig @@ -6,11 +6,8 @@ //! that would otherwise have to take up space in most user binaries. const std = @import("std"); -const microzig = @import("microzig"); const compatibility = @import("compatibility.zig"); -const arch = compatibility.arch; const chip = compatibility.chip; -const options = microzig.options.hal; /// Returns the ROM version number. pub inline fn get_version_number() u8 { From 1937e2b20af83b77057c70859e84058f559cd4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Anic=CC=81?= Date: Fri, 20 Feb 2026 16:14:32 +0100 Subject: [PATCH 4/4] use compile error instead of unreachable For the function which is RP2350 specific. --- port/raspberrypi/rp2xxx/src/hal/rom.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/rom.zig b/port/raspberrypi/rp2xxx/src/hal/rom.zig index 6d72f7192..48f5d7b28 100644 --- a/port/raspberrypi/rp2xxx/src/hal/rom.zig +++ b/port/raspberrypi/rp2xxx/src/hal/rom.zig @@ -213,7 +213,7 @@ pub fn reset_to_usb_boot() void { pub fn get_sys_info(out_buffer: [*]u32, out_buffer_word_size: u32, flags: u32) void { switch (chip) { - .RP2040 => unreachable, + .RP2040 => @compileError("not supported on this chip"), .RP2350 => { const f: *const signatures.get_sys_info = @ptrCast(@alignCast(lookup_function(.get_sys_info))); const rc = f(out_buffer, out_buffer_word_size, flags);