const std = @import("std");
const pico = @import("microzig").hal;
const FULL_AXIS = 4096; // u12
const QUARTER = FULL_AXIS / 4;
const pin_conf = pico.pins.GlobalConfiguration{
.GPIO22 = .{ .name = "neopixel", .function = .PIO0 },
.GPIO26 = .{ .name = "xaxis", .function = .ADC0 },
.GPIO27 = .{ .name = "yaxis", .function = .ADC1 },
.GPIO28 = .{ .name = "button", .direction = .in, .pull = .up },
};
const pins = pin_conf.pins();
const pio: pico.pio.Pio = .pio0;
const sm: pico.pio.StateMachine = .sm0;
const led_pin = pico.gpio.num(22);
pub fn main() !void {
pin_conf.apply();
pio.gpio_init(led_pin);
pio.sm_set_pindir(sm, @intFromEnum(led_pin), 1, .out);
const cycles_per_bit: comptime_int = ws2812_program.defines[0].value + //T1
ws2812_program.defines[1].value + //T2
ws2812_program.defines[2].value; //T3
const div = @as(f32, @floatFromInt(pico.clock_config.sys.?.frequency())) /
(800_000 * cycles_per_bit);
pio.sm_load_and_start_program(sm, ws2812_program, .{
.clkdiv = pico.pio.ClkDivOptions.from_float(div),
.pin_mappings = .{
.side_set = .{
.base = @intFromEnum(led_pin),
.count = 1,
},
},
.shift = .{
.out_shiftdir = .left,
.autopull = true,
.pull_threshold = 24,
.join_tx = true,
},
}) catch unreachable;
pio.sm_set_enabled(sm, true);
// ACTUAL LOGIC
const Colors = enum(u32) {
red = 0x00ff0000,
green = 0xff000000,
blue = 0x0000ff00,
white = 0xffffff00,
};
var color: Colors = .white;
while (true) {
// reading inputs
if (pins.button.read() == 0) {
pico.time.sleep_ms(20);
if (pins.button.read() == 0) {
color = switch (color) {
.white => .red,
.red => .green,
.green => .blue,
.blue => .white,
};
while (pins.button.read() == 0) {
asm volatile ("" ::: "memory");
}
}
}
const x = pico.adc.convert_one_shot_blocking(pins.xaxis) catch 0;
// const y = pico.adc.convert_one_shot_blocking(pins.yaxos) catch 0;
// writing outputs
// TODO: this is unfinished
switch (x) {
0...QUARTER - 1 => {
pio.sm_blocking_write(sm, @intFromEnum(color));
},
QUARTER...2 * QUARTER - 1 => {
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, @intFromEnum(color));
},
2 * QUARTER...3 * QUARTER - 1 => {
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, @intFromEnum(color));
},
else => {
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, 0x00000000);
pio.sm_blocking_write(sm, @intFromEnum(color));
},
}
pico.time.sleep_ms(100);
}
}
const ws2812_program = blk: {
@setEvalBranchQuota(10_000);
break :blk pico.pio.assemble(
\\;
\\; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
\\;
\\; SPDX-License-Identifier: BSD-3-Clause
\\;
\\.program ws2812
\\.side_set 1
\\
\\.define public T1 2
\\.define public T2 5
\\.define public T3 3
\\
\\.wrap_target
\\bitloop:
\\ out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls
\\ jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse
\\do_one:
\\ jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse
\\do_zero:
\\ nop side 0 [T2 - 1] ; Or drive low, for a short pulse
\\.wrap
, .{}).get_program_by_name("ws2812");
};