From 91e192b8fb2bfca32b7bc346895dba6ce24f69d1 Mon Sep 17 00:00:00 2001 From: TunayAdaKaracan Date: Thu, 23 Jul 2026 17:17:47 +0200 Subject: [PATCH] feat(clock): add clock and start on uart --- src/hal/clocks.zig | 12 ++++ src/hal/hal.zig | 2 + src/hal/peripherals/uart.zig | 42 ++++++++++++- src/hal/resets.zig | 55 +++++++++++++++++ src/startup.zig | 113 ++++++++++++++++++++++++++++++++--- 5 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 src/hal/clocks.zig create mode 100644 src/hal/resets.zig diff --git a/src/hal/clocks.zig b/src/hal/clocks.zig new file mode 100644 index 0000000..6454b7f --- /dev/null +++ b/src/hal/clocks.zig @@ -0,0 +1,12 @@ +pub const ClockSource = enum(u8) { + GPOUT0 = 0, + GPOUT1 = 1, + GPOUT2 = 2, + GPOUT3 = 3, + REF = 4, + SYS = 5, + PERI = 6, + HSTX = 7, + USB = 8, + ADC = 9, +}; diff --git a/src/hal/hal.zig b/src/hal/hal.zig index b3dd26f..0fb5272 100644 --- a/src/hal/hal.zig +++ b/src/hal/hal.zig @@ -1,4 +1,6 @@ pub const registers = @import("registers.zig"); +pub const resets = @import("resets.zig"); +pub const uart = @import("peripherals/uart.zig"); // NOTE: Not really happy with this pub const mmio = struct { diff --git a/src/hal/peripherals/uart.zig b/src/hal/peripherals/uart.zig index 4e573aa..6f6032f 100644 --- a/src/hal/peripherals/uart.zig +++ b/src/hal/peripherals/uart.zig @@ -1 +1,41 @@ -// TODO: UART +const hal = @import("../hal.zig"); + +pub const Uart = enum(u1) { + UART0, + UART1, + + pub fn addr(self: Uart) u32 { + return switch (self) { + .UART0 => hal.registers.UART0_BASE, + .UART1 => hal.registers.UART1_BASE, + }; + } +}; + +pub fn init(uart: Uart, clk_peri_freq: u32, baudrate: u32) void { + hal.resets.unreset(.UART0); + + const divisor: f32 = @as(f32, @floatFromInt(clk_peri_freq)) / (16 * @as(f32, @floatFromInt(baudrate))); + const divisor_int: u32 = @intFromFloat(@floor(divisor)); + const divisor_frac: u32 = @intFromFloat(@round((divisor - @as(f32, @floatFromInt(divisor_int))) * 64 + 0.5)); + + hal.mmio.write(uart.addr() + hal.registers.UART_UARTIBRD, divisor_int); + hal.mmio.write(uart.addr() + hal.registers.UART_UARTFBRD, divisor_frac); + hal.mmio.write(uart.addr() + hal.registers.UART_UARTLCR_H, 0b111 << 4); + hal.mmio.write_set(uart.addr() + hal.registers.UART_UARTCR, 0b110000001); + + hal.mmio.write(hal.registers.GPIO_CTRL + (0 * 8), 0x2); // TX + hal.mmio.write(hal.registers.GPIO_CTRL + (1 * 8), 0x2); // RX + + hal.mmio.write_clr(hal.registers.PADS_BANK0_GPIO + (0 * 4), 1 << 8); + hal.mmio.write_xor(hal.registers.PADS_BANK0_GPIO + (1 * 4), 0b101 << 6); +} + +pub fn write(uart: Uart, text: []const u8) void { + for (text) |c| { + while (hal.mmio.read(uart.addr() + hal.registers.UART_UARTFR) & (1 << 5) == 1) { + asm volatile ("add zero, zero, zero"); + } + hal.mmio.write(uart.addr() + hal.registers.UART_UARTDR, c); + } +} diff --git a/src/hal/resets.zig b/src/hal/resets.zig new file mode 100644 index 0000000..381e4a0 --- /dev/null +++ b/src/hal/resets.zig @@ -0,0 +1,55 @@ +const hal = @import("hal.zig"); + +pub const Subsystems = enum { + ADC, + BUSCTRL, + DMA, + HSTX, + I2C0, + I2C1, + IO_BANK0, + IO_QSPI, + JTAG, + PADS_BANK0, + PADS_QSPI, + PIO0, + PIO1, + PIO2, + PLL_SYS, + PLL_USB, + PWM, + SHA256, + SPI0, + SPI1, + SYSCFG, + SYSINFO, + TBMAN, + TIMER0, + TIMER1, + TRNG, + UART0, + UART1, + USBCTRL, + + pub fn value(self: Subsystems) u32 { + return @as(u32, 1) << @intFromEnum(self); + } +}; + +pub inline fn unreset(subsystem: Subsystems) void { + hal.mmio.write_clr(hal.registers.RESETS_RESET, subsystem.value()); +} + +pub inline fn reset(subsystem: Subsystems) void { + hal.mmio.write_set(hal.registers.RESETS_RESET, subsystem.value()); +} + +// FIXME: For some reason, can't do a full uart reset, stuck on waiting for reset_done +pub inline fn restart(subsystem: Subsystems) void { + reset(subsystem); + unreset(subsystem); + + while (hal.mmio.read(hal.registers.RESETS_RESET_DONE) & subsystem.value() == 0) { + asm volatile ("add zero, zero, zero"); + } +} diff --git a/src/startup.zig b/src/startup.zig index d1f4400..cf44b18 100644 --- a/src/startup.zig +++ b/src/startup.zig @@ -2,6 +2,101 @@ const hal = @import("hal"); const LED_PIN: u32 = 25; +// ceil((freq x time) % 256) +// 1 ms is sufficient +// ceil((12 * 10^6 x 1 * 10^-3) % 256) = 47 +const XOSC_STARTUP = 47; + +fn flash_led(comptime max_delay: u32, comptime inf: bool) void { + if (!inf) { + var times: u8 = 0; + while (times < 10) : (times += 1) { + hal.mmio.write(hal.registers.SIO_GPIO_OUT_XOR, 1 << LED_PIN); + + var delay: u32 = 0; + while (delay < max_delay) : (delay += 1) { + asm volatile ("add zero, zero, zero"); + } + } + } else { + while (true) { + hal.mmio.write(hal.registers.SIO_GPIO_OUT_XOR, 1 << LED_PIN); + + var delay: u32 = 0; + while (delay < max_delay) : (delay += 1) { + asm volatile ("add zero, zero, zero"); + } + } + } +} + +fn xosc_init() void { + // Set the freq to 1-15MHz, 47 startup timer + hal.mmio.write(hal.registers.XOSC_STARTUP, XOSC_STARTUP); + hal.mmio.write(hal.registers.XOSC_CTRL, 0xfabaa0); + + // TODO: Replace dummy wait + while (hal.mmio.read(hal.registers.XOSC_STATUS) & 0x80000000 == 0) { + asm volatile ("add zero, zero, zero"); + } +} + +fn pll_sys_init() void { + // Target: 150 MHz + // FREF = 12 MHz + // REFDIV = 1 + // FBDIV = 125 + // POSTDIV1 = 5 + // POSTDIV2 = 2 + // (FREF / REFDIV) * FBDIV / POSTDIV1 / POSTDIV2 + + // Reset sys PLL + // TODO: Check configuration of the PLL before resetting + hal.mmio.write_set(hal.registers.RESETS_BASE, 1 << 14); + hal.mmio.write_clr(hal.registers.RESETS_BASE, 1 << 14); + + while (hal.mmio.read(hal.registers.RESETS_RESET_DONE) & 0x4000 == 0) { + asm volatile ("add zero, zero, zero"); + } + + // Configure the PLL FBDIV and POSTDIVs (REFDIV reset is already 1) + hal.mmio.write(hal.registers.PLL_SYS_FBDIV_INT, 125); + hal.mmio.write(hal.registers.PLL_SYS_PRIM, (5 << 16) | (2 << 12)); + + // PD and VCO power enabled + hal.mmio.write_clr(hal.registers.PLL_SYS_PWR, (1 << 5) | (1 << 0)); + while (hal.mmio.read(hal.registers.PLL_SYS_CS) & 0x80000000 == 0) { + asm volatile ("add zero, zero, zero"); + } + + // Power up POSTDIVs + hal.mmio.write_clr(hal.registers.PLL_SYS_PWR, 1 << 3); +} + +fn switch_clk_ref() void { + // Use XOSC for CLK_REF + hal.mmio.write(hal.registers.CLOCKS_CLK_REF_CTRL, 0x2); + + // Wait until select has happened + while (hal.mmio.read(hal.registers.CLOCKS_CLK_REF_SELECTED) != 0b0100) { + asm volatile ("add zero, zero, zero"); + } +} + +fn switch_clk_sys() void { + hal.mmio.write_clr(hal.registers.CLOCKS_CLK_SYS_CTRL, 1); + while (hal.mmio.read(hal.registers.CLOCKS_CLK_SYS_SELECTED) != 0b01) { + asm volatile ("add zero, zero, zero"); + } + + hal.mmio.write_clr(hal.registers.CLOCKS_CLK_SYS_CTRL, (1 << 6)); + + hal.mmio.write_set(hal.registers.CLOCKS_CLK_SYS_CTRL, 1); + while (hal.mmio.read(hal.registers.CLOCKS_CLK_SYS_SELECTED) != 0b10) { + asm volatile ("add zero, zero, zero"); + } +} + export fn _main() void { // Set GPIO function to 5, 5 = SIO hal.mmio.write(hal.registers.GPIO_CTRL + (LED_PIN * 8), 5); @@ -12,14 +107,16 @@ export fn _main() void { // Set output enable for the led pin hal.mmio.write_set(hal.registers.SIO_GPIO_OE_SET, 1 << LED_PIN); - while (true) { - hal.mmio.write(hal.registers.SIO_GPIO_OUT_XOR, 1 << LED_PIN); + flash_led(1_000_000, false); - var delay: u32 = 0; - while (delay < 1_000_000) : (delay += 1) { - asm volatile ("add zero, zero, zero"); - } - } + xosc_init(); + switch_clk_ref(); + pll_sys_init(); + switch_clk_sys(); + + // FIXME: Seems to not work? + hal.uart.init(.UART0, 12_000_000, 115200); + hal.uart.write(.UART0, "Hello!\n"); - // TODO: Clocks setup to run the RP2350 at nominal speed of 150MHz + flash_led(1_000_000, true); } -- 2.51.2