const std = @import("std"); const microzig = @import("microzig"); const rp2xxx = microzig.hal; const chip = rp2xxx.compatibility.chip; const interrupt = microzig.cpu.interrupt; const peripherals = microzig.chip.peripherals; const build_options = @import("build_options"); const board = @import("board.zig").boardConfig(build_options.board); const CV = @import("cv.zig").CV; const DCC = @import("dcc.zig"); const PID = @import("pid.zig"); const gpio = @import("gpio.zig"); const motor = @import("motor.zig"); const log = std.log.scoped(.RP2040); pub const microzig_options: microzig.Options = .{ .log_level = .debug, .logFn = rp2xxx.uart.log_threadsafe, .interrupts = .{ .TIMER_IRQ_0 = .{ .c = timerInterrupt }, .IO_IRQ_BANK0 = .{ .c = gpioInterrupt }, }, }; pub const pins = board.pin_conf.pins(); var dcc = DCC.Parser{}; var pid: PID = undefined; pub var cv = CV.default; pub fn main() !void { board.pin_conf.apply(); { // UART log setup if (board.uart) |uart| { uart.apply(.{ .baud_rate = 115200, .clock_config = rp2xxx.clock_config, }); rp2xxx.uart.init_logger(uart); } } rp2xxx.irq.globally_disable(); gpio.enable_interrupt(pins.ddc, .{ .io_bank0 = .{ .proc0 = 1 } }, .{ .fall = 1, .rise = 1 }); { // PWM setup // 125MHz -> 25kHz pins.speed.slice().set_wrap(@intCast(125_000_000 / (@as(u32, cv.PWM_period) * 100 + 10_000) - 1)); pins.speed.slice().enable(); pins.speed.slice().set_phase_correct(false); pins.speed.slice().set_clk_div(1, 0); } { // ADC setup rp2xxx.adc.apply(.{ .sample_frequency = null, .round_robin = null, .temp_sensor_enabled = false, .fifo = .{ .dreq_enabled = false, .irq_enabled = false, .shift = false }, }); // apply calls enable too } rp2xxx.multicore.launch_core1(core1); // XXX: waiting for core1 should be more reliable rp2xxx.time.sleep_ms(1000); // const foo = CV.genSpeedTable(8, 60, 100); for (0..29) |i| { const val = cv.getCV(67 - 1 + @as(u8, @intCast(i))); // const val: u8 = @truncate(foo >> @truncate(i * 8)); log.debug("Step{d} expected EMF: {d}", .{ i, val }); } // try motor.tester(board.md, @intCast(125_000_000 / (@as(usize, cv.PWM_period) * 100 + 10_000))); rp2xxx.irq.globally_enable(); while (dcc.packets.readItem()) |packet| { if (packet.address == 55) { log.info("packet: {}", .{packet}); rp2xxx.multicore.fifo.write_blocking(@as(u12, @intCast(@intFromEnum(packet.speed()))) * 100); } } unreachable; // { // DDC testing // // preamble // for (0..10) |_| { // DCC.Test.sendOne(); // } // DCC.Test.sendZero(); // // 3 byte packet // DCC.Test.sendByte(0b00110111); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01110100); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendOne(); // // preamble // for (0..10) |_| { // DCC.Test.sendOne(); // } // DCC.Test.sendZero(); // // 4 byte packet // DCC.Test.sendByte(0b00110111); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01110100); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendOne(); // // preamble // for (0..10) |_| { // DCC.Test.sendOne(); // } // DCC.Test.sendZero(); // // 5 byte packet // DCC.Test.sendByte(0b00110111); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01110100); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendZero(); // DCC.Test.sendByte(0b01000011); // DCC.Test.sendOne(); // if (dcc.packets.readItem()) |packet| { // log.debug( // "packet address: {d} speed: {} instruction: {}", // .{ packet.address, packet.speed(), packet.instruction }, // ); // } // cv.validate(); // // Expected to be 8 // log.debug("vstart CV: {d}", .{cv.getCV(2 - 1)}); // dcc.listen(&cv); // rp2xxx.multicore.fifo.write_blocking(12); // rp2xxx.time.sleep_ms(5000); // rp2xxx.multicore.fifo.write_blocking(20); // rp2xxx.time.sleep_ms(5000); // } // while (true) { // microzig.cpu.wfi(); // } } fn core1() void { // initialize PID pid = PID.init(board, PID.PID_INTERRUPT_MS, 2.1, 0.03, 100); // timer interrupt for PID PID.setAlarm(PID.PID_INTERRUPT_MS); peripherals.TIMER.INTE.modify(.{ .ALARM_0 = 1 }); interrupt.set_priority(.TIMER_IRQ_0, .lowest); interrupt.enable(.TIMER_IRQ_0); while (true) { if (rp2xxx.multicore.fifo.read()) |raw_speed| { const speed: DCC.Speed = @enumFromInt(@as(u5, @truncate(raw_speed))); log.info("CPU{d}, speed: {}", .{ rp2xxx.get_cpu_id(), speed }); pid.sp = speed; } } } fn timerInterrupt() callconv(.c) void { // const cs = microzig.interrupt.enter_critical_section(); // defer cs.leave(); // log.debug("CPU{d} timerInterrupt start...", .{pico.get_cpu_id()}); // acknowledge interrupt peripherals.TIMER.INTR.modify(.{ .ALARM_0 = 1 }); const input: f32 = 5; _ = pid.compute(input); // FIXME: printing float kills everything... // log.debug("SP: {} in: {d} out: {d}", .{ // pid.sp, // @as(i32, @intFromFloat(input)), // @as(i32, @intFromFloat(output)), // }); PID.setAlarm(PID.PID_INTERRUPT_MS); // log.debug("CPU{d} timerInterrupt done.", .{pico.get_cpu_id()}); } fn gpioInterrupt() callconv(.c) void { // const cs = microzig.interrupt.enter_critical_section(); // defer cs.leave(); // log.debug("CPU{d} gpioInterrupt start...", .{pico.get_cpu_id()}); // XXX: this could be const without the testing code... var state = peripherals.IO_BANK0.PROC0_INTS1.read(); { // Handle forced state - only for testing purposes 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 }); // log.debug( // "CPU{d} gpioInterrupt LOW: {d} HIGH: {d}", // .{ rp2xxx.get_cpu_id(), state.GPIO15_EDGE_LOW, state.GPIO15_EDGE_HIGH }, // ); if (state.GPIO15_EDGE_HIGH == 1) { dcc.signalRising(); } else if (state.GPIO15_EDGE_LOW == 1) { dcc.signalFalling(); } // log.debug("CPU{d} gpioInterrupt stop.", .{pico.get_cpu_id()}); }