-
Notifications
You must be signed in to change notification settings - Fork 148
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
Open
ikskuh
wants to merge
9
commits into
main
Choose a base branch
from
xq/pio_fixes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
5369970
Fixes PIO subsystem supporting multiple calls to sm_load_and_start_pr…
987c83d
Adds RP2350.resets.Mask.only to allow usage like rp2350.resets.reset(…
e1282b7
Fixes bug in sm_load_and_start_program: Wrapping was not considered w…
84d7994
Implements a more verbose panic handler for Debug builds.
91027b7
Adds hacky user script to convert arm documentation into code.
a78a461
Makes rp2xxx.pio.PinMapping use gpio.Pin instead of raw indices to im…
d08fc1f
Implements rp2xxx.dma.TransferConfig.chain_to
bb2826d
Starts to implement improved Cortex-M debugging experience.
7b69765
rp2xxx: Refactors UART to use deadlines instead of relative timeouts.…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| const std = @import("std"); | ||
| const builtin = @import("builtin"); | ||
| const microzig = @import("microzig"); | ||
| const mmio = microzig.mmio; | ||
| const app = microzig.app; | ||
| const shared = @import("cortex_m/shared_types.zig"); | ||
|
|
||
| const Core = enum { | ||
| cortex_m0, | ||
|
|
@@ -658,6 +660,17 @@ pub const startup_logic = struct { | |
| } | ||
| } | ||
|
|
||
| // if (@hasField(types.peripherals.SystemControlBlock, "SHCSR")) { | ||
| { | ||
| // Enable distinction between MemFault, BusFault and UsageFault: | ||
| peripherals.scb.SHCSR.modify(.{ | ||
| .MEMFAULTENA = 1, | ||
| .BUSFAULTENA = 1, | ||
| .USGFAULTENA = 1, | ||
| }); | ||
| enable_fault_irq(); | ||
| } | ||
|
|
||
| microzig_main(); | ||
| } | ||
|
|
||
|
|
@@ -666,20 +679,194 @@ pub const startup_logic = struct { | |
| // will be imported by microzig.zig to allow system startup. | ||
| // must be aligned to 256 as VTOR ignores the lower 8 bits of the address. | ||
| pub const _vector_table: VectorTable align(256) = blk: { | ||
| if (cpu_flags.has_hard_fault and !@hasField(VectorTable, HardFault_name)) { | ||
| @compileError("The CPU configures a vector, but none present in the VectorTable type!"); | ||
| } | ||
| if (cpu_flags.has_bus_fault and !@hasField(VectorTable, BusFault_name)) { | ||
| @compileError("The CPU configures a vector, but none present in the VectorTable type!"); | ||
| } | ||
| if (cpu_flags.has_mem_manage_fault and !@hasField(VectorTable, MemManageFault_name)) { | ||
| @compileError("The CPU configures a vector, but none present in the VectorTable type!"); | ||
| } | ||
| if (cpu_flags.has_usage_fault and !@hasField(VectorTable, UsageFault_name)) { | ||
| @compileError("The CPU configures a vector, but none present in the VectorTable type!"); | ||
| } | ||
|
|
||
| var tmp: VectorTable = .{ | ||
| .initial_stack_pointer = microzig.config.end_of_stack, | ||
| .Reset = .{ .c = microzig.cpu.startup_logic._start }, | ||
| }; | ||
|
|
||
| for (@typeInfo(@TypeOf(microzig.options.interrupts)).@"struct".fields) |field| { | ||
| const maybe_handler = @field(microzig.options.interrupts, field.name); | ||
| if (maybe_handler) |handler| { | ||
| @field(tmp, field.name) = handler; | ||
| } | ||
| @field(tmp, field.name) = if (maybe_handler) |handler| | ||
| handler | ||
| else | ||
| default_exception_handler(field.name); | ||
| } | ||
|
|
||
| break :blk tmp; | ||
| }; | ||
|
|
||
| fn default_exception_handler(comptime name: []const u8) microzig.interrupt.Handler { | ||
| if (microzig.options.cpu.verbose_unhandled_irq) { | ||
| return .{ .c = debugExceptionHandler(name) }; | ||
| } else { | ||
| return .{ .c = ReleaseExceptionHandler.handle }; | ||
| } | ||
| } | ||
|
|
||
| const IrqHandlerFn = *const fn () callconv(.c) void; | ||
|
|
||
| fn debugExceptionHandler(comptime name: []const u8) IrqHandlerFn { | ||
| if (comptime std.mem.eql(u8, name, HardFault_name)) | ||
| return debug.hard_fault_handler; | ||
| if (comptime std.mem.eql(u8, name, BusFault_name)) | ||
| return debug.bus_fault_handler; | ||
| if (comptime std.mem.eql(u8, name, MemManageFault_name)) | ||
| return debug.mem_manage_fault_handler; | ||
| if (comptime std.mem.eql(u8, name, UsageFault_name)) | ||
| return debug.usage_fault_handler; | ||
|
|
||
| return struct { | ||
| fn handle() callconv(.c) void { | ||
| @panic("Unhandled exception: " ++ name); | ||
| } | ||
| }.handle; | ||
| } | ||
|
|
||
| const ReleaseExceptionHandler = struct { | ||
|
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 just to save on code + data size on release builds? |
||
| fn handle() callconv(.c) void { | ||
| @panic("Unhandled exception"); | ||
| } | ||
| }; | ||
|
|
||
| const HardFault_name = "HardFault"; | ||
| const BusFault_name = "BusFault"; | ||
| const MemManageFault_name = "MemManageFault"; | ||
| const UsageFault_name = "UsageFault"; | ||
| }; | ||
|
|
||
| /// Implements several mechanisms to easy debugging with Cortex-M cpus. | ||
| /// | ||
| /// Read more here: | ||
| /// https://interrupt.memfault.com/blog/cortex-m-hardfault-debug | ||
| pub const debug = struct { | ||
| const logger = std.log.scoped(.cortex_m3_debug); | ||
|
|
||
| /// This frame is pushed mostly by the CPU itself, and we move it into | ||
| /// the parameter register, so we can inspect it. | ||
| pub const ContextStateFrame = extern struct { | ||
| r0: u32, | ||
| r1: u32, | ||
| r2: u32, | ||
| r3: u32, | ||
| r12: u32, | ||
| lr: u32, | ||
| return_address: u32, | ||
| xpsr: u32, | ||
| }; | ||
|
|
||
| /// Wraps `handler` in a small asm block that ensures that it is a regular interrupt handler | ||
| /// function, but also provides us with a ContextStateFrame fetched from the system status: | ||
| pub fn make_fault_handler(comptime handler: *const fn (context: *ContextStateFrame) callconv(.C) void) *const fn () callconv(.C) void { | ||
| return struct { | ||
| fn invoke() callconv(.C) void { | ||
| // See this article on how we use that: | ||
| // https://interrupt.memfault.com/blog/cortex-m-hardfault-debug | ||
| asm volatile ( | ||
| \\ | ||
| // Check 2th bit of LR. | ||
| \\tst lr, #4 | ||
| // Do "if then else" equal | ||
| \\ite eq | ||
| // if equals, we use the MSP | ||
| \\mrseq r0, msp | ||
| // otherwise, we use the PSP | ||
| \\mrsne r0, psp | ||
| // Then we branch to our handler: | ||
| \\b %[handler] | ||
| : | ||
| : [handler] "s" (handler), | ||
| ); | ||
| } | ||
| }.invoke; | ||
| } | ||
|
|
||
| pub fn hard_fault_handler() callconv(.c) void { | ||
| const hfsr = peripherals.scb.HFSR; | ||
|
|
||
| logger.err("Hard Fault:", .{}); | ||
| logger.err(" VECTTBL: {}", .{hfsr.VECTTBL}); | ||
| logger.err(" FORCED: {}", .{hfsr.FORCED}); | ||
| logger.err(" DEBUGEVT: {}", .{hfsr.DEBUGEVT}); | ||
|
|
||
| @panic("Hard fault"); | ||
| } | ||
|
|
||
| pub fn mem_manage_fault_handler() callconv(.c) void { | ||
| @panic("Memory fault"); | ||
| } | ||
|
|
||
| pub const bus_fault_handler = make_fault_handler(handle_bus_fault_wrapped); | ||
|
|
||
| fn handle_bus_fault_wrapped(context: *const ContextStateFrame) callconv(.c) void { | ||
| const bfsr = peripherals.scb.CFSR.read().BFSR; | ||
|
|
||
| logger.err("Bus Fault:", .{}); | ||
| logger.err(" context = r0:0x{X:0>8} r1:0x{X:0>8} r2:0x{X:0>8} r3:0x{X:0>8}", .{ | ||
| context.r0, | ||
| context.r1, | ||
| context.r2, | ||
| context.r3, | ||
| }); | ||
| logger.err(" r12:0x{X:0>8} lr:0x{X:0>8} ra:0x{X:0>8} xpsr:0x{X:0>8}", .{ | ||
| context.r12, | ||
| context.lr, | ||
| context.return_address, | ||
| context.xpsr, | ||
| }); | ||
| logger.err(" instruction bus error = {}", .{bfsr.instruction_bus_error}); | ||
| logger.err(" precice data bus error = {}", .{bfsr.precice_data_bus_error}); | ||
| logger.err(" imprecice data bus error = {}", .{bfsr.imprecice_data_bus_error}); | ||
| logger.err(" unstacking exception error = {}", .{bfsr.unstacking_exception_error}); | ||
| logger.err(" exception stacking error = {}", .{bfsr.exception_stacking_error}); | ||
| logger.err(" busfault address register valid = {}", .{bfsr.busfault_address_register_valid}); | ||
| if (bfsr.busfault_address_register_valid) { | ||
| const address = peripherals.scb.BFAR; | ||
| logger.err(" busfault address register = 0x{X:0>8}", .{address}); | ||
| } | ||
|
|
||
| @panic("Bus fault"); | ||
| } | ||
|
|
||
| pub const usage_fault_handler = make_fault_handler(handle_usage_fault_wrapped); | ||
|
|
||
| fn handle_usage_fault_wrapped(context: *const ContextStateFrame) callconv(.c) void { | ||
| const ufsr = peripherals.scb.CFSR.read().UFSR; | ||
|
|
||
| logger.err("Usage Fault:", .{}); | ||
| logger.err(" context = r0:0x{X:0>8} r1:0x{X:0>8} r2:0x{X:0>8} r3:0x{X:0>8}", .{ | ||
| context.r0, | ||
| context.r1, | ||
| context.r2, | ||
| context.r3, | ||
| }); | ||
| logger.err(" r12:0x{X:0>8} lr:0x{X:0>8} ra:0x{X:0>8} xpsr:0x{X:0>8}", .{ | ||
| context.r12, | ||
| context.lr, | ||
| context.return_address, | ||
| context.xpsr, | ||
| }); | ||
| logger.err(" undefined instruction = {}", .{ufsr.undefined_instruction}); | ||
| logger.err(" invalid state = {}", .{ufsr.invalid_state}); | ||
| logger.err(" invalid pc load = {}", .{ufsr.invalid_pc_load}); | ||
| logger.err(" missing coprocessor usage = {}", .{ufsr.missing_coprocessor_usage}); | ||
| logger.err(" unaligned memory access = {}", .{ufsr.unaligned_memory_access}); | ||
| logger.err(" divide by zero = {}", .{ufsr.divide_by_zero}); | ||
|
|
||
| @panic("usage fault"); | ||
| } | ||
| }; | ||
|
|
||
| fn is_ramimage() bool { | ||
|
|
@@ -731,6 +918,8 @@ const core = blk: { | |
| }; | ||
| }; | ||
|
|
||
| const cpu_flags: shared.CpuFlags = core.cpu_flags; | ||
|
|
||
| pub const utils = switch (cortex_m) { | ||
| .cortex_m7 => @import("cortex_m/m7_utils.zig"), | ||
| else => void{}, | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Please change to
debug_exception_handler, in MicroZig we use snake case for function names.