From 39352aa22c3d2dedefa4dec201d85fab9bfa81d2 Mon Sep 17 00:00:00 2001 From: salalaika Date: Tue, 14 Jul 2026 14:00:25 +0800 Subject: [PATCH 1/5] fix:1:as5600,use `try read2_raw function`.2:mpu6050 read_reg timeout. --- drivers/src/root.zig | 2 +- drivers/src/sensor/AS5600.zig | 8 ++++---- drivers/src/sensor/MPU_6050.zig | 11 +++++++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/src/root.zig b/drivers/src/root.zig index c01086a08..970de223a 100644 --- a/drivers/src/root.zig +++ b/drivers/src/root.zig @@ -233,6 +233,7 @@ test { _ = sensor.TLV493D; _ = sensor.TMP117; _ = sensor.AHT30; + _ = sensor.AS5600; _ = @import("stepper/common.zig"); _ = stepper.A4988; @@ -250,4 +251,3 @@ test { _ = base.BlockMemory; _ = base.ClockDevice; _ = base.I2C_Device; -} diff --git a/drivers/src/sensor/AS5600.zig b/drivers/src/sensor/AS5600.zig index 01ea984d0..524db7487 100644 --- a/drivers/src/sensor/AS5600.zig +++ b/drivers/src/sensor/AS5600.zig @@ -108,7 +108,7 @@ pub const AS5600 = struct { } pub fn read_zero_position(self: *const Self) !u16 { - const zpos = self.read2_raw(register.ZPOS); + const zpos = try self.read2_raw(register.ZPOS); return zpos & 0xFFF; } @@ -120,7 +120,7 @@ pub const AS5600 = struct { } pub fn read_max_position(self: *const Self) !u16 { - const mpos = self.read2_raw(register.MPOS); + const mpos = try self.read2_raw(register.MPOS); return mpos & 0xFFF; } @@ -132,7 +132,7 @@ pub const AS5600 = struct { } pub fn read_max_angle(self: *const Self) !u16 { - const mang = self.read2_raw(register.MANG); + const mang = try self.read2_raw(register.MANG); return mang & 0xFFF; } @@ -144,7 +144,7 @@ pub const AS5600 = struct { } pub fn read_configuration(self: *const Self) !u16 { - const configuration = self.read2_raw(register.CONF); + const configuration = try self.read2_raw(register.CONF); return @bitCast(configuration); } diff --git a/drivers/src/sensor/MPU_6050.zig b/drivers/src/sensor/MPU_6050.zig index 802587bb9..9aa5bd2c8 100644 --- a/drivers/src/sensor/MPU_6050.zig +++ b/drivers/src/sensor/MPU_6050.zig @@ -83,8 +83,15 @@ pub const MPU_6050 = struct { self.accel_range = .@"2G"; self.gyro_range = .@"250d"; - - while ((try self.read_reg(.pwr_mgmt_1, regs.PWR_MGMT_1)).DEVICE_RESET) {} + // wait for device to wake up + var timeout: usize = 1000; + while ((try self.read_reg(.pwr_mgmt_1, regs.PWR_MGMT_1)).DEVICE_RESET) { + timeout -= 1; + if (timeout == 0) { + return Error.Timeout; + } + self.clock.sleep_ms(1); + } try self.modify_reg(.user_ctrl, regs.USER_CTRL, .{ .SIG_COND_RESET = true, From 18c60ef5b9c64499e3427d94c75debb6f8317679 Mon Sep 17 00:00:00 2001 From: salalaika Date: Tue, 14 Jul 2026 14:01:51 +0800 Subject: [PATCH 2/5] fix:1:as5600,use `try read2_raw function`.2:mpu6050 read_reg timeout. --- drivers/src/root.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/src/root.zig b/drivers/src/root.zig index 970de223a..75a375724 100644 --- a/drivers/src/root.zig +++ b/drivers/src/root.zig @@ -251,3 +251,4 @@ test { _ = base.BlockMemory; _ = base.ClockDevice; _ = base.I2C_Device; +} From 302c09cbd2557107b14b4fe8a9263ddcc2a40c85 Mon Sep 17 00:00:00 2001 From: salalaika Date: Tue, 14 Jul 2026 14:48:03 +0800 Subject: [PATCH 3/5] Add two-bit change detection before the existing logic. --- drivers/src/input/rotary_encoder.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/src/input/rotary_encoder.zig b/drivers/src/input/rotary_encoder.zig index 291e00843..249df2f79 100644 --- a/drivers/src/input/rotary_encoder.zig +++ b/drivers/src/input/rotary_encoder.zig @@ -45,6 +45,13 @@ pub fn RotaryEncoder(comptime options: Options) type { defer enc.last_a = a; defer enc.last_b = b; + // Detect invalid transitions: both bits changed simultaneously + const a_changed = a.value() ^ enc.last_a.value(); + const b_changed = b.value() ^ enc.last_b.value(); + if (a_changed != 0 and b_changed != 0) { + return .@"error"; + } + const enable = a.value() ^ b.value() ^ enc.last_a.value() ^ enc.last_b.value(); const direction = a.value() ^ enc.last_b.value(); @@ -136,4 +143,12 @@ test RotaryEncoder { try std.testing.expectEqual(.decrement, try encoder.poll()); try std.testing.expectEqual(.idle, try encoder.poll()); } + + // Test invalid state: both A and B change simultaneously + // Current state is (high, high) from the previous test loop + // Force both bits to change at once + a.state = .low; + b.state = .low; + try std.testing.expectEqual(.@"error", try encoder.poll()); + try std.testing.expectEqual(.idle, try encoder.poll()); } From 117a4f1ef39718e616986d8e8c6e5f9d7d71208d Mon Sep 17 00:00:00 2001 From: by Date: Tue, 14 Jul 2026 22:48:00 +0800 Subject: [PATCH 4/5] fix(core): correct several CPU port and utility bugs - riscv32: fix wfe() using wrong CSR address 0x810 -> 0x300 (mstatus) - msp430: fix memset/memcpy assembly operand order (TI syntax: OP src, dst) - cortex_m: add missing return in set_pending/clear_pending for m0+ - cortex_m/m0plus: fix NVIC is_enabled/is_pending return type void -> bool - utilities: fix CircularBuffer write/read hardcoded to u8 instead of T --- core/src/cpus/cortex_m.zig | 4 ++-- core/src/cpus/cortex_m/m0plus.zig | 4 ++-- core/src/cpus/msp430.zig | 10 +++++----- core/src/cpus/riscv32.zig | 6 ++++-- core/src/utilities.zig | 4 ++-- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 2d1acf289..1dde51305 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -262,8 +262,8 @@ pub const interrupt = struct { switch (cortex_m) { .cortex_m0plus, => { - if (excpt == .SVCALL) ppb.SHCSR.raw |= 0x0000_8000; - @compileError("not supported on this platform"); + if (excpt == .SVCALL) ppb.SHCSR.raw |= 0x0000_8000 orelse + @compileError("not supported on this platform"); }, .cortex_m3, .cortex_m4, .cortex_m7 => { switch (excpt) { diff --git a/core/src/cpus/cortex_m/m0plus.zig b/core/src/cpus/cortex_m/m0plus.zig index 7aedb4113..fd37d2565 100644 --- a/core/src/cpus/cortex_m/m0plus.zig +++ b/core/src/cpus/cortex_m/m0plus.zig @@ -169,7 +169,7 @@ pub const NestedVectorInterruptController = extern struct { /// register saves value 192 to the register. IPR: [32]u8, - pub fn is_enabled(nvic: *volatile NestedVectorInterruptController, num: comptime_int) void { + pub fn is_enabled(nvic: *volatile NestedVectorInterruptController, num: comptime_int) bool { return nvic.ISER & (1 << num) != 0; } @@ -181,7 +181,7 @@ pub const NestedVectorInterruptController = extern struct { nvic.ICER |= 1 << num; } - pub fn is_pending(nvic: *volatile NestedVectorInterruptController, num: comptime_int) void { + pub fn is_pending(nvic: *volatile NestedVectorInterruptController, num: comptime_int) bool { return nvic.ISPR & (1 << num) != 0; } diff --git a/core/src/cpus/msp430.zig b/core/src/cpus/msp430.zig index c0ddf51b9..4df67a5cb 100644 --- a/core/src/cpus/msp430.zig +++ b/core/src/cpus/msp430.zig @@ -136,7 +136,7 @@ export fn memset(dest: [*]u8, ch: u8, count: usize) callconv(.c) [*]u8 { _ = count; // R14 asm volatile ( \\ MOV R12, R5 - \\ ADD R5, R14 + \\ ADD R14, R5 \\memset_loop: \\ CMP R5, R12 \\ JEQ memset_done @@ -144,7 +144,7 @@ export fn memset(dest: [*]u8, ch: u8, count: usize) callconv(.c) [*]u8 { \\ INC R12 \\ JMP memset_loop \\memset_done: - \\ SUB R12, R14 + \\ SUB R14, R12 ::: .{ .r5 = true, // r12 doesn't go in the clobbers because it is restored before exiting @@ -160,8 +160,8 @@ export fn memcpy(dest: [*]u8, src: [*]const u8, count: usize) callconv(.c) [*]u8 _ = src; // R13 _ = count; // R14 asm volatile ( - \\ MOV R5, R12 - \\ ADD R5, R14 + \\ MOV R12, R5 + \\ ADD R14, R5 \\memcpy_loop: \\ CMP R5, R12 \\ JEQ memcpy_done @@ -169,7 +169,7 @@ export fn memcpy(dest: [*]u8, src: [*]const u8, count: usize) callconv(.c) [*]u8 \\ INC R12 \\ INC R13 \\memcpy_done: - \\ SUB R12, R14 + \\ SUB R14, R12 ::: .{ .r5 = true, // r12 doesn't go in the clobbers because it is restored before exiting diff --git a/core/src/cpus/riscv32.zig b/core/src/cpus/riscv32.zig index 10aa6794b..838efe2f1 100644 --- a/core/src/cpus/riscv32.zig +++ b/core/src/cpus/riscv32.zig @@ -9,9 +9,11 @@ pub const nop = riscv32_common.nop; pub const wfi = riscv32_common.wfi; pub fn wfe() void { - asm volatile ("csrs 0x810, 0x1"); + // Enable MIE (Machine Interrupt Enable) in mstatus so WFI can + // wake up on interrupts, then re-enable after WFI. + asm volatile ("csrs 0x300, 0x1"); wfi(); - asm volatile ("csrs 0x810, 0x1"); + asm volatile ("csrs 0x300, 0x1"); } pub const startup_logic = struct { diff --git a/core/src/utilities.zig b/core/src/utilities.zig index 3614d9eeb..def02a9aa 100644 --- a/core/src/utilities.zig +++ b/core/src/utilities.zig @@ -576,7 +576,7 @@ pub fn CircularBuffer(comptime T: type, comptime len: usize) type { buffer.full = true; } - pub fn read(buffer: *Self, out: []u8) usize { + pub fn read(buffer: *Self, out: []T) usize { buffer.assert_valid(); defer buffer.assert_valid(); @@ -589,7 +589,7 @@ pub fn CircularBuffer(comptime T: type, comptime len: usize) type { return count; } - pub fn write(buffer: *Self, data: []const u8) error{Full}!void { + pub fn write(buffer: *Self, data: []const T) error{Full}!void { buffer.assert_valid(); defer buffer.assert_valid(); for (data) |d| { From 06a61bb637362009692b274a6a85cac749246e40 Mon Sep 17 00:00:00 2001 From: by Date: Wed, 15 Jul 2026 07:18:17 +0800 Subject: [PATCH 5/5] Revert "fix(core): correct several CPU port and utility bugs" This reverts commit 117a4f1ef39718e616986d8e8c6e5f9d7d71208d. --- core/src/cpus/cortex_m.zig | 4 ++-- core/src/cpus/cortex_m/m0plus.zig | 4 ++-- core/src/cpus/msp430.zig | 10 +++++----- core/src/cpus/riscv32.zig | 6 ++---- core/src/utilities.zig | 4 ++-- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 1dde51305..2d1acf289 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -262,8 +262,8 @@ pub const interrupt = struct { switch (cortex_m) { .cortex_m0plus, => { - if (excpt == .SVCALL) ppb.SHCSR.raw |= 0x0000_8000 orelse - @compileError("not supported on this platform"); + if (excpt == .SVCALL) ppb.SHCSR.raw |= 0x0000_8000; + @compileError("not supported on this platform"); }, .cortex_m3, .cortex_m4, .cortex_m7 => { switch (excpt) { diff --git a/core/src/cpus/cortex_m/m0plus.zig b/core/src/cpus/cortex_m/m0plus.zig index fd37d2565..7aedb4113 100644 --- a/core/src/cpus/cortex_m/m0plus.zig +++ b/core/src/cpus/cortex_m/m0plus.zig @@ -169,7 +169,7 @@ pub const NestedVectorInterruptController = extern struct { /// register saves value 192 to the register. IPR: [32]u8, - pub fn is_enabled(nvic: *volatile NestedVectorInterruptController, num: comptime_int) bool { + pub fn is_enabled(nvic: *volatile NestedVectorInterruptController, num: comptime_int) void { return nvic.ISER & (1 << num) != 0; } @@ -181,7 +181,7 @@ pub const NestedVectorInterruptController = extern struct { nvic.ICER |= 1 << num; } - pub fn is_pending(nvic: *volatile NestedVectorInterruptController, num: comptime_int) bool { + pub fn is_pending(nvic: *volatile NestedVectorInterruptController, num: comptime_int) void { return nvic.ISPR & (1 << num) != 0; } diff --git a/core/src/cpus/msp430.zig b/core/src/cpus/msp430.zig index 4df67a5cb..c0ddf51b9 100644 --- a/core/src/cpus/msp430.zig +++ b/core/src/cpus/msp430.zig @@ -136,7 +136,7 @@ export fn memset(dest: [*]u8, ch: u8, count: usize) callconv(.c) [*]u8 { _ = count; // R14 asm volatile ( \\ MOV R12, R5 - \\ ADD R14, R5 + \\ ADD R5, R14 \\memset_loop: \\ CMP R5, R12 \\ JEQ memset_done @@ -144,7 +144,7 @@ export fn memset(dest: [*]u8, ch: u8, count: usize) callconv(.c) [*]u8 { \\ INC R12 \\ JMP memset_loop \\memset_done: - \\ SUB R14, R12 + \\ SUB R12, R14 ::: .{ .r5 = true, // r12 doesn't go in the clobbers because it is restored before exiting @@ -160,8 +160,8 @@ export fn memcpy(dest: [*]u8, src: [*]const u8, count: usize) callconv(.c) [*]u8 _ = src; // R13 _ = count; // R14 asm volatile ( - \\ MOV R12, R5 - \\ ADD R14, R5 + \\ MOV R5, R12 + \\ ADD R5, R14 \\memcpy_loop: \\ CMP R5, R12 \\ JEQ memcpy_done @@ -169,7 +169,7 @@ export fn memcpy(dest: [*]u8, src: [*]const u8, count: usize) callconv(.c) [*]u8 \\ INC R12 \\ INC R13 \\memcpy_done: - \\ SUB R14, R12 + \\ SUB R12, R14 ::: .{ .r5 = true, // r12 doesn't go in the clobbers because it is restored before exiting diff --git a/core/src/cpus/riscv32.zig b/core/src/cpus/riscv32.zig index 838efe2f1..10aa6794b 100644 --- a/core/src/cpus/riscv32.zig +++ b/core/src/cpus/riscv32.zig @@ -9,11 +9,9 @@ pub const nop = riscv32_common.nop; pub const wfi = riscv32_common.wfi; pub fn wfe() void { - // Enable MIE (Machine Interrupt Enable) in mstatus so WFI can - // wake up on interrupts, then re-enable after WFI. - asm volatile ("csrs 0x300, 0x1"); + asm volatile ("csrs 0x810, 0x1"); wfi(); - asm volatile ("csrs 0x300, 0x1"); + asm volatile ("csrs 0x810, 0x1"); } pub const startup_logic = struct { diff --git a/core/src/utilities.zig b/core/src/utilities.zig index def02a9aa..3614d9eeb 100644 --- a/core/src/utilities.zig +++ b/core/src/utilities.zig @@ -576,7 +576,7 @@ pub fn CircularBuffer(comptime T: type, comptime len: usize) type { buffer.full = true; } - pub fn read(buffer: *Self, out: []T) usize { + pub fn read(buffer: *Self, out: []u8) usize { buffer.assert_valid(); defer buffer.assert_valid(); @@ -589,7 +589,7 @@ pub fn CircularBuffer(comptime T: type, comptime len: usize) type { return count; } - pub fn write(buffer: *Self, data: []const T) error{Full}!void { + pub fn write(buffer: *Self, data: []const u8) error{Full}!void { buffer.assert_valid(); defer buffer.assert_valid(); for (data) |d| {