Skip to content

Commit fc4b37e

Browse files
committed
add async dma
1 parent 772a9ff commit fc4b37e

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

core/src/core/Io.zig

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@ fn to_stack_units(size: usize) usize {
2626
/// Downside: Performance (may be mitigated once https://github.com/ziglang/zig/issues/23367 is implemeted).
2727
pub const PauseReason = union(enum) {
2828
const OnStack = [to_stack_units(@sizeOf(@This()))]StackUint;
29+
const PtrMask = struct { ptr: *const usize, mask: usize };
2930

3031
/// Task volutarily gave up execution, but is ready to continue.
3132
yield,
3233
sleep_until: time.Absolute align(@alignOf(StackUint)),
33-
bits_mask_any_high: struct { ptr: *const usize, mask: usize },
34+
bits_mask_all_low: PtrMask,
35+
bits_mask_any_high: PtrMask,
3436
/// This value means there is no context stored on this stack
3537
/// so it can be used to launch a new task.
3638
no_task,
@@ -48,6 +50,9 @@ pub const PauseReason = union(enum) {
4850
.bits_mask_any_high => |info| {
4951
return @atomicLoad(usize, info.ptr, .acquire) & info.mask != 0;
5052
},
53+
.bits_mask_all_low => |info| {
54+
return @atomicLoad(usize, info.ptr, .acquire) & info.mask == 0;
55+
},
5156
.sleep_until => |t| t.is_reached_by(io.monotonic_clock()),
5257
};
5358
}
@@ -303,11 +308,24 @@ pub const RoundRobin = struct {
303308
pub fn monotonic_clock(this: *@This()) time.Absolute {
304309
return this.vtable.monotonic_clock();
305310
}
311+
312+
/// Perform memcpy with DMA. `dst` and `src` must have the same length.
313+
pub fn dma_memcpy(this: *@This(), T: type, dst: []T, src: []const T) !DmaResult {
314+
assert(dst.len == src.len);
315+
return this.vtable.dma_memcpy(dst.ptr, src.ptr, dst.len * @sizeOf(T));
316+
}
317+
};
318+
319+
/// TODO: I hate this
320+
pub const DmaResult = struct {
321+
await: *const fn (*@This(), *RoundRobin) void,
322+
channel: u32,
306323
};
307324

308325
/// Common functionality between all implementations.
309326
/// Needs to be specified by every port.
310327
pub const VTable = struct {
311328
/// A clock source that only ever goes up, not synchronized with epoch.
312329
monotonic_clock: *const fn () time.Absolute,
330+
dma_memcpy: *const fn (*anyopaque, *const anyopaque, usize) anyerror!DmaResult,
313331
};

examples/raspberrypi/rp2xxx/src/async_blinky.zig

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,18 @@ pub fn main() !void {
4949
io.async(task_blink, .{ &io, 24_000 });
5050
io.async(task_blink, .{ &io, 25_000 });
5151

52+
// DMA demo: using large arrays to prove waiting for transfer completion works.
53+
const src: [1 << 15]u32 = @splat(1);
54+
var dst: [1 << 15]u32 = @splat(0);
55+
std.log.info("Before DMA: {any}", .{dst[dst.len - 16 ..]});
56+
var future_dma = try io.dma_memcpy(u32, &dst, &src);
57+
future_dma.await(&future_dma, &io);
58+
std.log.info("After DMA: {any}", .{dst[dst.len - 16 ..]});
59+
5260
var deadline: time.Absolute = io.monotonic_clock();
5361
var cnt: u32 = 0;
5462
while (true) {
55-
try uart.writer().print("Hello! {}\r\n", .{cnt});
63+
std.log.info("Hello! {}\r\n", .{cnt});
5664
cnt += 1;
5765
deadline = deadline.add_duration(.from_ms(1000));
5866
io.pause(&.{ .sleep_until = deadline });

port/raspberrypi/rp2xxx/src/hal.zig

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@ pub const dma = @import("hal/dma.zig");
1919
pub const drivers = @import("hal/drivers.zig");
2020
pub const flash = @import("hal/flash.zig");
2121
pub const gpio = @import("hal/gpio.zig");
22-
pub const Io = struct {
23-
pub const vtable: microzig.core.Io.VTable = .{
24-
.monotonic_clock = time.get_time_since_boot,
25-
};
26-
};
22+
pub const Io = @import("hal/Io.zig");
2723
pub const multicore = @import("hal/multicore.zig");
2824
pub const mutex = @import("hal/mutex.zig");
2925
pub const pins = @import("hal/pins.zig");
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const std = @import("std");
2+
const microzig = @import("microzig");
3+
const rp2xxx = @import("../hal.zig");
4+
const Io = microzig.core.Io;
5+
6+
/// See Io.VTable for function descriptions.
7+
pub const vtable: Io.VTable = .{
8+
.monotonic_clock = rp2xxx.time.get_time_since_boot,
9+
.dma_memcpy = dma_memcpy,
10+
};
11+
12+
pub fn dma_memcpy(dst: *anyopaque, src: *const anyopaque, size: usize) !Io.DmaResult {
13+
const channel = rp2xxx.dma.claim_unused_channel().?;
14+
try channel.setup_transfer(
15+
@as([*]u8, @ptrCast(dst))[0..size],
16+
@as([*]const u8, @ptrCast(src))[0..size],
17+
.{ .trigger = true, .enable = true },
18+
);
19+
return .{
20+
.await = &dma_await,
21+
.channel = @intFromEnum(channel),
22+
};
23+
}
24+
25+
pub fn dma_await(result: *Io.DmaResult, io: *Io.RoundRobin) void {
26+
const channel = rp2xxx.dma.channel(@intCast(result.channel));
27+
const ctrl = &channel.get_regs().ctrl_trig;
28+
var mask: @TypeOf(ctrl.*).underlying_type = @bitCast(@as(u32, 0));
29+
mask.BUSY = 1;
30+
io.pause(&.{ .bits_mask_all_low = .{ .ptr = @ptrCast(@volatileCast(ctrl)), .mask = @bitCast(mask) } });
31+
}

port/raspberrypi/rp2xxx/src/hal/dma.zig

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,16 @@ pub const Channel = enum(u4) {
183183
inline fn get_addr(value: anytype) u32 {
184184
const Type = @TypeOf(value);
185185
const Info = @typeInfo(Type);
186-
switch (Info) {
186+
return switch (Info) {
187187
.@"struct" => {
188-
return value.addr;
188+
value.addr;
189189
},
190-
.pointer => {
191-
return @intFromPtr(value);
190+
.pointer => |ptr| switch (ptr.size) {
191+
.one, .c, .many => @intFromPtr(value),
192+
.slice => @intFromPtr(value.ptr),
192193
},
193194
else => comptime unreachable,
194-
}
195+
};
195196
}
196197

197198
inline fn get_dreq(value: anytype) Dreq {

0 commit comments

Comments
 (0)