miraitowa-la/esp_spi_link

0.1.0

Latest
uploaded 1 hour ago
ESP-IDF SPI link component for short-range ESP32 master/slave board-to-board communication.

readme

# ESP-IDF SPI_Link

`esp_spi_link` is an ESP-IDF component for short-range SPI communication between
two ESP boards. It wraps the ESP-IDF SPI Master and SPI Slave drivers with a
small framed protocol, CRC validation, a READY notification GPIO, pending
responses, and a PING/PONG handshake.

The component is designed for two-board systems such as an ESP32-S3 main
controller talking to a coprocessor, sensor board, or algorithm board over SPI.

## ESP Component Registry usage

After this component is published, add it to an ESP-IDF project with:

```bash
idf.py add-dependency "miraitowa-la/esp_spi_link^0.1.0"
```

Or add it manually in the consuming project's `main/idf_component.yml`:

```yaml
dependencies:
  miraitowa-la/esp_spi_link: "^0.1.0"
```

## Files

```text
esp_spi_link/
|-- CMakeLists.txt
|-- idf_component.yml
|-- LICENSE
|-- README.md
|-- docs/
|   `-- SPI_Link说明文档.html
|-- include/
|   `-- spi_link.h
`-- src/
    `-- spi_link.c
```

## Features

- SPI Master and SPI Slave role initialization.
- Fixed wire frame with header, version, command, payload length, and CRC16.
- READY GPIO notification from Slave to Master.
- One pending Slave response that Master reads with `SPI_LINK_CMD_READ`.
- PING/PONG handshake with reset-tolerant fallback paths.
- ACK, NACK, and ERROR response commands.
- Single-instance runtime context with mutex protection and DMA-capable buffers.

## Hardware connection

Both boards must share GND. SPI is intended for short-distance links, preferably
short wires or the same PCB.

| Signal | Master | Slave | Description |
| --- | --- | --- | --- |
| SCLK | GPIO12 | GPIO12 | SPI clock generated by Master |
| MOSI | GPIO11 | GPIO11 | Master output to Slave |
| MISO | GPIO13 | GPIO13 | Slave output to Master |
| CS | GPIO10 | GPIO10 | SPI chip select |
| READY | GPIO9 input | GPIO9 output | Slave has pending response |
| GND | GND | GND | Common ground |

The GPIO numbers above are examples. Configure the actual pins through
`spi_link_config_t`.

## Wire frame

```text
| 0xAA | 0x55 | Version | CMD | LEN_H | LEN_L | Payload... | CRC_H | CRC_L |
```

CRC uses CRC-16/CCITT-FALSE and covers:

```text
Version + CMD + LEN + Payload
```

The two header bytes are synchronization markers and are not included in the CRC
scope.

## Command ranges

| Range | Usage |
| --- | --- |
| `0x01` to `0x1F` | Reserved protocol commands such as PING, PONG, and READ |
| `0x20` to `0xEF` | User-defined business commands |
| `0xF0` to `0xFF` | System responses such as ACK, NACK, and ERROR |

## Master example

```c
#include "spi_link.h"
#include "esp_log.h"

static const char *TAG = "app_master";

void app_main(void)
{
    spi_link_config_t config = {
        .mode = SPI_LINK_MODE_MASTER,
        .host = SPI2_HOST,
        .pin_mosi = 11,
        .pin_miso = 13,
        .pin_sclk = 12,
        .pin_cs = 10,
        .pin_ready = 9,
        .clock_speed_hz = SPI_LINK_DEFAULT_CLOCK_HZ,
        .queue_size = SPI_LINK_DEFAULT_QUEUE_SIZE,
        .max_transfer_size = SPI_LINK_DEFAULT_MAX_TRANS_SIZE,
    };

    ESP_ERROR_CHECK(spi_link_init(&config));

    while (spi_link_handshake(1000) != ESP_OK) {
        ESP_LOGW(TAG, "Waiting for Slave handshake...");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    uint8_t rx_buf[128] = {0};
    size_t rx_len = sizeof(rx_buf);
    esp_err_t err = spi_link_master_request(SPI_LINK_CMD_DATA,
                                            "hello",
                                            5,
                                            rx_buf,
                                            &rx_len,
                                            1000);
    if (err == ESP_OK) {
        ESP_LOGI(TAG, "Response length: %u", (unsigned)rx_len);
    }
}
```

## Slave example

```c
#include "spi_link.h"
#include "esp_log.h"

static const char *TAG = "app_slave";

void app_main(void)
{
    spi_link_config_t config = {
        .mode = SPI_LINK_MODE_SLAVE,
        .host = SPI2_HOST,
        .pin_mosi = 11,
        .pin_miso = 13,
        .pin_sclk = 12,
        .pin_cs = 10,
        .pin_ready = 9,
        .queue_size = SPI_LINK_DEFAULT_QUEUE_SIZE,
        .max_transfer_size = SPI_LINK_DEFAULT_MAX_TRANS_SIZE,
    };

    ESP_ERROR_CHECK(spi_link_init(&config));

    while (1) {
        spi_link_packet_t packet = {0};
        esp_err_t err = spi_link_slave_receive(&packet, portMAX_DELAY);
        if (err != ESP_OK) {
            continue;
        }

        if (packet.cmd == SPI_LINK_CMD_DATA) {
            const char reply[] = "ok";
            spi_link_slave_reply(SPI_LINK_CMD_ACK, reply, sizeof(reply) - 1);
        } else if (packet.cmd >= SPI_LINK_CMD_USER_BASE &&
                   packet.cmd <= SPI_LINK_CMD_USER_END) {
            spi_link_slave_reply(SPI_LINK_CMD_ACK, NULL, 0);
        } else {
            spi_link_slave_reply(SPI_LINK_CMD_NACK, NULL, 0);
        }
    }
}
```

## API overview

Common APIs:

- `spi_link_init()`
- `spi_link_deinit()`
- `spi_link_is_connected()`
- `spi_link_is_slave_ready()`

Master APIs:

- `spi_link_handshake()`
- `spi_link_master_send()`
- `spi_link_master_request()`
- `spi_link_master_read()`

Slave APIs:

- `spi_link_slave_receive()`
- `spi_link_slave_reply()`

## Current limitations

- The component currently keeps one global runtime context and supports a single
  SPI_Link instance.
- Automatic retry is not implemented.
- Large payload fragmentation is not implemented. A single payload is limited to
  `SPI_LINK_MAX_PAYLOAD_SIZE`.

See [docs/SPI_Link说明文档.html](docs/SPI_Link说明文档.html) for the full Chinese
design and API document.

Links

Supports all targets

Maintainer

  • Miraitowa-la

License: MIT

To add this component to your project, run:

idf.py add-dependency "miraitowa-la/esp_spi_link^0.1.0"

download archive

Stats

  • Archive size
    Archive size ~ 24.13 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

miraitowa-la/esp_spi_link version: 0.1.0
|