Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/espressif/esp/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub fn build(b: *std.Build) void {
.{ .name = "blinky", .file = "src/blinky.zig" },
.{ .name = "custom_clock_config", .file = "src/custom_clock_config.zig" },
.{ .name = "gpio_input", .file = "src/gpio_input.zig" },
.{ .name = "i2c_accel", .file = "src/i2c_accel.zig" },
.{ .name = "i2c_bus_scan", .file = "src/i2c_bus_scan.zig" },
.{ .name = "i2c_temp", .file = "src/i2c_temp.zig" },
.{ .name = "i2c_display_sh1106", .file = "src/i2c_display_sh1106.zig" },
Expand Down
76 changes: 76 additions & 0 deletions examples/espressif/esp/src/i2c_accel.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const std = @import("std");
const microzig = @import("microzig");
const ICM_20948 = microzig.drivers.sensor.ICM_20948(.{});

const esp = microzig.hal;
const i2c = esp.i2c;
const gpio = esp.gpio;
const I2C_Device = esp.drivers.I2C_Device;
const sleep_ms = esp.time.sleep_ms;

var i2c0 = i2c.instance.num(0);

const usb_serial_jtag = esp.usb_serial_jtag;

pub const std_options = microzig.std_options(.{
.log_level = .info,
.logFn = usb_serial_jtag.logger.log,
});

comptime {
_ = microzig.export_startup();
}

pub fn main() !void {
const sda_pin = gpio.num(5);
const scl_pin = gpio.num(6);

// Setup SDA pin
sda_pin.apply(.{
.output_enable = true,
.input_enable = true,
.open_drain = true,
.pull = .up,
});

// Setup SCL pin
scl_pin.apply(.{
.output_enable = true,
.input_enable = true,
.open_drain = true,
.pull = .up,
});

i2c0.connect_pins(.{ .sda = sda_pin, .scl = scl_pin });
try i2c0.apply(100_000);

// Create i2c and clock devices
var i2c_device = I2C_Device.init(i2c0, null);
// Pass devices to driver to create sensor instance
var dev = try ICM_20948.init(
i2c_device.i2c_device(),
@fromBackingInt(@intCast(0x69)),
esp.drivers.clock_device(),
.{
.accel_dlp = .@"6Hz",
.gyro_dlp = .@"6Hz",
.accel_odr_div = 21, // About 50Hz
.gyro_odr_div = 21, // About 50Hz
},
);

try dev.setup();

while (true) {
const data = try dev.get_accel_gyro_mag_data();
std.log.info(
"accel: x {d: >6.2} y {d: >6.2} z {d: >6.2} (m/s²) " ++
"gyro: x {d: >6.2} y {d: >6.2} z {d: >6.2} (rads) " ++
"temp: {d: >5.2}°C " ++
"mag: x {d: >6.2} y {d: >6.2} z {d: >6.2} (µT)",
.{ data.accel.x, data.accel.y, data.accel.z, data.gyro.x, data.gyro.y, data.gyro.z, data.temp, data.mag.x, data.mag.y, data.mag.z },
);

sleep_ms(500);
}
}
2 changes: 2 additions & 0 deletions examples/wch/ch32v/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ pub fn build(b: *std.Build) void {
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_uart_echo", .file = "src/uart_echo.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_uart_log", .file = "src/uart_log.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_i2c_bus_scan", .file = "src/i2c_bus_scan.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_i2c_accel", .file = "src/i2c_accel.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_i2c_eeprom", .file = "src/i2c_eeprom.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_i2c_eeprom_dma", .file = "src/i2c_eeprom_dma.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_i2c_position_sensor", .file = "src/i2c_position_sensor.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_spi_loopback", .file = "src/spi_loopback.zig" },
.{ .target = mb.ports.ch32v.boards.ch32v203.lana_tny, .name = "lana_tny_spi_flash_w25q", .file = "src/spi_flash_w25q.zig" },
Expand Down
77 changes: 77 additions & 0 deletions examples/wch/ch32v/src/i2c_accel.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const std = @import("std");
const microzig = @import("microzig");
const hal = microzig.hal;
const board = microzig.board;

const i2c = hal.i2c;

const ICM_20948 = microzig.drivers.sensor.ICM_20948(.{ .log_level = null });

const uart = board.uart_setup;
const i2c_hw = board.i2c_setup;

pub const std_options = microzig.std_options(.{
.log_level = .info,
.logFn = hal.usart.log,
});

// Configure I2C1 with DMA support
const i2c_config = i2c.Config{
.baud_rate = 100_000, // 100 kHz
.dma = .{
.tx_channel = .Ch6, // I2C1 TX must use Ch6
.rx_channel = .Ch7, // I2C1 RX must use Ch7
.priority = .High,
// Lower DMA threshold for testing (accelerometer makes 6-byte reads)
.threshold = 4,
},
};

comptime {
_ = microzig.export_startup();
}

pub fn main() !void {
// Board brings up clocks and time
board.init();

// Initialize UART for logging
uart.apply(.{ .baud_rate = 115200 });
hal.usart.init_logger(uart.instance);

// Initialize I2C
i2c_hw.apply(i2c_config);

// Get the specialized I2C_Device type for this config
const I2C_DeviceType = hal.drivers.I2C_Device(i2c_config);

// Create i2c and clock devices
var i2c_device = I2C_DeviceType.init(i2c_hw.instance, null);
// Pass devices to driver to create sensor instance
var dev = try ICM_20948.init(
i2c_device.i2c_device(),
@fromBackingInt(@intCast(0x69)),
hal.drivers.clock_device(),
.{
.accel_dlp = .@"6Hz",
.gyro_dlp = .@"6Hz",
.accel_odr_div = 21, // About 50Hz
.gyro_odr_div = 21, // About 50Hz
},
);

try dev.setup();

while (true) {
const data = try dev.get_accel_gyro_mag_data();
std.log.info(
"accel: x {d: >6.2} y {d: >6.2} z {d: >6.2} (m/s²) " ++
"gyro: x {d: >6.2} y {d: >6.2} z {d: >6.2} (rads) " ++
"temp: {d: >5.2}°C " ++
"mag: x {d: >6.2} y {d: >6.2} z {d: >6.2} (µT)",
.{ data.accel.x, data.accel.y, data.accel.z, data.gyro.x, data.gyro.y, data.gyro.z, data.temp, data.mag.x, data.mag.y, data.mag.z },
);

hal.time.sleep_ms(500);
}
}
73 changes: 73 additions & 0 deletions examples/wch/ch32v/src/i2c_eeprom_dma.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const std = @import("std");
const microzig = @import("microzig");
const hal = microzig.hal;
const board = microzig.board;
const i2c = hal.i2c;

const uart = board.uart_setup;
const i2c_hw = board.i2c_setup;

pub const panic = microzig.panic;

pub const std_options = microzig.std_options(.{
.log_level = .debug,
.logFn = hal.usart.log,
});

// Configure I2C1 with DMA support
const i2c_config = i2c.Config{
.baud_rate = 400_000, // 400 kHz fast mode
.dma = .{
.tx_channel = .Ch6, // I2C1 TX must use Ch6
.rx_channel = .Ch7, // I2C1 RX must use Ch7
.priority = .High,
},
};

comptime {
_ = microzig.export_startup();
}

pub fn main() !void {
// Board brings up clocks and time
board.init();

// Initialize UART for logging
uart.apply(.{ .baud_rate = 115200 });
hal.usart.init_logger(uart.instance);

// Initialize I2C
i2c_hw.apply(i2c_config);

const eeprom_address: i2c.Address = @fromBackingInt(0x50);

// Example: Write large buffer using DMA
std.log.info("Writing large buffer manually", .{});
var tx_buffer: [64]u8 = undefined;
for (&tx_buffer, 0..) |*byte, i| {
byte.* = @intCast(i);
}

// Explicit DMA write
std.log.info("Writing to EEPROM via DMA", .{});
try i2c_hw.instance.write_dma(i2c_config, eeprom_address, &tx_buffer, null);

hal.time.sleep_ms(10);

// Automatic selection (uses DMA for large transfers)
std.log.info("Writing to EEPROM via 'auto'", .{});
try i2c_hw.instance.write_auto(i2c_config, eeprom_address, &tx_buffer, null);

// Small transfer (automatic polling)
const small_buffer = [_]u8{ 0x12, 0x34 };
try i2c_hw.instance.write_auto(i2c_config, eeprom_address, &small_buffer, null);

// Read using DMA
std.log.info("Reading from EEPROM via DMA", .{});
var rx_buffer: [64]u8 = undefined;
try i2c_hw.instance.read_dma(i2c_config, eeprom_address, &rx_buffer, null);

while (true) {
hal.time.sleep_ms(1000);
}
}
4 changes: 2 additions & 2 deletions port/wch/ch32v/src/hals/drivers.zig
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,9 @@ pub const ClockDevice = struct {
///
/// Implementation of a `ClockDevice` that uses the HAL's `time` module.
///
pub fn clock_device() ClockDevice {
pub fn clock_device() drivers.ClockDevice {
const S = struct {
const vtable: ClockDevice.VTable = .{
const vtable: drivers.ClockDevice.VTable = .{
.get_time_since_boot = get_time_since_boot_fn,
};

Expand Down
9 changes: 8 additions & 1 deletion port/wch/ch32v/src/hals/i2c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@ pub const I2C = enum(u1) {
try i2c.wait_flag_star2("BUSY", 0, deadline);
}

/// Read using DMA (only available if DMA configured)
pub fn read_dma(
i2c: I2C,
comptime config: Config,
Expand Down Expand Up @@ -593,6 +592,10 @@ pub const I2C = enum(u1) {
///
/// Automatically selects between DMA and polling based on transfer size. DMA is used for
/// transfers over configured threshold, polling for smaller transfers.
///
/// NOTE: The 16-byte default threshold is a heuristic based on typical DMA setup overhead vs
/// polling cost. It has not been benchmarked specifically for CH32V and may not be optimal for
/// all use cases. For explicit control, use write_dma() or write_blocking() directly.
pub fn write_auto(
i2c: I2C,
comptime config: Config,
Expand All @@ -612,6 +615,10 @@ pub const I2C = enum(u1) {
///
/// Automatically selects between DMA and polling based on transfer size. DMA is used for
/// transfers over configured threshold, polling for smaller transfers.
///
/// NOTE: The 16-byte default threshold is a heuristic based on typical DMA setup overhead vs
/// polling cost. It has not been benchmarked specifically for CH32V and may not be optimal for
/// all use cases. For explicit control, use read_dma() or read_blocking() directly.
pub fn read_auto(
i2c: I2C,
comptime config: Config,
Expand Down
Loading