Files
Yukihiro "Matz" Matsumoto 3e2ce88eab hw-spi: wrap splat-bearing method signatures as code in README
After f91936b06e kept the splat notation unescaped, prettier
kept flagging the standalone `*` in the SPI#write / SPI#transfer
headings every CI run.  Wrap the two signatures in backticks so
prettier treats them as inline code (which they are), and the
`*data` form stays unescaped without further conflict.  Same
convention is already used in mruby-kernel-ext/README.md
(e.g. `### \`fail(*args)\``).

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-20 08:35:22 +09:00
..

hw-spi - SPI peripheral interface for mruby

This gem provides the SPI class for Serial Peripheral Interface communication from mruby. It is designed for embedded platforms such as ESP32 and RP2040.

Architecture

Platform-specific HAL implementations are in ports/ directories:

  • ports/esp32/ - ESP32 using ESP-IDF SPI master driver
  • ports/rp2040/ - RP2040 using Pico SDK

The build system automatically compiles matching port sources based on conf.ports setting.

Build Configuration

MRuby::CrossBuild.new('esp32') do |conf|
  conf.ports :esp32
  conf.gem core: 'hw-spi'
end

Ruby API

SPI.new

spi = SPI.new(
  unit:      :RP2040_SPI0,     # SPI unit name (required)
  frequency: 100_000,          # clock frequency in Hz (default: 100kHz)
  sck_pin:   -1,               # SCK GPIO pin (default: platform default)
  copi_pin:  -1,               # COPI/MOSI GPIO pin
  cipo_pin:  -1,               # CIPO/MISO GPIO pin
  cs_pin:    -1,               # CS GPIO pin (-1 for manual control)
  mode:      0,                # SPI mode 0-3 (default: 0)
  first_bit: SPI::MSB_FIRST    # bit order (default: MSB_FIRST)
)

Unit Names

Platform Available Units
ESP32 :ESP32_SPI2_HOST, :ESP32_HSPI_HOST,
:ESP32_SPI3_HOST*, :ESP32_VSPI_HOST*
RP2040 :RP2040_SPI0, :RP2040_SPI1

*SPI3 availability depends on ESP32 variant.

SPI#write(*data)

Write data to the SPI bus. Data can be Integer, Array, or String.

spi.write(0x01, [0x02, 0x03])

SPI#read(len, tx_value = 0)

Read len bytes. Optionally specify the value to transmit during read.

data = spi.read(4)         # transmits 0x00 while reading
data = spi.read(4, 0xFF)   # transmits 0xFF while reading

SPI#transfer(*data, additional_read_bytes: 0)

Full-duplex transfer. Sends data and returns received bytes. Use additional_read_bytes: to append zero-filled read bytes.

# Send 1 byte command, read 4 bytes response
rx = spi.transfer(0x9F, additional_read_bytes: 4)

SPI#select / SPI#deselect

Manually control the CS pin (when using GPIO-based chip select).

spi.select do |s|
  s.write(0x01)
  data = s.read(4)
end  # CS automatically deasserted

HAL Interface

To add support for a new platform, create a ports/<name>/ directory and implement the following C functions declared in <mruby/spi.h>:

int mrb_spi_unit_name_to_num(const char *name);
mrb_spi_status mrb_spi_init(mrb_spi_info *info);
int mrb_spi_read(mrb_spi_info *info, uint8_t *dst, size_t len,
                 uint8_t tx_val);
int mrb_spi_write(mrb_spi_info *info, const uint8_t *src, size_t len);
int mrb_spi_transfer(mrb_spi_info *info, const uint8_t *tx,
                     uint8_t *rx, size_t len);

The mrb_spi_info struct contains all configuration (unit, pins, frequency, mode, bit order) and is passed to every HAL call.

License

MIT