Skip to content

Commit

Permalink
Add A4988 Stepper driver (#359)
Browse files Browse the repository at this point in the history
* wip: Add A4988 stepper motor driver

* wip: Rewrite driver in terms of time types

* Finish using mdf time

* example is not rp2040 only

* Generalize driver and add DRV8825 support

* mv to generic name

* Cleanup todos

* Update readme

* Update module comment

* Set DRV times

* Actually wait board's sleep time

* More explanatory comments

* Fix typos and cleanup

* add stepper.zig to build.zig.zon

* Add a few more tests
  • Loading branch information
Grazfather authored Jan 25, 2025
1 parent a7a702b commit ceefa56
Show file tree
Hide file tree
Showing 8 changed files with 751 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ A collection of device drivers for the use with MicroZig.
- [ ] [ILI9488](https://github.com/ZigEmbeddedGroup/microzig/issues/249)
- Wireless
- [ ] [SX1276, SX1278](https://github.com/ZigEmbeddedGroup/microzig/issues/248)
- Stepper
- [x] A4988
- [x] DRV8825 (Implemented but untested)
109 changes: 109 additions & 0 deletions drivers/base/Clock_Device.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//!
//! An abstract clock device
//!
//! Clock_Devices can be used to track time & sleep
//!

const std = @import("std");
const mdf = @import("../framework.zig");

const Clock_Device = @This();

/// Pointer to the object implementing the driver.
///
/// If the implementation requires no `object` pointer,
/// you can safely use `undefined` here.
object: *anyopaque,

/// Virtual table for the digital i/o functions.
vtable: *const VTable,

/// API
pub fn is_reached(td: Clock_Device, time: mdf.time.Absolute) bool {
const now = td.get_time_since_boot();
return time.is_reached_by(now);
}

pub fn make_timeout(td: Clock_Device, timeout: mdf.time.Duration) mdf.time.Absolute {
return @as(mdf.time.Absolute, @enumFromInt(td.get_time_since_boot().to_us() + timeout.to_us()));
}

pub fn make_timeout_us(td: Clock_Device, timeout_us: u64) mdf.time.Absolute {
return @as(mdf.time.Absolute, @enumFromInt(td.get_time_since_boot().to_us() + timeout_us));
}

pub fn sleep_ms(td: Clock_Device, time_ms: u32) void {
td.sleep_us(time_ms * 1000);
}

pub fn sleep_us(td: Clock_Device, time_us: u64) void {
const end_time = td.make_timeout_us(time_us);
while (!td.is_reached(end_time)) {}
}

/// VTable methods
pub fn get_time_since_boot(td: Clock_Device) mdf.time.Absolute {
return td.vtable.get_time_since_boot(td.object);
}

pub const VTable = struct {
get_time_since_boot: *const fn (*anyopaque) mdf.time.Absolute,
};

pub const Test_Device = struct {
time: u64 = 0,

pub fn init() Test_Device {
return Test_Device{};
}

pub fn elapse_time(dev: *Test_Device, time_us: u64) void {
dev.time += time_us;
}

pub fn set_time(dev: *Test_Device, time_us: u64) void {
dev.time = time_us;
}

pub fn clock_device(dev: *Test_Device) Clock_Device {
return Clock_Device{
.object = dev,
.vtable = &vtable,
};
}

pub fn get_time_since_boot_fn(ctx: *anyopaque) mdf.time.Absolute {
const dev: *Test_Device = @ptrCast(@alignCast(ctx));
return @enumFromInt(dev.time);
}

const vtable = VTable{
.get_time_since_boot = Test_Device.get_time_since_boot_fn,
};
};

test Test_Device {
var ttd = Test_Device.init();

const td = ttd.clock_device();

// Check if time elapses between calls
try std.testing.expectEqual(0, td.get_time_since_boot().to_us());
ttd.elapse_time(2);
try std.testing.expectEqual(2, td.get_time_since_boot().to_us());

try std.testing.expect(!td.is_reached(@enumFromInt(4)));
ttd.elapse_time(2);
try std.testing.expect(td.is_reached(@enumFromInt(4)));

// Timeouts
try std.testing.expectEqual(
54,
@intFromEnum(td.make_timeout(mdf.time.Duration.from_us(50))),
);
ttd.elapse_time(50);
try std.testing.expectEqual(
104,
@intFromEnum(td.make_timeout_us(50)),
);
}
1 change: 1 addition & 0 deletions drivers/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"display",
"input",
"io_expander",
"stepper",
},
}
5 changes: 5 additions & 0 deletions drivers/framework.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub const input = struct {
};
};

pub const stepper = @import("stepper/stepper.zig");

pub const IO_expander = struct {
pub const pcf8574 = @import("io_expander/pcf8574.zig");
pub const PCF8574 = pcf8574.PCF8574;
Expand Down Expand Up @@ -168,6 +170,7 @@ pub const base = struct {
pub const Datagram_Device = @import("base/Datagram_Device.zig");
pub const Stream_Device = @import("base/Stream_Device.zig");
pub const Digital_IO = @import("base/Digital_IO.zig");
pub const Clock_Device = @import("base/Clock_Device.zig");
};

test {
Expand All @@ -179,6 +182,8 @@ test {
_ = input.debounced_button;
_ = input.rotary_encoder;

_ = stepper;

_ = IO_expander.pcf8574;

_ = time;
Expand Down
Loading

0 comments on commit ceefa56

Please sign in to comment.