RIKRRTK5ZNVTCDJBS2O54P36TSQXENEZ2DYXJ3WPFW7ZQ6CF4DMQC
const std = @import("std");
const microzig = @import("microzig");
const pico = microzig.hal;
const peripherals = microzig.chip.peripherals;
// XXX: hardcoded!
pub const PID_INTERRUPT_MS = 1000;
// TODO: use fixed point arithmetics here!
const VariableType = f32;
// PID State variables
var err_sum: VariableType = 0;
var err_last: VariableType = 0;
kp: VariableType,
ki: VariableType,
kd: VariableType,
// TODO: make an initWithInterrupt function to set up periodic interrupts
pub fn init(interrupt: u10, kp: VariableType, ki: VariableType, kd: VariableType) @This() {
const pid = @This(){
.kp = kp,
.ki = ki * interrupt,
.kd = kd / interrupt,
};
return pid;
}
pub fn compute(self: @This(), input: VariableType, sp: VariableType) VariableType {
// Calculate errors
const err: VariableType = sp - input;
err_sum += err;
const err_diff: VariableType = err - err_last;
// Calculate PID output
const output: VariableType = self.kp * err + self.ki * err_sum + self.kd * err_diff;
// Update state
err_last = err;
// re-enable interrupt
setAlarm(PID_INTERRUPT_MS);
return output;
}
// XXX: make this non-public!
pub fn setAlarm(ms: u32) void {
const current = pico.time.get_time_since_boot();
const target = current.add_duration(microzig.drivers.time.Duration.from_ms(ms));
peripherals.TIMER.ALARM0.write_raw(@truncate(@intFromEnum(target)));
}
fn timerInterrupt() callconv(.c) void {
const cs = microzig.interrupt.enter_critical_section();
defer cs.leave();
std.log.info("timer_interrupt called!", .{});
peripherals.TIMER.INTR.modify(.{ .ALARM_0 = 1 });
setAlarm(1_000);
}
fn gpioInterrupt() callconv(.c) void {
// const cs = microzig.interrupt.enter_critical_section();
// defer cs.leave();
// XXX: this could be const without the .Debug code...
var state = peripherals.IO_BANK0.PROC0_INTS1.read();
if (builtin.mode == .Debug) {
const fstate = peripherals.IO_BANK0.PROC0_INTF1.read();
if (fstate.GPIO15_LEVEL_LOW == 1) state.GPIO15_EDGE_LOW = 1;
if (fstate.GPIO15_LEVEL_HIGH == 1) state.GPIO15_EDGE_HIGH = 1;
// disable forcing
peripherals.IO_BANK0.PROC0_INTF1.modify(.{
.GPIO15_EDGE_HIGH = 0,
.GPIO15_EDGE_LOW = 0,
});
}
// aknowledge interrupt
peripherals.IO_BANK0.INTR1.modify(.{ .GPIO15_EDGE_LOW = 1, .GPIO15_EDGE_HIGH = 1 });
// std.log.debug("gpioInterrupt LOW: {d} HIGH: {d}", .{ state.GPIO15_EDGE_LOW, state.GPIO15_EDGE_HIGH });
if (state.GPIO15_EDGE_HIGH == 1) {
ddc.signalRising();
} else if (state.GPIO15_EDGE_LOW == 1) {
ddc.signalFalling();
}
}
fn setAlarm(ms: u32) void {
const current = pico.time.get_time_since_boot();
const target = current.add_duration(microzig.drivers.time.Duration.from_ms(ms));
// peripherals.TIMER.ALARM0.write_raw(@intCast(@intFromEnum(target) & 0xffffffff));
peripherals.TIMER.ALARM0.write_raw(@truncate(@intFromEnum(target)));
}
// TODO: could be useful for watchdog updating
// timer interrupt
// setAlarm(1_000);
// peripherals.TIMER.INTE.toggle(.{ .ALARM_0 = 1 });
// interrupt.enable(.TIMER_IRQ_0);
pico.multicore.launch_core1(core1);
while (pico.multicore.fifo.read()) |rec| {
std.log.debug("CPU FIFO: {}", .{rec});
pico.multicore.fifo.write_blocking(rec);
}
fn core1() void {
std.log.debug("core1 is up and running", .{});
// timer interrupt for PID
PID.setAlarm(PID.PID_INTERRUPT_MS);
peripherals.TIMER.INTE.toggle(.{ .ALARM_0 = 1 });
interrupt.enable(.TIMER_IRQ_0);
while (true) {
microzig.cpu.wfi();
}
}
fn timerInterrupt() callconv(.c) void {
const cs = microzig.interrupt.enter_critical_section();
defer cs.leave();
// acknowledge interrupt
peripherals.TIMER.INTR.modify(.{ .ALARM_0 = 1 });
const sp: f32 = 50;
const input: f32 = undefined;
const output = pid.compute(input, sp);
std.log.debug("SP: {d} in: {d} out: {d}", .{ sp, input, output });
}
fn gpioInterrupt() callconv(.c) void {
// const cs = microzig.interrupt.enter_critical_section();
// defer cs.leave();
// XXX: this could be const without the .Debug code...
var state = peripherals.IO_BANK0.PROC0_INTS1.read();
if (builtin.mode == .Debug) {
const fstate = peripherals.IO_BANK0.PROC0_INTF1.read();
if (fstate.GPIO15_LEVEL_LOW == 1) state.GPIO15_EDGE_LOW = 1;
if (fstate.GPIO15_LEVEL_HIGH == 1) state.GPIO15_EDGE_HIGH = 1;
// disable forcing
peripherals.IO_BANK0.PROC0_INTF1.modify(.{
.GPIO15_EDGE_HIGH = 0,
.GPIO15_EDGE_LOW = 0,
});
}
// aknowledge interrupt
peripherals.IO_BANK0.INTR1.modify(.{ .GPIO15_EDGE_LOW = 1, .GPIO15_EDGE_HIGH = 1 });
// std.log.debug("gpioInterrupt LOW: {d} HIGH: {d}", .{ state.GPIO15_EDGE_LOW, state.GPIO15_EDGE_HIGH });
if (state.GPIO15_EDGE_HIGH == 1) {
ddc.signalRising();
} else if (state.GPIO15_EDGE_LOW == 1) {
ddc.signalFalling();
}
}