Skip to content

Commit 540a525

Browse files
matevzmihalicmattnite
authored andcommitted
rp2040: add flash id function (#182)
1 parent 1ed0296 commit 540a525

File tree

4 files changed

+132
-1
lines changed

4 files changed

+132
-1
lines changed

bsp/raspberrypi/rp2040/src/hal/flash.zig

+89
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
//! See [rp2040 docs](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf), page 136.
22
const rom = @import("rom.zig");
33

4+
const microzig = @import("microzig");
5+
const peripherals = microzig.chip.peripherals;
6+
7+
const IO_QSPI = peripherals.IO_QSPI;
8+
const XIP_SSI = peripherals.XIP_SSI;
9+
410
pub const Command = enum(u8) {
511
block_erase = 0xd8,
612
ruid_cmd = 0x4b,
@@ -108,3 +114,86 @@ export fn _range_program(offset: u32, data: [*]const u8, len: usize) linksection
108114

109115
boot2.flash_enable_xip();
110116
}
117+
118+
/// Force the chip select using IO overrides, in case RAM-resident IRQs
119+
/// are still running, and the FIFO bottoms out
120+
pub inline fn force_cs(high: bool) void {
121+
@call(.never_inline, _force_cs, .{high});
122+
}
123+
124+
fn _force_cs(high: bool) linksection(".time_critical") void {
125+
const value = v: {
126+
var value: u32 = 0x2;
127+
if (high) {
128+
value = 0x3;
129+
}
130+
break :v value << 8;
131+
};
132+
133+
const IO_QSPI_GPIO_QSPI_SS_CTRL: *volatile u32 = @ptrFromInt(@intFromPtr(IO_QSPI) + 0x0C);
134+
IO_QSPI_GPIO_QSPI_SS_CTRL.* = (IO_QSPI_GPIO_QSPI_SS_CTRL.* ^ value) & 0x300;
135+
}
136+
137+
/// Execute a command on the flash chip
138+
///
139+
/// Configures flash for serial mode operation, sends a command, receives response
140+
/// and then configures flash back to XIP mode
141+
pub inline fn cmd(tx_buf: []const u8, rx_buf: []u8) void {
142+
@call(.never_inline, _cmd, .{ tx_buf, rx_buf });
143+
}
144+
145+
fn _cmd(tx_buf: []const u8, rx_buf: []u8) linksection(".time_critical") void {
146+
boot2.flash_init();
147+
asm volatile ("" ::: "memory"); // memory barrier
148+
rom.connect_internal_flash()();
149+
rom.flash_exit_xip()();
150+
force_cs(false);
151+
152+
// can't use peripherals, because its functions are not in ram
153+
const XIP_SSI_SR: *volatile u32 = @ptrFromInt(@intFromPtr(XIP_SSI) + 0x28);
154+
const XIP_SSI_DR0: *volatile u8 = @ptrFromInt(@intFromPtr(XIP_SSI) + 0x60);
155+
156+
const len = tx_buf.len;
157+
var tx_remaining = len;
158+
var rx_remaining = len;
159+
const fifo_depth = 16 - 2;
160+
while (tx_remaining > 0 or rx_remaining > 0) {
161+
const can_put = XIP_SSI_SR.* & 0x2 != 0; // TFNF
162+
const can_get = XIP_SSI_SR.* & 0x8 != 0; // RFNE
163+
164+
if (can_put and tx_remaining > 0 and rx_remaining < tx_remaining + fifo_depth) {
165+
XIP_SSI_DR0.* = tx_buf[len - tx_remaining];
166+
tx_remaining -= 1;
167+
}
168+
if (can_get and rx_remaining > 0) {
169+
rx_buf[len - rx_remaining] = XIP_SSI_DR0.*;
170+
rx_remaining -= 1;
171+
}
172+
}
173+
174+
force_cs(true);
175+
rom.flash_flush_cache()();
176+
boot2.flash_enable_xip();
177+
}
178+
179+
const id_dummy_len = 4;
180+
const id_data_len = 8;
181+
const id_total_len = 1 + id_dummy_len + id_data_len;
182+
var id_buf: ?[id_data_len]u8 = null;
183+
184+
/// Read the flash chip's ID which is unique to each RP2040
185+
pub fn id() [id_data_len]u8 {
186+
if (id_buf) |b| {
187+
return b;
188+
}
189+
190+
var tx_buf: [id_total_len]u8 = undefined;
191+
var rx_buf: [id_total_len]u8 = undefined;
192+
tx_buf[0] = @intFromEnum(Command.ruid_cmd);
193+
cmd(&tx_buf, &rx_buf);
194+
195+
id_buf = undefined;
196+
@memcpy(&id_buf.?, rx_buf[1 + id_dummy_len ..]);
197+
198+
return id_buf.?;
199+
}

bsp/stmicro/stm32/build.zig

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub const chips = struct {
6161
},
6262
},
6363
.hal = .{
64-
.source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F407.zig" },
64+
.root_source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F407.zig" },
6565
},
6666
};
6767

examples/raspberrypi/rp2040/build.zig

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const available_examples = [_]Example{
77
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_adc", .file = "src/adc.zig" },
88
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_blinky", .file = "src/blinky.zig" },
99
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_flash-program", .file = "src/flash_program.zig" },
10+
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_flash-id", .file = "src/flash_id.zig" },
1011
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_gpio-clk", .file = "src/gpio_clk.zig" },
1112
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_i2c-bus-scan", .file = "src/i2c_bus_scan.zig" },
1213
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_pwm", .file = "src/pwm.zig" },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const std = @import("std");
2+
const microzig = @import("microzig");
3+
4+
const rp2040 = microzig.hal;
5+
const time = rp2040.time;
6+
const gpio = rp2040.gpio;
7+
const flash = rp2040.flash;
8+
9+
const uart = rp2040.uart.num(0);
10+
const baud_rate = 115200;
11+
const uart_tx_pin = gpio.num(0);
12+
const uart_rx_pin = gpio.num(1);
13+
14+
pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
15+
std.log.err("panic: {s}", .{message});
16+
@breakpoint();
17+
while (true) {}
18+
}
19+
20+
pub const std_options = struct {
21+
pub const log_level = .debug;
22+
pub const logFn = rp2040.uart.log;
23+
};
24+
25+
pub fn main() !void {
26+
uart.apply(.{
27+
.baud_rate = baud_rate,
28+
.tx_pin = uart_tx_pin,
29+
.rx_pin = uart_rx_pin,
30+
.clock_config = rp2040.clock_config,
31+
});
32+
33+
rp2040.uart.init_logger(uart);
34+
35+
while (true) {
36+
const serial_number = flash.id();
37+
const hex_serial_number = std.fmt.fmtSliceHexLower(&serial_number);
38+
std.log.info("serial number: {s}", .{hex_serial_number});
39+
time.sleep_ms(1000);
40+
}
41+
}

0 commit comments

Comments
 (0)