Skip to content

Commit 1aecd46

Browse files
authored
esp: Add GPIO device to hal (#483)
* esp32c3: Add gpio driver and stepper example * Add stepper example
1 parent ab10027 commit 1aecd46

File tree

6 files changed

+157
-14
lines changed

6 files changed

+157
-14
lines changed

examples/espressif/esp/build.zig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ pub fn build(b: *std.Build) void {
1919

2020
const available_examples = [_]Example{
2121
.{ .name = "blinky", .file = "src/blinky.zig" },
22-
.{ .name = "interrupts", .file = "src/interrupts.zig" },
2322
.{ .name = "custom_clock_config", .file = "src/custom_clock_config.zig" },
23+
.{ .name = "interrupts", .file = "src/interrupts.zig" },
24+
.{ .name = "stepper_driver", .file = "src/stepper_driver.zig" },
2425
};
2526

2627
for (available_examples) |example| {

examples/espressif/esp/src/blinky.zig

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ const peripherals = microzig.chip.peripherals;
44
const hal = microzig.hal;
55
const gpio = hal.gpio;
66
const usb_serial_jtag = hal.usb_serial_jtag;
7-
const time = microzig.hal.time;
7+
const time = hal.time;
88

99
pub const microzig_options: microzig.Options = .{
10-
.log_level = .debug,
1110
.logFn = usb_serial_jtag.logger.logFn,
1211
};
1312

@@ -17,9 +16,9 @@ pub fn main() !void {
1716
.drive_strength = gpio.DriveStrength.@"40mA",
1817
};
1918

20-
const led_r_pin = gpio.instance.GPIO3;
21-
const led_g_pin = gpio.instance.GPIO4;
22-
const led_b_pin = gpio.instance.GPIO5;
19+
const led_r_pin = gpio.instance.num(3);
20+
const led_g_pin = gpio.instance.num(4);
21+
const led_b_pin = gpio.instance.num(5);
2322

2423
led_r_pin.apply(pin_config);
2524
led_g_pin.apply(pin_config);
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const std = @import("std");
2+
const microzig = @import("microzig");
3+
const hal = microzig.hal;
4+
const gpio = hal.gpio;
5+
const time = hal.time;
6+
7+
const GPIO_Device = hal.drivers.GPIO_Device;
8+
const ClockDevice = hal.drivers.ClockDevice;
9+
const A4988 = microzig.drivers.stepper.A4988;
10+
11+
const usb_serial_jtag = hal.usb_serial_jtag;
12+
13+
pub const microzig_options = microzig.Options{
14+
.logFn = usb_serial_jtag.logger.logFn,
15+
};
16+
17+
pub fn main() !void {
18+
var cd = ClockDevice{};
19+
20+
// Setup all pins for the stepper driver
21+
var pins: struct {
22+
ms1: GPIO_Device,
23+
ms2: GPIO_Device,
24+
ms3: GPIO_Device,
25+
dir: GPIO_Device,
26+
step: GPIO_Device,
27+
} = undefined;
28+
inline for (std.meta.fields(@TypeOf(pins)), .{ 0, 1, 2, 20, 10 }) |field, num| {
29+
const pin = gpio.instance.num(num);
30+
// Give the pin a sane default config
31+
pin.apply(.{});
32+
@field(pins, field.name) = GPIO_Device.init(pin);
33+
}
34+
35+
var stepper = A4988.init(.{
36+
.ms1_pin = pins.ms1.digital_io(),
37+
.ms2_pin = pins.ms2.digital_io(),
38+
.ms3_pin = pins.ms3.digital_io(),
39+
.dir_pin = pins.dir.digital_io(),
40+
.step_pin = pins.step.digital_io(),
41+
.clock_device = cd.clock_device(),
42+
});
43+
44+
try stepper.begin(100, 1);
45+
46+
while (true) {
47+
const linear_profile = A4988.Speed_Profile{ .linear_speed = .{ .accel = 200, .decel = 200 } };
48+
const constant_profile = A4988.Speed_Profile.constant_speed;
49+
// Try both constant and linear acceleration profiles
50+
inline for (.{ constant_profile, linear_profile }) |profile| {
51+
stepper.set_speed_profile(
52+
profile,
53+
);
54+
std.log.info("profile: {s} ", .{@tagName(profile)});
55+
// Try different microsteps
56+
inline for (.{ 1, 2, 4, 8, 16 }) |ms| {
57+
_ = try stepper.set_microstep(ms);
58+
std.log.info("microsteps: {}", .{ms});
59+
try stepper.rotate(360);
60+
time.sleep_ms(250);
61+
try stepper.rotate(-360);
62+
time.sleep_ms(250);
63+
}
64+
}
65+
}
66+
}

examples/raspberrypi/rp2xxx/src/stepper_driver.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ pub fn main() !void {
4848
}
4949

5050
var stepper = A4988.init(.{
51-
.dir_pin = pins.dir.digital_io(),
52-
.step_pin = pins.step.digital_io(),
5351
.ms1_pin = pins.ms1.digital_io(),
5452
.ms2_pin = pins.ms2.digital_io(),
5553
.ms3_pin = pins.ms3.digital_io(),
54+
.dir_pin = pins.dir.digital_io(),
55+
.step_pin = pins.step.digital_io(),
5656
.clock_device = cd.clock_device(),
5757
});
5858

port/espressif/esp/src/hal/drivers.zig

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,83 @@ const hal = @import("../hal.zig");
99
const drivers = microzig.drivers.base;
1010
const time = microzig.drivers.time;
1111

12+
const Digital_IO = drivers.Digital_IO;
1213
const Clock_Device = drivers.Clock_Device;
1314

15+
///
16+
/// Implementation of a digital i/o device.
17+
///
18+
pub const GPIO_Device = struct {
19+
pub const SetDirError = Digital_IO.SetDirError;
20+
pub const SetBiasError = Digital_IO.SetBiasError;
21+
pub const WriteError = Digital_IO.WriteError;
22+
pub const ReadError = Digital_IO.ReadError;
23+
24+
pub const State = Digital_IO.State;
25+
pub const Direction = Digital_IO.Direction;
26+
27+
pin: hal.gpio.Pin,
28+
29+
pub fn init(pin: hal.gpio.Pin) GPIO_Device {
30+
return .{ .pin = pin };
31+
}
32+
33+
pub fn digital_io(dio: *GPIO_Device) Digital_IO {
34+
return Digital_IO{
35+
.ptr = dio,
36+
.vtable = &vtable,
37+
};
38+
}
39+
40+
pub fn set_direction(dio: GPIO_Device, dir: Direction) SetDirError!void {
41+
dio.pin.set_output_enable(dir == .output);
42+
}
43+
44+
pub fn set_bias(dio: GPIO_Device, maybe_bias: ?State) SetBiasError!void {
45+
dio.pin.set_pullup(if (maybe_bias) |bias| switch (bias) {
46+
.low => false,
47+
.high => true,
48+
} else false);
49+
}
50+
51+
pub fn write(dio: GPIO_Device, state: State) WriteError!void {
52+
dio.pin.write(@enumFromInt(state.value()));
53+
}
54+
55+
pub fn read(dio: GPIO_Device) ReadError!State {
56+
return @enumFromInt(@intFromEnum(dio.pin.read()));
57+
}
58+
59+
const vtable = Digital_IO.VTable{
60+
.set_direction_fn = set_direction_fn,
61+
.set_bias_fn = set_bias_fn,
62+
.write_fn = write_fn,
63+
.read_fn = read_fn,
64+
};
65+
66+
fn set_direction_fn(io: *anyopaque, dir: Direction) SetDirError!void {
67+
const gpio: *GPIO_Device = @ptrCast(@alignCast(io));
68+
try gpio.set_direction(dir);
69+
}
70+
71+
fn set_bias_fn(io: *anyopaque, bias: ?State) SetBiasError!void {
72+
const gpio: *GPIO_Device = @ptrCast(@alignCast(io));
73+
74+
try gpio.set_bias(bias);
75+
}
76+
77+
fn write_fn(io: *anyopaque, state: State) WriteError!void {
78+
const gpio: *GPIO_Device = @ptrCast(@alignCast(io));
79+
80+
try gpio.write(state);
81+
}
82+
83+
fn read_fn(io: *anyopaque) ReadError!State {
84+
const gpio: *GPIO_Device = @ptrCast(@alignCast(io));
85+
return try gpio.read();
86+
}
87+
};
88+
1489
///
1590
/// Implementation of a time device
1691
///

port/espressif/esp/src/hal/gpio.zig

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ pub const Pin = struct {
6767
usb_conf0.DM_PULLDOWN == 0);
6868
}
6969

70-
GPIO.ENABLE_W1TS.write(.{ .ENABLE_W1TS = @as(u17, 1) << self.number, .padding = 0 });
70+
GPIO.ENABLE_W1TS.write(.{ .ENABLE_W1TS = @as(u26, 1) << self.number, .padding = 0 });
7171
}
7272

7373
pub fn reset(self: Pin) void {
7474
IO_MUX.GPIO[self.number].write_raw(0x00);
7575
GPIO.FUNC_OUT_SEL_CFG[self.number].write_raw(0x00);
7676
GPIO.PIN[self.number].write_raw(0x00);
77-
GPIO.ENABLE_W1TC.write(.{ .ENABLE_W1TC = @as(u17, 1) << self.number, .padding = 0 });
77+
GPIO.ENABLE_W1TC.write(.{ .ENABLE_W1TC = @as(u26, 1) << self.number, .padding = 0 });
7878
}
7979

8080
pub fn set_output_enable(self: Pin, enable: bool) void {
@@ -120,11 +120,12 @@ pub const Pin = struct {
120120
}
121121

122122
pub fn write(self: Pin, level: Level) void {
123+
// Assert that the pin is set to output enabled
123124
std.debug.assert(GPIO.FUNC_OUT_SEL_CFG[self.number].read().OEN_SEL == 1);
124125

125126
switch (level) {
126-
Level.low => GPIO.OUT_W1TC.write(.{ .OUT_W1TC = @as(u17, 1) << self.number, .padding = 0 }),
127-
Level.high => GPIO.OUT_W1TS.write(.{ .OUT_W1TS = @as(u17, 1) << self.number, .padding = 0 }),
127+
Level.low => GPIO.OUT_W1TC.write(.{ .OUT_W1TC = @as(u26, 1) << self.number }),
128+
Level.high => GPIO.OUT_W1TS.write(.{ .OUT_W1TS = @as(u26, 1) << self.number }),
128129
}
129130
}
130131

@@ -135,7 +136,7 @@ pub const Pin = struct {
135136
}
136137

137138
pub fn read(self: Pin) Level {
138-
std.debug.assert(IO_MUX.GPIO[self.number].FUN_IE == 1);
139+
std.debug.assert(IO_MUX.GPIO[self.number].read().FUN_IE == 1);
139140

140141
return @enumFromInt(GPIO.IN.raw >> self.number & 0x01);
141142
}
@@ -175,9 +176,10 @@ pub const instance = struct {
175176
pub const GPIO18: Pin = .{ .number = 18 };
176177
pub const GPIO19: Pin = .{ .number = 19 };
177178
pub const GPIO20: Pin = .{ .number = 20 };
179+
pub const GPIO21: Pin = .{ .number = 21 };
178180

179181
pub fn num(instance_number: u5) Pin {
180-
std.debug.assert(instance_number < 21);
182+
std.debug.assert(instance_number < 22);
181183
return .{ .number = instance_number };
182184
}
183185
};

0 commit comments

Comments
 (0)