diff --git a/core/src/cpus/cortex_m.zig b/core/src/cpus/cortex_m.zig index 441e304e5..f06918499 100644 --- a/core/src/cpus/cortex_m.zig +++ b/core/src/cpus/cortex_m.zig @@ -652,7 +652,9 @@ pub const startup_logic = struct { @memcpy(ram_vectors[0..vector_count], flash_vector[0..vector_count]); - peripherals.scb.VTOR = @intFromPtr(&ram_vectors); + const vtor_addr: u32 = @intFromPtr(&ram_vectors); + std.debug.assert(std.mem.isAligned(vtor_addr, 256)); + peripherals.scb.VTOR = vtor_addr; } } @@ -662,7 +664,8 @@ pub const startup_logic = struct { const VectorTable = microzig.chip.VectorTable; // will be imported by microzig.zig to allow system startup. - pub const _vector_table: VectorTable = blk: { + // must be aligned to 256 as VTOR ignores the lower 8 bits of the address. + pub const _vector_table: VectorTable align(256) = blk: { var tmp: VectorTable = .{ .initial_stack_pointer = microzig.config.end_of_stack, .Reset = .{ .c = microzig.cpu.startup_logic._start }, diff --git a/examples/raspberrypi/rp2xxx/src/i2c_bus_scan.zig b/examples/raspberrypi/rp2xxx/src/i2c_bus_scan.zig index b95f9c02f..f662f20fb 100644 --- a/examples/raspberrypi/rp2xxx/src/i2c_bus_scan.zig +++ b/examples/raspberrypi/rp2xxx/src/i2c_bus_scan.zig @@ -35,7 +35,7 @@ pub fn main() !void { pin.set_function(.i2c); } - try i2c0.apply(.{ + i2c0.apply(.{ .clock_config = rp2xxx.clock_config, }); diff --git a/examples/raspberrypi/rp2xxx/src/mlx90640.zig b/examples/raspberrypi/rp2xxx/src/mlx90640.zig index 5250642ec..739133d4f 100644 --- a/examples/raspberrypi/rp2xxx/src/mlx90640.zig +++ b/examples/raspberrypi/rp2xxx/src/mlx90640.zig @@ -76,7 +76,7 @@ fn init() !void { .clock_config = rpxxxx.clock_config, }); - try i2c0.apply(i2c.Config{ .clock_config = rpxxxx.clock_config }); + i2c0.apply(i2c.Config{ .clock_config = rpxxxx.clock_config }); rpxxxx.uart.init_logger(uart); pin_config.apply(); diff --git a/examples/raspberrypi/rp2xxx/src/rp2040_only/hd44780.zig b/examples/raspberrypi/rp2xxx/src/rp2040_only/hd44780.zig index 3f640aa5b..85bad28fb 100644 --- a/examples/raspberrypi/rp2xxx/src/rp2040_only/hd44780.zig +++ b/examples/raspberrypi/rp2xxx/src/rp2040_only/hd44780.zig @@ -31,7 +31,7 @@ pub fn main() !void { pin.set_function(.i2c); } - try i2c0.apply(.{ + i2c0.apply(.{ .clock_config = rp2040.clock_config, }); var expander = PCF8574(.{ .Datagram_Device = I2C_Device }).init(i2c_device); diff --git a/examples/raspberrypi/rp2xxx/src/rp2040_only/pcf8574.zig b/examples/raspberrypi/rp2xxx/src/rp2040_only/pcf8574.zig index 4d642d145..44bd87d18 100644 --- a/examples/raspberrypi/rp2xxx/src/rp2040_only/pcf8574.zig +++ b/examples/raspberrypi/rp2xxx/src/rp2040_only/pcf8574.zig @@ -23,7 +23,7 @@ pub fn main() !void { pin.set_function(.i2c); } - try i2c0.apply(.{ + i2c0.apply(.{ .clock_config = rp2040.clock_config, }); var expander = PCF8574(.{ .Datagram_Device = I2C_Device }).init(i2c_device); diff --git a/port/raspberrypi/rp2xxx/src/hal/dma.zig b/port/raspberrypi/rp2xxx/src/hal/dma.zig index 6ca75ff80..37b60c0f1 100644 --- a/port/raspberrypi/rp2xxx/src/hal/dma.zig +++ b/port/raspberrypi/rp2xxx/src/hal/dma.zig @@ -100,7 +100,7 @@ pub const Channel = enum(u4) { al3_read_addr_trig: u32, }; - fn get_regs(chan: Channel) *volatile Regs { + pub inline fn get_regs(chan: Channel) *volatile Regs { const regs = @as(*volatile [num_channels]Regs, @ptrCast(&DMA.CH0_READ_ADDR)); return ®s[@intFromEnum(chan)]; } diff --git a/port/raspberrypi/rp2xxx/src/hal/gpio.zig b/port/raspberrypi/rp2xxx/src/hal/gpio.zig index d9865fdae..f40e2ef6c 100644 --- a/port/raspberrypi/rp2xxx/src/hal/gpio.zig +++ b/port/raspberrypi/rp2xxx/src/hal/gpio.zig @@ -318,22 +318,22 @@ pub const Pin = enum(u6) { .RP2350 => *volatile [48]PadsReg, }; - fn get_regs(gpio: Pin) *volatile Regs { + pub inline fn get_regs(gpio: Pin) *volatile Regs { const regs = @as(RegsArray, @ptrCast(&IO_BANK0.GPIO0_STATUS)); return ®s[@intFromEnum(gpio)]; } - fn get_pads_reg(gpio: Pin) *volatile PadsReg { + pub inline fn get_pads_reg(gpio: Pin) *volatile PadsReg { const regs = @as(PadsRegArray, @ptrCast(&PADS_BANK0.GPIO0)); return ®s[@intFromEnum(gpio)]; } /// Only relevant for RP2350 which has 48 GPIOs - fn is_upper(gpio: Pin) bool { + pub inline fn is_upper(gpio: Pin) bool { return @intFromEnum(gpio) > 31; } - pub fn mask(gpio: Pin) u32 { + pub inline fn mask(gpio: Pin) u32 { const bitshift_val: u5 = switch (chip) { .RP2040 => @intCast(@intFromEnum(gpio)), .RP2350 => diff --git a/port/raspberrypi/rp2xxx/src/hal/i2c.zig b/port/raspberrypi/rp2xxx/src/hal/i2c.zig index 5f9306836..2d8b48a19 100644 --- a/port/raspberrypi/rp2xxx/src/hal/i2c.zig +++ b/port/raspberrypi/rp2xxx/src/hal/i2c.zig @@ -216,7 +216,7 @@ pub const instance = struct { pub const I2C = enum(u1) { _, - fn get_regs(i2c: I2C) *volatile I2cRegs { + pub inline fn get_regs(i2c: I2C) *volatile I2cRegs { return switch (@intFromEnum(i2c)) { 0 => I2C0, 1 => I2C1, @@ -246,7 +246,7 @@ pub const I2C = enum(u1) { /// - TX_EMPTY_CTRL is always enabled for easy detection of TX finished /// - TX and RX FIFO detection thresholds set to 1, this makes polling for TX finished/RX ready much simpler /// - DREQ signalling is always enabled, harmless if DMA isn't configured to listen for this - pub fn apply(i2c: I2C, comptime config: Config) ConfigError!void { + pub fn apply(i2c: I2C, comptime config: Config) void { i2c.disable(); const regs = i2c.get_regs(); regs.IC_CON.write(.{ @@ -273,8 +273,11 @@ pub const I2C = enum(u1) { }); const peripheral_block_freq = (comptime config.clock_config.get_frequency(.clk_sys)) orelse @compileError("clk_sys must be set for I²C"); + + const timings = comptime translate_baudrate(config.baud_rate, peripheral_block_freq) catch @compileError("baud_rate is not possible with the provided clock_config"); + // set_baudrate() enables I2C block before returning - try i2c.set_baudrate(config.baud_rate, peripheral_block_freq); + i2c.set_computed_baudrate(timings); } /// Disables I2C, returns peripheral registers to reset state. @@ -289,13 +292,23 @@ pub const I2C = enum(u1) { /// pin rise/fall time as that is board specific, so actual baud rates may be /// slightly lower than specified. pub fn set_baudrate(i2c: I2C, baud_rate: u32, freq_in: u32) ConfigError!void { - const reg_vals = try translate_baudrate(baud_rate, freq_in); + const timings = try translate_baudrate(baud_rate, freq_in); + i2c.set_computed_baudrate(timings); + } + + /// Configures I2C to run at a specified baud rate given a peripheral clock frequency. + /// + /// Validates configuration to ensure it's both within I2C spec, and the peripheral + /// block's configuration capabilities. Note that this does NOT take into account + /// pin rise/fall time as that is board specific, so actual baud rates may be + /// slightly lower than specified. + pub fn set_computed_baudrate(i2c: I2C, timings: TimingRegisterValues) void { i2c.disable(); const regs = i2c.get_regs(); - regs.IC_FS_SCL_HCNT.write(.{ .IC_FS_SCL_HCNT = reg_vals.scl_hcnt }); - regs.IC_FS_SCL_LCNT.write(.{ .IC_FS_SCL_LCNT = reg_vals.scl_lcnt }); - regs.IC_FS_SPKLEN.write(.{ .IC_FS_SPKLEN = reg_vals.spklen }); - regs.IC_SDA_HOLD.modify(.{ .IC_SDA_TX_HOLD = reg_vals.sda_tx_hold_count }); + regs.IC_FS_SCL_HCNT.write(.{ .IC_FS_SCL_HCNT = timings.scl_hcnt }); + regs.IC_FS_SCL_LCNT.write(.{ .IC_FS_SCL_LCNT = timings.scl_lcnt }); + regs.IC_FS_SPKLEN.write(.{ .IC_FS_SPKLEN = timings.spklen }); + regs.IC_SDA_HOLD.modify(.{ .IC_SDA_TX_HOLD = timings.sda_tx_hold_count }); i2c.enable(); } diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig index 0fb0c3a75..00a9226b4 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/assembler.zig @@ -72,6 +72,12 @@ pub const Diagnostics = struct { } }; +/// Creates a copy of a slice at comptime that is guaranteed to be immutable. +fn comptime_copy(comptime T: type, comptime slice: []const T) []const T { + const arr: [slice.len]T = slice[0..slice.len].*; + return &arr; +} + pub fn assemble_impl(comptime chip: Chip, comptime source: []const u8, diags: *?Diagnostics, options: AssembleOptions) !Output { const tokens = try tokenizer.tokenize(chip, source, diags, options.tokenize); const encoder_output = try encoder.encode(chip, tokens.slice(), diags, options.encode); @@ -87,9 +93,9 @@ pub fn assemble_impl(comptime chip: Chip, comptime source: []const u8, diags: *? .name = define.name, .value = define.value, }) catch unreachable; - break :blk tmp.constSlice(); + break :blk comptime_copy(Define, tmp.slice()); }, - .programs = programs.constSlice(), + .programs = comptime_copy(Program, programs.slice()), }; } diff --git a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig index 790cf45f3..28717ef11 100644 --- a/port/raspberrypi/rp2xxx/src/hal/pio/common.zig +++ b/port/raspberrypi/rp2xxx/src/hal/pio/common.zig @@ -133,8 +133,12 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { if (origin != offset) return false; + // Will never fit in the first place: + if (offset + program.instructions.len > 32) + return false; + const used_mask = UsedInstructionSpace(chip).val[@intFromEnum(self)]; - const program_mask = program.get_mask(); + const program_mask = (program.get_mask() << offset); // We can add the program if the masks don't overlap, if there is // overlap the result of a bitwise AND will have a non-zero result @@ -537,6 +541,7 @@ pub fn PioImpl(EnumType: type, chip: Chip) type { // TODO: check program settings vs pin mapping const offset = try self.add_program(program); + self.sm_init(sm, offset, .{ .clkdiv = options.clkdiv, .shift = options.shift, diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 95f416b5b..ecd79a1c7 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -153,7 +153,7 @@ pub const UART = enum(u1) { return .{ .context = uart }; } - fn get_regs(uart: UART) *volatile UartRegs { + pub inline fn get_regs(uart: UART) *volatile UartRegs { return switch (@intFromEnum(uart)) { 0 => UART0_reg, 1 => UART1_reg,