From f2ab4659f402d335bf506b03978123ac8c847b21 Mon Sep 17 00:00:00 2001 From: RecursiveError Date: Sat, 23 Aug 2025 22:51:32 -0300 Subject: [PATCH] I2C STYLE TEST --- drivers/base/Datagram_Device.zig | 38 +++++++++---------- drivers/base/I2C_Device.zig | 35 +++++++++++++++++ examples/raspberrypi/rp2xxx/build.zig | 1 + .../rp2xxx/src/rp2040_only/i2c_test.zig | 37 ++++++++++++++++++ 4 files changed, 92 insertions(+), 19 deletions(-) create mode 100644 examples/raspberrypi/rp2xxx/src/rp2040_only/i2c_test.zig diff --git a/drivers/base/Datagram_Device.zig b/drivers/base/Datagram_Device.zig index cdecdf3b6..cff0980d5 100644 --- a/drivers/base/Datagram_Device.zig +++ b/drivers/base/Datagram_Device.zig @@ -14,7 +14,7 @@ const Datagram_Device = @This(); /// /// If the implementation requires no `ptr` pointer, /// you can safely use `undefined` here. -ptr: *anyopaque, +//ptr: *anyopaque, no more CTX prt /// Virtual table for the datagram device functions. vtable: *const VTable, @@ -27,33 +27,33 @@ pub const AnyError = ConnectError || WriteError || ReadError; /// Establishes a connection to the device (like activating a chip-select lane or similar). /// NOTE: Call `.disconnect()` when the usage of the device is done to release it. -pub fn connect(dd: Datagram_Device) ConnectError!void { +pub fn connect(dd: *const Datagram_Device) ConnectError!void { if (dd.vtable.connect_fn) |connectFn| { - return connectFn(dd.ptr); + return connectFn(dd); } } /// Releases a device from the connection. -pub fn disconnect(dd: Datagram_Device) void { +pub fn disconnect(dd: *const Datagram_Device) void { if (dd.vtable.disconnect_fn) |disconnectFn| { - return disconnectFn(dd.ptr); + return disconnectFn(dd); } } /// Writes a single `datagram` to the device. -pub fn write(dd: Datagram_Device, datagram: []const u8) WriteError!void { +pub fn write(dd: *const Datagram_Device, datagram: []const u8) WriteError!void { return try dd.writev(&.{datagram}); } /// Writes multiple `datagrams` to the device. -pub fn writev(dd: Datagram_Device, datagrams: []const []const u8) WriteError!void { +pub fn writev(dd: *const Datagram_Device, datagrams: []const []const u8) WriteError!void { const writev_fn = dd.vtable.writev_fn orelse return error.Unsupported; - return writev_fn(dd.ptr, datagrams); + return writev_fn(dd, datagrams); } /// Writes then reads a single `datagram` to the device. pub fn write_then_read( - dd: Datagram_Device, + dd: *const Datagram_Device, src: []const u8, dst: []u8, ) (WriteError || ReadError)!void { @@ -62,12 +62,12 @@ pub fn write_then_read( /// Writes a slice of datagrams to the device, then reads back into another slice of datagrams pub fn writev_then_readv( - dd: Datagram_Device, + dd: *const Datagram_Device, write_chunks: []const []const u8, read_chunks: []const []u8, ) (WriteError || ReadError)!void { const writev_then_readv_fn = dd.vtable.writev_then_readv_fn orelse return error.Unsupported; - return writev_then_readv_fn(dd.ptr, write_chunks, read_chunks); + return writev_then_readv_fn(dd, write_chunks, read_chunks); } /// Reads a single `datagram` from the device. @@ -75,7 +75,7 @@ pub fn writev_then_readv( /// /// If `error.BufferOverrun` is returned, the `datagram` will still be fully filled with the data /// that was received up till the overrun. The rest of the datagram will be discarded. -pub fn read(dd: Datagram_Device, datagram: []u8) ReadError!usize { +pub fn read(dd: *const Datagram_Device, datagram: []u8) ReadError!usize { return try dd.readv(&.{datagram}); } @@ -84,18 +84,18 @@ pub fn read(dd: Datagram_Device, datagram: []u8) ReadError!usize { /// /// If `error.BufferOverrun` is returned, the `datagrams` will still be fully filled with the data /// that was received up till the overrun. The rest of the datagram will be discarded. -pub fn readv(dd: Datagram_Device, datagrams: []const []u8) ReadError!usize { +pub fn readv(dd: *const Datagram_Device, datagrams: []const []u8) ReadError!usize { const readv_fn = dd.vtable.readv_fn orelse return error.Unsupported; - return readv_fn(dd.ptr, datagrams); + return readv_fn(dd, datagrams); } pub const VTable = struct { - connect_fn: ?*const fn (*anyopaque) ConnectError!void, - disconnect_fn: ?*const fn (*anyopaque) void, - writev_fn: ?*const fn (*anyopaque, datagrams: []const []const u8) WriteError!void, - readv_fn: ?*const fn (*anyopaque, datagrams: []const []u8) ReadError!usize, + connect_fn: ?*const fn (*const Datagram_Device) ConnectError!void, + disconnect_fn: ?*const fn (*const Datagram_Device) void, + writev_fn: ?*const fn (*const Datagram_Device, datagrams: []const []const u8) WriteError!void, + readv_fn: ?*const fn (*const Datagram_Device, datagrams: []const []u8) ReadError!usize, writev_then_readv_fn: ?*const fn ( - *anyopaque, + *const Datagram_Device, write_chunks: []const []const u8, read_chunks: []const []u8, ) (WriteError || ReadError)!void = null, diff --git a/drivers/base/I2C_Device.zig b/drivers/base/I2C_Device.zig index 242b2af83..76c06ba38 100644 --- a/drivers/base/I2C_Device.zig +++ b/drivers/base/I2C_Device.zig @@ -3,6 +3,7 @@ //! const std = @import("std"); +const Datagram = @import("Datagram_Device.zig"); /// Error is a set of errors that make sense for I2C at the protocol level pub const Error = error{ @@ -66,6 +67,12 @@ pub const Address = enum(u7) { } }; +pub const I2C_Datagram = struct { + addr: Address, + bus: *const I2C_Device, + interface: Datagram, +}; + const I2C_Device = @This(); /// Pointer to the object implementing the driver. @@ -117,6 +124,34 @@ pub fn readv(dev: I2C_Device, address: Address, datagrams: []const []u8) Interfa return readv_fn(dev.ptr, address, datagrams); } +//just a test, no error return yet +fn datagram_readv(dd: *const Datagram, datagrams: []const []u8) Datagram.ReadError!usize { + const dev: *const I2C_Datagram = @alignCast(@fieldParentPtr("interface", dd)); + return dev.bus.readv(dev.addr, datagrams) catch Datagram.ReadError.Timeout; +} + +//just a test, no error return yet +fn datagram_writev(dd: *const Datagram, datagrams: []const []const u8) Datagram.WriteError!void { + const dev: *const I2C_Datagram = @alignCast(@fieldParentPtr("interface", dd)); + dev.bus.writev(dev.addr, datagrams) catch {}; +} + +pub fn Datagram_Device(dev: *const I2C_Device, addr: Address) I2C_Datagram { + return I2C_Datagram{ + .bus = dev, + .addr = addr, + .interface = Datagram{ .vtable = &Datagram_Vtable }, + }; +} + +const Datagram_Vtable = Datagram.VTable{ + .connect_fn = null, + .disconnect_fn = null, + .writev_then_readv_fn = null, + .readv_fn = datagram_readv, + .writev_fn = datagram_writev, +}; + pub const VTable = struct { writev_fn: ?*const fn (*anyopaque, Address, datagrams: []const []const u8) InterfaceError!void, readv_fn: ?*const fn (*anyopaque, Address, datagrams: []const []u8) InterfaceError!usize, diff --git a/examples/raspberrypi/rp2xxx/build.zig b/examples/raspberrypi/rp2xxx/build.zig index 34f98d9ba..6474af2ad 100644 --- a/examples/raspberrypi/rp2xxx/build.zig +++ b/examples/raspberrypi/rp2xxx/build.zig @@ -24,6 +24,7 @@ pub fn build(b: *std.Build) void { .{ .target = raspberrypi.pico, .name = "pico_multicore", .file = "src/rp2040_only/blinky_core1.zig" }, .{ .target = raspberrypi.pico, .name = "pico_hd44780", .file = "src/rp2040_only/hd44780.zig" }, .{ .target = raspberrypi.pico, .name = "pico_pcf8574", .file = "src/rp2040_only/pcf8574.zig" }, + .{ .target = raspberrypi.pico, .name = "pico_i2_test", .file = "src/rp2040_only/i2c_test.zig" }, .{ .target = raspberrypi.pico, .name = "pico_i2c_slave", .file = "src/rp2040_only/i2c_slave.zig" }, .{ .target = raspberrypi.pico_flashless, .name = "pico_flashless_blinky", .file = "src/blinky.zig" }, .{ .target = raspberrypi.pico2_arm_flashless, .name = "pico2_arm_flashless_blinky", .file = "src/blinky.zig" }, diff --git a/examples/raspberrypi/rp2xxx/src/rp2040_only/i2c_test.zig b/examples/raspberrypi/rp2xxx/src/rp2040_only/i2c_test.zig new file mode 100644 index 000000000..93f45d75a --- /dev/null +++ b/examples/raspberrypi/rp2xxx/src/rp2040_only/i2c_test.zig @@ -0,0 +1,37 @@ +const std = @import("std"); +const microzig = @import("microzig"); + +const drivers = microzig.drivers; +const PCF8574 = drivers.IO_expander.PCF8574; +const State = drivers.base.Digital_IO.State; + +const rp2040 = microzig.hal; +const i2c = rp2040.i2c; +const I2C_Device = rp2040.drivers.I2C_Device; +const gpio = rp2040.gpio; +const timer = rp2040.time; + +const i2c0 = i2c.instance.num(0); + +var i2c_device = I2C_Device.init(i2c0, null); + +pub fn main() !void { + const scl_pin = gpio.num(5); + const sda_pin = gpio.num(4); + inline for (&.{ scl_pin, sda_pin }) |pin| { + pin.set_slew_rate(.slow); + pin.set_schmitt_trigger_enabled(true); + pin.set_function(.i2c); + } + + i2c0.apply(.{ + .clock_config = rp2040.clock_config, + }); + const datagram_dev = i2c_device.i2c_device().Datagram_Device(@enumFromInt(0x27)); + while (true) { + try datagram_dev.interface.write(&.{0b01011010}); + timer.sleep_ms(500); + try datagram_dev.interface.write(&.{0b10100101}); + timer.sleep_ms(500); + } +}