-
Notifications
You must be signed in to change notification settings - Fork 152
RP2xxx PIO and Reset fixes #633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
5369970
987c83d
e1282b7
84d7994
91027b7
a78a461
d08fc1f
bb2826d
7b69765
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ const std = @import("std"); | |
| const assert = std.debug.assert; | ||
|
|
||
| const microzig = @import("microzig"); | ||
|
|
||
| const Chip = @import("../chip.zig").Chip; | ||
|
|
||
| pub const PIO = microzig.chip.types.peripherals.PIO0; | ||
|
|
@@ -100,7 +101,7 @@ pub const ClkDivOptions = struct { | |
| }; | ||
|
|
||
| pub const ExecOptions = struct { | ||
| jmp_pin: u5 = 0, | ||
| jmp_pin: ?gpio.Pin = null, | ||
| wrap: u5 = 31, | ||
| wrap_target: u5 = 0, | ||
| side_pindir: bool = false, | ||
|
|
@@ -109,16 +110,25 @@ pub const ExecOptions = struct { | |
|
|
||
| pub fn PinMapping(comptime Count: type) type { | ||
| return struct { | ||
| base: u5 = 0, | ||
| count: Count = 0, | ||
| /// Creates a mapping with a single pin, length 1 | ||
| pub fn single(pin: gpio.Pin) PinMapping(Count) { | ||
| return .{ .low = pin, .high = pin }; | ||
| } | ||
|
|
||
| low: gpio.Pin, | ||
| high: gpio.Pin, | ||
|
|
||
| fn count(range: @This()) Count { | ||
| return @intCast(@intFromEnum(range.high) - @intFromEnum(range.low) + 1); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| pub const PinMappingOptions = struct { | ||
| out: PinMapping(u6) = .{}, | ||
| set: PinMapping(u3) = .{ .count = 5 }, | ||
| side_set: PinMapping(u3) = .{}, | ||
| in_base: u5 = 0, | ||
| out: ?PinMapping(u6) = null, | ||
| set: ?PinMapping(u3) = null, | ||
| side_set: ?PinMapping(u3) = null, | ||
| in_base: ?gpio.Pin = null, | ||
| }; | ||
|
|
||
| pub fn PioImpl(EnumType: type, chip: Chip) type { | ||
|
|
@@ -163,8 +173,16 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| return error.NoSpace; | ||
|
|
||
| const instruction_memory = self.get_instruction_memory(); | ||
| for (program.instructions, offset..) |insn, i| | ||
| instruction_memory[i] = insn; | ||
| for (program.instructions, program.relocations, offset..) |insn, reloc, i| | ||
| instruction_memory[i] = switch (reloc) { | ||
| .none => insn, | ||
| .jmpslot => blk: { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind just adding a comment here reminding us how you're doing the reloc |
||
| const Jmp = packed struct(u16) { address: u5, reset: u11 }; | ||
| var jmp: Jmp = @bitCast(insn); | ||
| jmp.address += offset; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In release this won't catch if offset + address overflows. Do we have a guarantee that the offset will be in the correct range? Probably worse a comment asserting that. |
||
| break :blk @as(u16, @bitCast(jmp)); | ||
| }, | ||
| }; | ||
|
|
||
| const program_mask = program.get_mask(); | ||
| UsedInstructionSpace(chip).val[@intFromEnum(self)] |= program_mask << offset; | ||
|
|
@@ -225,15 +243,24 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| }); | ||
| } | ||
|
|
||
| pub fn sm_set_exec_options(self: EnumType, sm: StateMachine, options: ExecOptions) void { | ||
| fn pin_to_index(self: EnumType, pin: gpio.Pin) error{InvalidPin}!u5 { | ||
| const index = @intFromEnum(pin); | ||
| const base = (0x10 & self.get_regs().GPIOBASE.raw); | ||
| if (index < base or index >= base + 32) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this OK for rp2350? the 32 is the number of pins that be setup in pio, not how many pins the chip has, correct? |
||
| return error.InvalidPin; | ||
| } | ||
| return @intCast(index - base); | ||
| } | ||
|
|
||
| pub fn sm_set_exec_options(self: EnumType, sm: StateMachine, options: ExecOptions) !void { | ||
| const sm_regs = self.get_sm_regs(sm); | ||
| sm_regs.execctrl.modify(.{ | ||
| // NOTE: EXEC_STALLED is RO | ||
| .WRAP_BOTTOM = options.wrap_target, | ||
| .WRAP_TOP = options.wrap, | ||
| .SIDE_PINDIR = @intFromBool(options.side_pindir), | ||
| .SIDE_EN = @intFromBool(options.side_set_optional), | ||
| .JMP_PIN = options.jmp_pin, | ||
| .JMP_PIN = if (options.jmp_pin) |jmp_pin| try pin_to_index(self, jmp_pin) else 0, | ||
|
|
||
| // TODO: plug in rest of the options | ||
| // STATUS_N | ||
|
|
@@ -244,55 +271,37 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| // EXEC_STALLED | ||
| }); | ||
| } | ||
| pub fn sm_set_pin_mappings(self: EnumType, sm: StateMachine, options: PinMappingOptions) void { | ||
|
|
||
| pub fn sm_set_pin_mappings(self: EnumType, sm: StateMachine, options: PinMappingOptions) !void { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||
| const sm_regs = self.get_sm_regs(sm); | ||
| sm_regs.pinctrl.modify(.{ | ||
| .OUT_BASE = options.out.base, | ||
| .OUT_COUNT = options.out.count, | ||
| .OUT_BASE = if (options.out) |out| try pin_to_index(self, out.low) else 0, | ||
| .OUT_COUNT = if (options.out) |out| out.count() else 0, | ||
|
|
||
| .SET_BASE = options.set.base, | ||
| .SET_COUNT = options.set.count, | ||
| .SET_BASE = if (options.set) |set| try pin_to_index(self, set.low) else 0, | ||
| .SET_COUNT = if (options.set) |set| set.count() else 0, | ||
|
|
||
| .SIDESET_BASE = options.side_set.base, | ||
| .SIDESET_COUNT = options.side_set.count, | ||
| .SIDESET_BASE = if (options.side_set) |side_set| try pin_to_index(self, side_set.low) else 0, | ||
| .SIDESET_COUNT = if (options.side_set) |side_set| side_set.count() else 0, | ||
|
|
||
| .IN_BASE = options.in_base, | ||
| .IN_BASE = if (options.in_base) |in_base| try pin_to_index(self, in_base) else 0, | ||
| }); | ||
| } | ||
|
|
||
| pub fn sm_set_pindir(self: EnumType, sm: StateMachine, base: u5, count: u5, dir: gpio.Direction) void { | ||
| pub fn sm_set_pindir(self: EnumType, sm: StateMachine, base: gpio.Pin, count: u5, dir: gpio.Direction) !void { | ||
| const sm_regs = self.get_sm_regs(sm); | ||
| const reg_pinctrl__copy = sm_regs.pinctrl; | ||
| const reg_execctrl__copy = sm_regs.execctrl; | ||
|
|
||
| for (base..base + count) |pin__number| { | ||
| for (0..count) |counter| { | ||
| const pin_config: PinMappingOptions = .{ | ||
| .out = .{ | ||
| .base = 0, | ||
| .count = 0, | ||
| }, | ||
| .set = .{ | ||
| .base = @intCast(pin__number), | ||
| .count = 1, | ||
| }, | ||
| .side_set = .{ | ||
| .base = 0, | ||
| .count = 0, | ||
| }, | ||
| .in_base = 0, | ||
| .out = null, | ||
| .set = .single(@enumFromInt(@intFromEnum(base) + counter)), | ||
| .side_set = null, | ||
| .in_base = null, | ||
| }; | ||
| sm_regs.pinctrl.modify(.{ | ||
| .OUT_BASE = pin_config.out.base, | ||
| .OUT_COUNT = pin_config.out.count, | ||
|
|
||
| .SET_BASE = pin_config.set.base, | ||
| .SET_COUNT = pin_config.set.count, | ||
| try sm_set_pin_mappings(self, sm, pin_config); | ||
|
|
||
| .SIDESET_BASE = pin_config.side_set.base, | ||
| .SIDESET_COUNT = pin_config.side_set.count, | ||
|
|
||
| .IN_BASE = pin_config.in_base, | ||
| }); | ||
| self.sm_exec(sm, .{ | ||
| .payload = .{ | ||
| .set = .{ | ||
|
|
@@ -308,39 +317,19 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| sm_regs.execctrl = reg_execctrl__copy; | ||
| } | ||
|
|
||
| pub fn sm_set_pin(self: EnumType, sm: StateMachine, base: u5, count: u5, value: u1) void { | ||
| pub fn sm_set_pin(self: EnumType, sm: StateMachine, base: gpio.Pin, count: u5, value: u1) !void { | ||
| const sm_regs = self.get_sm_regs(sm); | ||
| const reg_pinctrl__copy = sm_regs.pinctrl; | ||
| const reg_execctrl__copy = sm_regs.execctrl; | ||
|
|
||
| for (base..base + count) |pin__number| { | ||
| for (0..count) |counter| { | ||
| const pin_config: PinMappingOptions = .{ | ||
| .out = .{ | ||
| .base = 0, | ||
| .count = 0, | ||
| }, | ||
| .set = .{ | ||
| .base = @intCast(pin__number), | ||
| .count = 1, | ||
| }, | ||
| .side_set = .{ | ||
| .base = 0, | ||
| .count = 0, | ||
| }, | ||
| .in_base = 0, | ||
| .out = null, | ||
| .set = .single(@enumFromInt(@intFromEnum(base) + counter)), | ||
| .side_set = null, | ||
| .in_base = null, | ||
| }; | ||
| sm_regs.pinctrl.modify(.{ | ||
| .OUT_BASE = pin_config.out.base, | ||
| .OUT_COUNT = pin_config.out.count, | ||
|
|
||
| .SET_BASE = pin_config.set.base, | ||
| .SET_COUNT = pin_config.set.count, | ||
|
|
||
| .SIDESET_BASE = pin_config.side_set.base, | ||
| .SIDESET_COUNT = pin_config.side_set.count, | ||
|
|
||
| .IN_BASE = pin_config.in_base, | ||
| }); | ||
| try sm_set_pin_mappings(self, sm, pin_config); | ||
| self.sm_exec(sm, .{ | ||
| .payload = .{ | ||
| .set = .{ | ||
|
|
@@ -491,13 +480,13 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| sm: StateMachine, | ||
| initial_pc: u5, | ||
| options: StateMachineInitOptions(chip), | ||
| ) void { | ||
| ) !void { | ||
| // Halt the machine, set some sensible defaults | ||
| self.sm_set_enabled(sm, false); | ||
| self.sm_set_clkdiv(sm, options.clkdiv); | ||
| self.sm_set_exec_options(sm, options.exec); | ||
| try self.sm_set_exec_options(sm, options.exec); | ||
| self.sm_set_shift_options(sm, options.shift); | ||
| self.sm_set_pin_mappings(sm, options.pin_mappings); | ||
| try self.sm_set_pin_mappings(sm, options.pin_mappings); | ||
|
|
||
| self.sm_clear_fifos(sm); | ||
| self.sm_clear_debug(sm); | ||
|
|
@@ -537,23 +526,24 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { | |
| else | ||
| 0; | ||
|
|
||
| assert(expected_side_set_pins == options.pin_mappings.side_set.count); | ||
| const config_count = if (options.pin_mappings.side_set) |side_set| side_set.count() else 0; | ||
| assert(expected_side_set_pins == config_count); | ||
|
|
||
| // TODO: check program settings vs pin mapping | ||
| const offset = try self.add_program(program); | ||
|
|
||
| self.sm_init(sm, offset, .{ | ||
| try self.sm_init(sm, offset, .{ | ||
| .clkdiv = options.clkdiv, | ||
| .shift = options.shift, | ||
| .pin_mappings = options.pin_mappings, | ||
| .exec = .{ | ||
| .wrap = if (program.wrap) |wrap| | ||
| wrap | ||
| offset + wrap | ||
| else | ||
| offset + @as(u5, @intCast(program.instructions.len)), | ||
|
|
||
| .wrap_target = if (program.wrap_target) |wrap_target| | ||
| wrap_target | ||
| offset + wrap_target | ||
| else | ||
| offset, | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this just to save on code + data size on release builds?