diff --git a/build.zig.zon b/build.zig.zon
index 30dde66c6..f75864ab9 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -46,6 +46,10 @@
.url = "git+https://codeberg.org/mattnite/boxzer.git#4021540de4b07c11102dd4d46383ce0066f838bb",
.hash = "boxzer-0.1.0--ed-MPrnAAAQAwXnfMJuSkgAsw4FseHEHKcn7OMKXGZS",
},
+ .serial = .{
+ .url = "git+https://github.com/ZigEmbeddedGroup/serial.git?ref=master#fbd7389ff8bbc9fa362aa74081588755b5d028a0",
+ .hash = "serial-0.0.1-PoeRzF60AAAN8Iu0yXTIX-t3DVzsnmN7vWHKM2HA2Zbq",
+ },
},
.paths = .{
"README.md",
diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig
index 2a8e2e425..6c07f71b9 100644
--- a/core/src/cpus/cortex_m.zig
+++ b/core/src/cpus/cortex_m.zig
@@ -693,7 +693,7 @@ pub inline fn enable_fpu() void {
/// The RAM vector table used. You can swap interrupt handlers at runtime here.
/// Available when using a RAM vector table or a RAM image.
-pub var ram_vector_table: VectorTable align(256) = if (using_ram_vector_table or is_ram_image)
+pub var ram_vector_table: VectorTable align(128) = if (using_ram_vector_table or is_ram_image)
startup_logic.generate_vector_table()
else
@compileError("`ram_vector_table` is not available. Consider adding .cpu = .{ .ram_vector_table = true }" ++
@@ -834,7 +834,7 @@ pub const startup_logic = struct {
fn default_exception_handler(comptime name: []const u8) microzig.interrupt.Handler {
return switch (builtin.mode) {
.Debug => .{ .c = DebugExceptionHandler(name).handle },
- else => .{ .c = ReleaseExceptionHandler.handle },
+ else => .{ .c = DebugExceptionHandler(name).handle },
};
}
diff --git a/port/raspberrypi/rp2xxx/src/hal/dma.zig b/port/raspberrypi/rp2xxx/src/hal/dma.zig
index e50f7fab8..49ef20d09 100644
--- a/port/raspberrypi/rp2xxx/src/hal/dma.zig
+++ b/port/raspberrypi/rp2xxx/src/hal/dma.zig
@@ -52,6 +52,69 @@ pub const DMA_WriteTarget = struct {
addr: u32,
};
+pub const RingConfig = union(enum) {
+ disabled,
+ read: RingSize,
+ write: RingSize,
+};
+
+pub const TransferMode = enum(u4) {
+ /// When MODE is 0x0, the transfer count decrements with each transfer,
+ /// until 0, and then the channel triggers the next channel indicated by
+ /// CTRL_CHAIN_TO.
+ default = 0x0,
+
+ /// When MODE is 0x1, the transfer count decrements with each transfer until 0,
+ /// and then the channel re-triggers itself, in addition to the trigger indicated by
+ /// CTRL_CHAIN_TO. This is useful for e.g. an endless ring-buffer DMA with
+ /// periodic interrupts.
+ trigger_self = 0x1,
+
+ /// When MODE is 0xf, the transfer count does not decrement. The DMA channel
+ /// performs an endless sequence of transfers, never triggering other channels or
+ /// raising interrupts, until an ABORT is raised.
+ endless = 0xF,
+};
+
+pub const RingSize = enum(u4) {
+ // disabled = 0,
+ @"2" = 1,
+ @"4" = 2,
+ @"8" = 3,
+ @"16" = 4,
+ @"32" = 5,
+ @"64" = 6,
+ @"128" = 7,
+ @"256" = 8,
+ @"512" = 9,
+ @"1024" = 10,
+ @"2048" = 11,
+ @"4096" = 12,
+ @"8192" = 13,
+ @"16384" = 14,
+ @"32768" = 15,
+};
+
+pub const IncrementMode = enum {
+ none,
+ increment,
+ decrement,
+ increment_x2,
+
+ inline fn get_read_value(mode: IncrementMode) u1 {
+ return switch (mode) {
+ .none, .increment_x2 => 0,
+ .increment, .decrement => 1,
+ };
+ }
+ inline fn get_read_rev_value(mode: IncrementMode) u1 {
+ return switch (mode) {
+ .none, .increment => 0,
+ .decrement, .increment_x2 => 1,
+ };
+ }
+};
+
pub const ChannelError = error{AlreadyClaimed};
pub const Channel = enum(u4) {
@@ -109,18 +172,22 @@ pub const Channel = enum(u4) {
trigger: bool = true,
data_size: DataSize,
enable: bool,
- read_increment: bool,
- write_increment: bool,
+ read_increment: IncrementMode,
+ write_increment: IncrementMode,
dreq: Dreq,
chain_to: ?Channel = null,
high_priority: bool = false,
- // TODO:
- // chain to
- // ring
- // byte swapping
+ ring: RingConfig = .disabled,
+ swap_bytes: bool = false,
+
+ sniffer_enabled: bool = false,
+
+ irq_quiet: bool = false,
+
+ mode: TransferMode = .default,
};
pub fn setup_transfer_raw(
@@ -130,31 +197,54 @@ pub const Channel = enum(u4) {
count: u32,
config: TransferConfig,
) void {
+ std.debug.assert(config.chain_to != chan); // A channel can never link to itself, use "ENDLESS" count instead.
+ std.debug.assert(count <= std.math.maxInt(u28)); // Must fit into 28 bits
+
+ const CountField = packed struct(u32) {
+ count: u28,
+ mode: TransferMode,
+ };
+ const count_field: CountField = .{
+ .count = @intCast(count),
+ .mode = config.mode,
+ };
+ const count_val: u32 = @bitCast(count_field);
+
const regs = chan.get_regs();
regs.read_addr = read_addr;
regs.write_addr = write_addr;
- regs.trans_count = count;
+ regs.trans_count = count_val;
const chain_to = config.chain_to orelse chan;
+
+ const TrigType = @TypeOf(microzig.chip.peripherals.DMA.CH0_CTRL_TRIG).underlying_type;
+
+ const new_cfg: TrigType = .{
+ .EN = @intFromBool(config.enable),
+ .DATA_SIZE = config.data_size,
+ .INCR_READ = config.read_increment.get_read_value(),
+ .INCR_READ_REV = config.read_increment.get_read_rev_value(),
+ .INCR_WRITE = config.write_increment.get_read_value(),
+ .INCR_WRITE_REV = config.write_increment.get_read_rev_value(),
+ .TREQ_SEL = config.dreq,
+ .CHAIN_TO = @intFromEnum(chain_to),
+ .HIGH_PRIORITY = @intFromBool(config.high_priority),
+ .RING_SEL = switch (config.ring) {
+ .disabled, .read => 0,
+ .write => 1,
+ },
+ .RING_SIZE = switch (config.ring) {
+ .disabled => .RING_NONE,
+ .read, .write => |size| @enumFromInt(@intFromEnum(size)),
+ },
+ .BSWAP = @intFromBool(config.swap_bytes),
+ .SNIFF_EN = @intFromBool(config.sniffer_enabled),
+ .IRQ_QUIET = @intFromBool(config.irq_quiet),
+ };
+
if (config.trigger) {
- regs.ctrl_trig.modify(.{
- .EN = @intFromBool(config.enable),
- .DATA_SIZE = config.data_size,
- .INCR_READ = @intFromBool(config.read_increment),
- .INCR_WRITE = @intFromBool(config.write_increment),
- .TREQ_SEL = config.dreq,
- .CHAIN_TO = @intFromEnum(chain_to),
- .HIGH_PRIORITY = @intFromBool(config.high_priority),
- });
+ regs.ctrl_trig.write(new_cfg);
} else {
- regs.al1_ctrl.modify(.{
- .EN = @intFromBool(config.enable),
- .DATA_SIZE = config.data_size,
- .INCR_READ = @intFromBool(config.read_increment),
- .INCR_WRITE = @intFromBool(config.write_increment),
- .TREQ_SEL = config.dreq,
- .CHAIN_TO = @intFromEnum(chain_to),
- .HIGH_PRIORITY = @intFromBool(config.high_priority),
- });
+ regs.al1_ctrl.write(new_cfg);
}
}
diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig
index 1aa48b5da..51faa75c6 100644
--- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig
+++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig
@@ -31,6 +31,8 @@ pub const Program = struct {
wrap: ?u5,
pub fn get_mask(program: Program) u32 {
+ if (program.instructions.len == 32)
+ return 0xFFFF_FFFF;
return (@as(u32, 1) << @as(u5, @intCast(program.instructions.len))) - 1;
}
};
diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig
index 5df0a3bb2..0f64ab066 100644
--- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig
+++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler/encoder.zig
@@ -501,12 +501,23 @@ pub fn Encoder(comptime chip: Chip, comptime options: Options) type {
var instr_index: ?u5 = program.origin orelse 0;
for (self.tokens[self.index..]) |token| {
switch (token.data) {
- .label => |label| try program.labels.append(.{
- .name = label.name,
- .public = label.public,
- .index = instr_index.?,
- }),
+ .label => |label| {
+ if (instr_index == null) {
+ diags.* = Diagnostics.init(token.index, "label not addressable (out of instructions)", .{});
+ return error.Overflow;
+ }
+ try program.labels.append(.{
+ .name = label.name,
+ .public = label.public,
+ .index = instr_index.?,
+ });
+ },
.instruction, .word => {
+ if (instr_index == null) {
+ diags.* = Diagnostics.init(token.index, "out of instructions", .{});
+ return error.Overflow;
+ }
+
const result, const ov = @addWithOverflow(instr_index.?, 1);
instr_index = if (ov != 0) null else result;
},
diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig
index 8a2a58d9a..f3162ef97 100644
--- a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig
+++ b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig
@@ -156,12 +156,22 @@ pub fn PioImpl(EnumType: type, chip: Chip) type {
}
pub fn find_offset_for_program(self: EnumType, program: Program) !u5 {
- return if (program.origin) |origin|
- if (self.can_add_program_at_offset(program, origin))
- origin
- else
- error.NoSpace
- else for (0..(32 - program.instructions.len)) |i| {
+ std.log.info("", .{ program.origin, program.instructions.len });
+ defer std.log.info("", .{});
+
+ if (program.origin) |origin| {
+ if (!self.can_add_program_at_offset(program, origin))
+ return error.NoSpace;
+ return origin;
+ }
+
+ if (program.instructions.len == 32) {
+ if (!self.can_add_program_at_offset(program, 0))
+ return error.NoSpace;
+ return 0;
+ }
+
+ return for (0..(32 - program.instructions.len)) |i| {
const offset = @as(u5, @intCast(i));
if (self.can_add_program_at_offset(program, offset))
break offset;
@@ -194,6 +204,7 @@ pub fn PioImpl(EnumType: type, chip: Chip) type {
//defer lock.unlock();
const offset = try self.find_offset_for_program(program);
+ std.log.info("add_program offset = {}", .{offset});
try self.add_program_at_offset_unlocked(program, offset);
return offset;
}
@@ -526,9 +537,13 @@ pub fn PioImpl(EnumType: type, chip: Chip) type {
const config_count = if (options.pin_mappings.side_set) |side_set| side_set.count() else 0;
assert(expected_side_set_pins == config_count);
+ std.log.info("", .{});
+
// TODO: check program settings vs pin mapping
const offset = try self.add_program(program);
+ std.log.info("", .{});
+
try self.sm_init(sm, offset, .{
.clkdiv = options.clkdiv,
.shift = options.shift,