Pico and SPDIF audio
I've found code for a SPDIF transmitter for the Pico which looks okay. But an SPDIF receiver is a lot harder. Has anybody tried to do this and either succeeded or failed because the Pico isn't up to it ? Don't want to spend time on a doomed project if it's been proven to bound to fail.
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
-
cleverca22
- Posts: 9572
- Joined: Sat Aug 18, 2012 2:33 pm
Re: Pico and SPDIF audio
at a rough guess, i'm thinking you would want to over-sample the spdif signal
so you would want maybe 4 samples for every 1 bit on the digital stream
then if you sometimes get 3 or 5 in a row, you can shift what your code is treating as 1 bit, and compensate for the minor timing differences
the problem then, is what is the raw sample rate you need, including any embedded clocking signals?
is there enough cpu left-over to compute samples at that rate?
so you would want maybe 4 samples for every 1 bit on the digital stream
then if you sometimes get 3 or 5 in a row, you can shift what your code is treating as 1 bit, and compensate for the minor timing differences
the problem then, is what is the raw sample rate you need, including any embedded clocking signals?
is there enough cpu left-over to compute samples at that rate?
-
kilograham
- Raspberry Pi Engineer & Forum Moderator

- Posts: 1835
- Joined: Fri Apr 12, 2019 11:00 am
- Location: austin tx
Re: Pico and SPDIF audio
yeah you can. i had a quick play a while back and was able to decode up to 192khz stereo from another pico. Didn't have anything sensible to hook up real world stuff with. I was super sampling at just over 2 samples per shortest half cycle which is about 13.5Mhz for 44100 or 48000. Combine that with DMA and a fast CPU side state machine to crank those raw samples into pulse lengths & decoded bits.
I chose that method because I was curious if i could get up to 192khz, but there are probably simpler methods (i.e. do more work on PIO) for lower frequencies.
I chose that method because I was curious if i could get up to 192khz, but there are probably simpler methods (i.e. do more work on PIO) for lower frequencies.
-
cleverca22
- Posts: 9572
- Joined: Sat Aug 18, 2012 2:33 pm
Re: Pico and SPDIF audio
kilograham wrote: ↑Sat Aug 21, 2021 4:44 amCombine that with DMA and a fast CPU side state machine to crank those raw samples into pulse lengths & decoded bits.
Code: Select all
[nix-shell:~/apps/rpi/lk-overlay]$ cat ../pico/pico-examples/pio/logic_analyser/lh2.pio
.define public pin_count 16
.program lh2
set x, 1
in x, 1
in null, 8
mov x, isr ; X now contains 1<<8
.wrap_target
mov y, x
wait 1 irq 0
inner_loop:
in pins, pin_count
jmp y-- inner_loop
.wrap
.program lh2_trigger
.wrap_target
main_loop:
in pins, pin_count
mov x, isr
jmp x!=y edge_found
.wrap
edge_found:
irq 0
mov y, x
jmp main_loop
[nix-shell:~/apps/rpi/lk-overlay]$ cat ../pico/pico-examples/pio/logic_analyser/lh2-v2.pio
.define public pin_count 16
.program lh2_v2
main_loop:
.wrap_target
in pins, pin_count
mov x, isr
jmp x!=y edge_found
.wrap
edge_found:
set pins, 1
push
mov y, x
jmp main_loop
.program lh2_v2_rle
.wrap_target
mov x, ~null
loop:
jmp pin triggered
jmp x-- loop
triggered:
set pins, 0
mov osr, x
push
.wrap
they basically do a form of RLE compression within the PIO itself
any time the input pins change state, it will report the new state and how many loops it was in the old state
then you just need some code to further condense it, so if you get 2 samples, saying 00 and 01, but you only care about the left bit, you can add the time period for both, and create a new sample just saying 0
and boom, you now have a series of time periods, for the on/off time of a 1 bit stream!
the reason i was capturing more then 1 bit, is because i wanted to deal with multiple VR tracking receivers at once, just capture the whole mess in parallel, then untangle it afterwards, when hits arent happening
Re: Pico and SPDIF audio
That's great thanks ! I'll order a pack of Picos thenkilograham wrote: ↑Sat Aug 21, 2021 4:44 amyeah you can. i had a quick play a while back and was able to decode up to 192khz stereo from another pico. Didn't have anything sensible to hook up real world stuff with. I was super sampling at just over 2 samples per shortest half cycle which is about 13.5Mhz for 44100 or 48000. Combine that with DMA and a fast CPU side state machine to crank those raw samples into pulse lengths & decoded bits.
I chose that method because I was curious if i could get up to 192khz, but there are probably simpler methods (i.e. do more work on PIO) for lower frequencies.
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
Re: Pico and SPDIF audio
Sorry to resurrect this one Graham, but can I ask were you overclocking the Pico when you tried to get to 192kHz ?kilograham wrote: ↑Sat Aug 21, 2021 4:44 amyeah you can. i had a quick play a while back and was able to decode up to 192khz stereo from another pico. Didn't have anything sensible to hook up real world stuff with. I was super sampling at just over 2 samples per shortest half cycle which is about 13.5Mhz for 44100 or 48000. Combine that with DMA and a fast CPU side state machine to crank those raw samples into pulse lengths & decoded bits.
I chose that method because I was curious if i could get up to 192khz, but there are probably simpler methods (i.e. do more work on PIO) for lower frequencies.
I'm using 96kHz sample rate, which translates to a 12.288 MHz cell rate, and oversampling at 3 times to help filter out transition sampling errors. I run length encode in software using a dedicated second core, but that seems to need just under 50% overclocking to keep up.
Now looking at doing the RLE on the PIO but don't have all four state machines available.
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
-
kilograham
- Raspberry Pi Engineer & Forum Moderator

- Posts: 1835
- Joined: Fri Apr 12, 2019 11:00 am
- Location: austin tx
Re: Pico and SPDIF audio
I did not overclock... i italicized "fast" because it does need to be quite.
I can't give you all the code, but as i say i over-sample at just over 2, and have a state machine advanced by each sampled bit. some edges on the state machine emit symbols (e.g. decoded "1", decoded "0", "SYNC", "X", Y", "Z")
My state machine has 51 states. (a short pulse requires 2, or 3 of the same bit in a row, a long pulse requires 4 or 5 etc, so you need states for each possible distinct preceding bit sequence that is meaningful)... most of the states are for spotting an classifying the sync pulses.
given the state machine, i precompute a table for what happens foreach incoming state and the next 8 bits received, recording what symbols are output as a result and the resulting state after the 8 bits.
thus the decode looks something like
I can't give you all the code, but as i say i over-sample at just over 2, and have a state machine advanced by each sampled bit. some edges on the state machine emit symbols (e.g. decoded "1", decoded "0", "SYNC", "X", Y", "Z")
My state machine has 51 states. (a short pulse requires 2, or 3 of the same bit in a row, a long pulse requires 4 or 5 etc, so you need states for each possible distinct preceding bit sequence that is meaningful)... most of the states are for spotting an classifying the sync pulses.
given the state machine, i precompute a table for what happens foreach incoming state and the next 8 bits received, recording what symbols are output as a result and the resulting state after the 8 bits.
thus the decode looks something like
Code: Select all
// for each byte of 8 oversamples from the PIO (at d8)
uint val = decoder_table[(ds->state << 8u) | *d8++];
ds->state = val & 0xffu; // new state
// handle one of 22 possible combinations of output
switch(val>>8u) {
...
case 9: ds_0(ds); break;
case 10: ds_1(ds); break;
case 11: ds_0(ds); ds_sync(ds); break;
...
case 18: ds_1(ds); ds_0(ds); break;
case 19: ds_x(ds); ds_1(ds); break;
}
Re: Pico and SPDIF audio
Ok thanks. That's moreorless what I'm doing but I'm using a faster clock to make sure any edge sampled just as it changes can be ignored. I'll pull the clock rate down and see if/when the error rate rises.
Thanks again
Thanks again
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
-
shreekumar3d
- Posts: 35
- Joined: Mon Nov 29, 2021 4:43 am
Re: Pico and SPDIF audio
I have had success decoding SPDIF too.
Here's what I am doing: one PIO program converts the SPDIF signal into run lengths. The CPU then converts these into actual bit lengths - 1.5, 1 and half. The resulting buffer is fed back to another PIO program that converts the bit lengths to actual audio samples. DMA is used to move samples up and down.
It's a work in progress at the moment. Quick benchmarks: a millisecond of audio - 48 samples (16 bit) at 48 kHz are decoded in ~150 microseconds. So there is a lot of headroom to handle faster data rates. So haven't found the need to overclock the RP2040.
Here's what I am doing: one PIO program converts the SPDIF signal into run lengths. The CPU then converts these into actual bit lengths - 1.5, 1 and half. The resulting buffer is fed back to another PIO program that converts the bit lengths to actual audio samples. DMA is used to move samples up and down.
It's a work in progress at the moment. Quick benchmarks: a millisecond of audio - 48 samples (16 bit) at 48 kHz are decoded in ~150 microseconds. So there is a lot of headroom to handle faster data rates. So haven't found the need to overclock the RP2040.
Re: Pico and SPDIF audio
I get the PIO to just give me three run states - '1' for a single cell (half a audio '1' bit), '2' for a double cell (audio '0' bit) and '3' for a violation (preambles). Then I do everything else on the processor which ends up being pretty marginal with 122.88MHz clock and 24 bit/96kHz sampling as I need to extract some of the other bits as well, though I don't bother with parity. Interesting idea to put data back into the PIO for post-processing, but unfortunately I've had to use up the rest of both PIO memories for I2S interfaces and for SPI as I wasn't budgeting for the standard SPI peripheral not working with a CM4.shreekumar3d wrote: ↑Tue Nov 30, 2021 3:49 amI have had success decoding SPDIF too.
Here's what I am doing: one PIO program converts the SPDIF signal into run lengths. The CPU then converts these into actual bit lengths - 1.5, 1 and half. The resulting buffer is fed back to another PIO program that converts the bit lengths to actual audio samples. DMA is used to move samples up and down.
It's a work in progress at the moment. Quick benchmarks: a millisecond of audio - 48 samples (16 bit) at 48 kHz are decoded in ~150 microseconds. So there is a lot of headroom to handle faster data rates. So haven't found the need to overclock the RP2040.
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
Re: Pico and SPDIF audio
Okay I've been thinking about this all day and still haven't worked out how you get a PIO to do that. Any hints ?shreekumar3d wrote: ↑Tue Nov 30, 2021 3:49 amThe resulting buffer is fed back to another PIO program that converts the bit lengths to actual audio samples.
Always interested in innovative audio startups needing help and investment. Look for InPoSe Ltd or Future Horizons on LinkedIn to find me (same avatar photograph)
-
shreekumar3d
- Posts: 35
- Joined: Mon Nov 29, 2021 4:43 am
Re: Pico and SPDIF audio
The three states are encoded into 2 bits, values 0, 1, and 2 (for bit 0, 1 and violation) on the CPU and sent to PIO. PIO knows the structure of the SPDIF frame (premable, AUX bits, data, VUCP). It goes over the data 2 bits at a time, and outputs only the audio bits. As a result the CPU gets the direct samples back.
For this scheme to work, the CPU waits for a full preamble (B or M - left samples) to come in & then start feeding data to the PIO. This only needs to be done once. This gives PIO the starting point. It doesn't bother with what the preamble is. The preamble is guaranteed to be 4 x 2 bits long - so it just skips over them.