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>
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 driverports/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