rp2040: add flash id function (#182)

wch-ch32v003
Matevz Mihalic 5 months ago committed by Matt Knight
parent 1ed0296bb7
commit 540a52585f

@ -1,6 +1,12 @@
//! See [rp2040 docs](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf), page 136. //! See [rp2040 docs](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf), page 136.
const rom = @import("rom.zig"); const rom = @import("rom.zig");
const microzig = @import("microzig");
const peripherals = microzig.chip.peripherals;
const IO_QSPI = peripherals.IO_QSPI;
const XIP_SSI = peripherals.XIP_SSI;
pub const Command = enum(u8) { pub const Command = enum(u8) {
block_erase = 0xd8, block_erase = 0xd8,
ruid_cmd = 0x4b, ruid_cmd = 0x4b,
@ -108,3 +114,86 @@ export fn _range_program(offset: u32, data: [*]const u8, len: usize) linksection
boot2.flash_enable_xip(); boot2.flash_enable_xip();
} }
/// Force the chip select using IO overrides, in case RAM-resident IRQs
/// are still running, and the FIFO bottoms out
pub inline fn force_cs(high: bool) void {
@call(.never_inline, _force_cs, .{high});
}
fn _force_cs(high: bool) linksection(".time_critical") void {
const value = v: {
var value: u32 = 0x2;
if (high) {
value = 0x3;
}
break :v value << 8;
};
const IO_QSPI_GPIO_QSPI_SS_CTRL: *volatile u32 = @ptrFromInt(@intFromPtr(IO_QSPI) + 0x0C);
IO_QSPI_GPIO_QSPI_SS_CTRL.* = (IO_QSPI_GPIO_QSPI_SS_CTRL.* ^ value) & 0x300;
}
/// Execute a command on the flash chip
///
/// Configures flash for serial mode operation, sends a command, receives response
/// and then configures flash back to XIP mode
pub inline fn cmd(tx_buf: []const u8, rx_buf: []u8) void {
@call(.never_inline, _cmd, .{ tx_buf, rx_buf });
}
fn _cmd(tx_buf: []const u8, rx_buf: []u8) linksection(".time_critical") void {
boot2.flash_init();
asm volatile ("" ::: "memory"); // memory barrier
rom.connect_internal_flash()();
rom.flash_exit_xip()();
force_cs(false);
// can't use peripherals, because its functions are not in ram
const XIP_SSI_SR: *volatile u32 = @ptrFromInt(@intFromPtr(XIP_SSI) + 0x28);
const XIP_SSI_DR0: *volatile u8 = @ptrFromInt(@intFromPtr(XIP_SSI) + 0x60);
const len = tx_buf.len;
var tx_remaining = len;
var rx_remaining = len;
const fifo_depth = 16 - 2;
while (tx_remaining > 0 or rx_remaining > 0) {
const can_put = XIP_SSI_SR.* & 0x2 != 0; // TFNF
const can_get = XIP_SSI_SR.* & 0x8 != 0; // RFNE
if (can_put and tx_remaining > 0 and rx_remaining < tx_remaining + fifo_depth) {
XIP_SSI_DR0.* = tx_buf[len - tx_remaining];
tx_remaining -= 1;
}
if (can_get and rx_remaining > 0) {
rx_buf[len - rx_remaining] = XIP_SSI_DR0.*;
rx_remaining -= 1;
}
}
force_cs(true);
rom.flash_flush_cache()();
boot2.flash_enable_xip();
}
const id_dummy_len = 4;
const id_data_len = 8;
const id_total_len = 1 + id_dummy_len + id_data_len;
var id_buf: ?[id_data_len]u8 = null;
/// Read the flash chip's ID which is unique to each RP2040
pub fn id() [id_data_len]u8 {
if (id_buf) |b| {
return b;
}
var tx_buf: [id_total_len]u8 = undefined;
var rx_buf: [id_total_len]u8 = undefined;
tx_buf[0] = @intFromEnum(Command.ruid_cmd);
cmd(&tx_buf, &rx_buf);
id_buf = undefined;
@memcpy(&id_buf.?, rx_buf[1 + id_dummy_len ..]);
return id_buf.?;
}

@ -61,7 +61,7 @@ pub const chips = struct {
}, },
}, },
.hal = .{ .hal = .{
.source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F407.zig" }, .root_source_file = .{ .cwd_relative = build_root ++ "/src/hals/STM32F407.zig" },
}, },
}; };

@ -7,6 +7,7 @@ const available_examples = [_]Example{
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_adc", .file = "src/adc.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_adc", .file = "src/adc.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_blinky", .file = "src/blinky.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_blinky", .file = "src/blinky.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_flash-program", .file = "src/flash_program.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_flash-program", .file = "src/flash_program.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_flash-id", .file = "src/flash_id.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_gpio-clk", .file = "src/gpio_clk.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_gpio-clk", .file = "src/gpio_clk.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_i2c-bus-scan", .file = "src/i2c_bus_scan.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_i2c-bus-scan", .file = "src/i2c_bus_scan.zig" },
.{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_pwm", .file = "src/pwm.zig" }, .{ .target = rp2040.boards.raspberrypi.pico, .name = "pico_pwm", .file = "src/pwm.zig" },

@ -0,0 +1,41 @@
const std = @import("std");
const microzig = @import("microzig");
const rp2040 = microzig.hal;
const time = rp2040.time;
const gpio = rp2040.gpio;
const flash = rp2040.flash;
const uart = rp2040.uart.num(0);
const baud_rate = 115200;
const uart_tx_pin = gpio.num(0);
const uart_rx_pin = gpio.num(1);
pub fn panic(message: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
std.log.err("panic: {s}", .{message});
@breakpoint();
while (true) {}
}
pub const std_options = struct {
pub const log_level = .debug;
pub const logFn = rp2040.uart.log;
};
pub fn main() !void {
uart.apply(.{
.baud_rate = baud_rate,
.tx_pin = uart_tx_pin,
.rx_pin = uart_rx_pin,
.clock_config = rp2040.clock_config,
});
rp2040.uart.init_logger(uart);
while (true) {
const serial_number = flash.id();
const hex_serial_number = std.fmt.fmtSliceHexLower(&serial_number);
std.log.info("serial number: {s}", .{hex_serial_number});
time.sleep_ms(1000);
}
}
Loading…
Cancel
Save