Skip to content

netham45/esp32-spdif

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESP32 S/PDIF Input (RMT-based)

High-performance S/PDIF receiver implemented with the ESP-IDF RMT RX + DMA. It auto-discovers the input pulse timing, decodes bi-phase-mark encoded subframes, and produces interleaved 16-bit PCM stereo frames via a FreeRTOS ring buffer.

Key files:

Supported targets and IDF:

Data Flow

flowchart LR
  RMT[RMT RX ISR] --> SYM[Symbol ringbuffer]
  SYM --> DEC[Decoder task]
  DEC --> PCM[PCM ringbuffer int16 stereo]
  PCM --> APP[Application reader]
Loading

Features

Hardware Notes

  • Input is consumer S/PDIF; do not connect coax S/PDIF directly to a GPIO. Use an optical receiver module or a proper transformer/line receiver to 3.3 V logic.
  • Choose any RMT-capable GPIO for the input pin; pass it to spdif_receiver_init().

Quick Start

  1. Initialize and start the receiver
#include "spdif_in.h"

static void on_ready(void) {
    // Optional callback when init completes
}

void app_start(void) {
    ESP_ERROR_CHECK(spdif_receiver_init(GPIO_NUM_4, on_ready)); // [spdif_receiver_init()](include/spdif_in.h#L46)
    ESP_ERROR_CHECK(spdif_receiver_start());                    // [spdif_receiver_start()](include/spdif_in.h#L47)
}
  1. Wait for sample-rate lock and read PCM frames
uint32_t sr = 0;
while ((sr = spdif_receiver_get_sample_rate()) == 0) {
    vTaskDelay(pdMS_TO_TICKS(10)); // [spdif_receiver_get_sample_rate()](spdif_in.c#L374)
}

// Either use the helper reader...
int16_t stereo[2];
int got = spdif_receiver_read((uint8_t*)stereo, sizeof(stereo)); // [spdif_receiver_read()](include/spdif_in.h#L56)

// ...or pull directly from the ring buffer for batched reads
size_t n = 0;
uint8_t* data = (uint8_t*) xRingbufferReceiveUpTo(
    spdif_in_get_ringbuf(), &n, pdMS_TO_TICKS(20), 1024); // [spdif_in_get_ringbuf()](include/spdif_in.h#L52)
if (data) {
    // data contains interleaved int16 little-endian [L,R] frames
    vRingbufferReturnItem(spdif_in_get_ringbuf(), data);
}
  1. Stop and deinit if needed
ESP_ERROR_CHECK(spdif_receiver_stop());   // [spdif_receiver_stop()](include/spdif_in.h#L48)
spdif_receiver_deinit();                  // [spdif_receiver_deinit()](include/spdif_in.h#L49)

API Reference

Configuration Constants

Notes on Timing Discovery

PCM Format

  • Interleaved stereo little-endian int16 frames: [L0,R0,L1,R1,...]
  • Producer writes a pair on each right-channel sample in spdif_decoder_task()
  • With PCM_BUFFER_SIZE=4096, the buffer holds 1024 stereo frames (~21 ms at 48 kHz)

Threading and Resources

Limitations

  • Only 48 kHz and 44.1 kHz are reported by spdif_receiver_get_sample_rate()
  • Channel status/user data are not parsed; only 24-bit audio sample fields are decoded then downshifted to int16
  • No slip/underrun recovery signaling to the application beyond normal ring buffer semantics

Troubleshooting

  • Sample rate stays 0: ensure valid S/PDIF signal and allow time to gather at least MIN_SAMPLES_FOR_ANALYSIS symbols
  • Empty reads: check that the consumer reads in multiples of 4 bytes and that spdif_receiver_start() has been called
  • Pin mapping: confirm the selected GPIO supports RMT RX on your target

Version and Metadata

About

esp32 spdif component

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published