Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rp2040: Add spi slave example #391

Merged
merged 10 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/raspberrypi/rp2xxx/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ pub fn build(b: *std.Build) void {
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_pwm", .file = "src/rp2040_only/pwm.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_random", .file = "src/rp2040_only/random.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_rtc", .file = "src/rp2040_only/rtc.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_spi-host", .file = "src/rp2040_only/spi_host.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_uart-echo", .file = "src/rp2040_only/uart_echo.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_uart-log", .file = "src/rp2040_only/uart_log.zig" },
.{ .target = mb.ports.rp2xxx.boards.raspberrypi.pico, .name = "pico_usb-hid", .file = "src/rp2040_only/usb_hid.zig" },
Expand All @@ -40,6 +39,8 @@ pub fn build(b: *std.Build) void {
};

const chip_agnostic_examples: []const ChipAgnosticExample = &.{
.{ .name = "spi-master", .file = "src/spi_master.zig" },
.{ .name = "spi-slave", .file = "src/spi_slave.zig" },
.{ .name = "squarewave", .file = "src/squarewave.zig" },
.{ .name = "ws2812", .file = "src/ws2812.zig" },
.{ .name = "blinky", .file = "src/blinky.zig" },
Expand Down
67 changes: 0 additions & 67 deletions examples/raspberrypi/rp2xxx/src/rp2040_only/spi_host.zig

This file was deleted.

37 changes: 37 additions & 0 deletions examples/raspberrypi/rp2xxx/src/spi_master.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const std = @import("std");
const microzig = @import("microzig");

const rp2xxx = microzig.hal;
const time = rp2xxx.time;
const gpio = rp2xxx.gpio;

const BUF_LEN = 0x100;
const spi = rp2xxx.spi.instance.SPI0;

// These may change depending on which GPIO pins you have your SPI device routed to.
const CS_PIN = 17;
const SCK_PIN = 18;
// NOTE: rp2xxx doesn't label pins as MOSI/MISO. Instead a pin is always for
// either receiving or transmitting SPI data, no matter whether the chip is in
// master or slave mode.
const TX_PIN = 19;

// Communicate with another RP2040 over spi
pub fn main() !void {
// Set pin functions for CS, SCK, RX
const csn = rp2xxx.gpio.num(CS_PIN);
const mosi = rp2xxx.gpio.num(TX_PIN);
const sck = rp2xxx.gpio.num(SCK_PIN);
inline for (&.{ csn, mosi, sck }) |pin| {
pin.set_function(.spi);
}

try spi.apply(.{ .clock_config = rp2xxx.clock_config });
var out_buf: [BUF_LEN]u8 = .{ 'h', 'e', 'y', ' ', 'y', 'o', 'u', '!' } ** (BUF_LEN / 8);

while (true) {
std.log.info("Sending some data\n", .{});
spi.write_blocking(u8, &out_buf);
time.sleep_ms(1 * 1000);
}
}
62 changes: 62 additions & 0 deletions examples/raspberrypi/rp2xxx/src/spi_slave.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const std = @import("std");
const microzig = @import("microzig");

const rp2xxx = microzig.hal;
const time = rp2xxx.time;
const gpio = rp2xxx.gpio;
const chip = rp2xxx.compatibility.chip;

const BUF_LEN = 0x100;
const spi = rp2xxx.spi.instance.SPI0;

const uart = rp2xxx.uart.instance.num(0);
const uart_baud_rate = 115200;
const uart_tx_pin = gpio.num(0);

// These may change depending on which GPIO pins you have your SPI device routed to.
const CS_PIN = 17;
const SCK_PIN = 18;
// NOTE: rp2xxx doesn't label pins as MOSI/MISO. Instead a pin is always for
// either receiving or transmitting SPI data, no matter whether the chip is in
// master or slave mode.
const RX_PIN = 16;

pub const microzig_options = .{
.log_level = .debug,
.logFn = rp2xxx.uart.logFn,
};

pub fn main() !void {
// Set pin functions for CS, SCK, RX
const csn = gpio.num(CS_PIN);
const mosi = gpio.num(RX_PIN);
const sck = gpio.num(SCK_PIN);
inline for (&.{ csn, mosi, sck }) |pin| {
pin.set_function(.spi);
}

switch (chip) {
.RP2040 => uart_tx_pin.set_function(.uart),
.RP2350 => uart_tx_pin.set_function(.uart_first),
}
uart.apply(.{
.baud_rate = uart_baud_rate,
.clock_config = rp2xxx.clock_config,
});

rp2xxx.uart.init_logger(uart);

std.log.info("Setting SPI as slave device", .{});
spi.set_slave(true);

try spi.apply(.{ .clock_config = rp2xxx.clock_config });
var in_buf: [BUF_LEN]u8 = undefined;

std.log.info("Reading", .{});

while (true) {
spi.read_blocking(u8, 0, &in_buf);
std.log.info("Got: {s}", .{in_buf});
time.sleep_ms(1 * 1000);
}
}
14 changes: 12 additions & 2 deletions port/raspberrypi/rp2xxx/src/hal/spi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const peripherals = microzig.chip.peripherals;
const SPI0_reg = peripherals.SPI0;
const SPI1_reg = peripherals.SPI1;

const gpio = @import("gpio.zig");
const clocks = @import("clocks.zig");
const resets = @import("resets.zig");
const time = @import("time.zig");
Expand Down Expand Up @@ -162,6 +161,17 @@ pub const SPI = enum(u1) {
spi_regs.SSPCPSR.modify(.{ .CPSDVSR = 0 });
}

pub fn set_slave(spi: SPI, slave: bool) void {
const regs = spi.get_regs();
// Disable SPI
regs.SSPCR1.modify(.{ .SSE = 0 });

regs.SSPCR1.modify(.{ .MS = @intFromBool(slave) });

// Re-enable SPI
regs.SSPCR1.modify(.{ .SSE = 1 });
}

pub inline fn is_writable(spi: SPI) bool {
return spi.get_regs().SSPSR.read().TNF == 1;
}
Expand Down Expand Up @@ -336,7 +346,7 @@ pub const SPI = enum(u1) {
/// be 0, but some devices require a specific value here,
/// e.g. SD cards expect 0xff
///
/// NOTE: This function is a vectored version of `write_blocking` and takes an array of arrays.
/// NOTE: This function is a vectored version of `read_blocking` and takes an array of arrays.
/// This pattern allows one to create better zero-copy send routines as message prefixes and
/// suffixes won't need to be concatenated/inserted to the original buffer, but can be managed
/// in a separate memory.
Expand Down
Loading