New Idea and a Change of Venue

A project log for Propeller S/PDIF Receiver

Uncovering Subchannel Secrets

Jac GoudsmitJac Goudsmit 06/03/2017 at 22:020 Comments

I haven't had time to work on this for a few days but I wanted to share a new idea of decoding the biphase input with the Propeller timers, and this picture:

The photo shows a minor change of venue: I rebuilt the schematic on a different breadboard using the new Parallax FLiP module. This is a great new product ftom the producers of the Propeller (I'm not affiliated, just a fan as you may have noticed) that offers an entire Propeller circuit including USB to serial converter, 5 MHz crystal, and a great flexible power supply on a board that's the size of a DIP Propeller. They even had space to solder two LEDs onto pins 26 and 27 which can help greatly with debugging. Using the FLiP makes it much easier to put together a Propeller circuit because (unlike with the PE kit) you don't have to mess around with the power supply, the crystal, and/or a prop plug.

Anyway, about that new idea I had: As I've mentioned before, the Propeller has to be able to process one bit of biphase data in 326ns if I want to make it work at 48kHz stereo sampling rate. That's about 6 assembler instructions. I already got it to (kinda) decode a signal by using two cogs (one for recovering the clock and one for measuring time) but I wasn't happy with the result.

The last implementation of the biphase decoder counted flanks on the XORIN input which is better, but it was very difficult to get the timing right because of all the propagation delays, and I had the feeling that that wasn't going to be robust enough. For one thing, the timing would have to be adjusted to the input frequency, even if it changed only slightly.

But earlier this week I had an epiphany: what if I just keep counting flanks from the beginning of a subframe to the end of a subframe, and never reset the counter? That would have some serious advantages!

In the previous version of the code, I would read the timer/counter (PHSA register) at the start of every bit, and then reset it. But by the time that the timer actually gets reset, the next pulse is already almost coming in if the current bit is a 1. That's exactly what I didn't like about that code: I had to time the reset exactly right (within one 12.5ns Propeller clock cycle accuracy) so the timers wouldn't miss anything, and I had the feeling that this was pretty much impossible given the amount of jitter. That's not something I want the end user to have do (besides, it would probably be difficult to do while the system is running).

I thought up a simple loop in PASM that goes about as follows:

  1. Set timer A to count positive edges on XORIN.
  2. Wait for a positive edge on XORIN using a WAITPxx instruction. This signifies the start of a new bit.
  3. Test the lsb of PHSA to find out if there was an odd or even number of transitions in the spdif input.
  4. Shift the odd/even result into a long word as a single bit.
  5. Check if a preamble was detected and jump out of the loop if so (I may do this a different way but that's not relevant for this discussion)
  6. By now, 6 instructions should have passed so jump back to the beginning of the loop (step 2). Alternatively, I may unroll the loop and just paste the above 32 times.

At the end of the subframe, there are 32 bits of data available but each bit doesn't represent an actual data bit value but a record of the oddness of the total number of biphase flanks at the end of each bit time.

On the SPDIF input, a zero-bit is represented as a single transition and a one-bit is represented as two transitions. So if the total number of transitions goes from even to odd or from odd to even in one bit-time, the encoded data bit must have been a 0 because one transition on the SPDIF line causes one pulse on the XORIN line and an odd number plus 1 is always an even number and vice versa. Similarly if the total number of positive edges on XORIN stayed even or stayed odd, the encoded data bit must have been a 1 because the oddness of a number doesn't change if you add (a multiple of) 2.

I'll have to figure out if it's possible to process the oddness-changes on the fly (if so, the biphase decoding would only take a single cog, that would be perfect!), otherwise I'll stick to my earlier idea of running two cogs in parallel; one for the left channel and one for the right channel, and each cog processes the data while the other cog is sampling the next subframe.

But I'm pretty confident that this is a solid way of decoding biphase without ANY need to adjust timing constants (except maybe the expected length of a preamble) as long as the input frequency is between 32kHz and 48kHz and as long as the Propeller frequency is at least 80MHz. If the Propeller is too fast for the signal (i.e. it's able to execute all the instructions before the secondary pulse of a biphase "1" comes in) or too slow (i.e. it can't distinguish a preamble from a biphase "0" bit), it will stop working but I think with the current requirements, I can make it work.

I'll try to program something around this idea in the next few days. I'm getting pretty confident that I'm close to writing a robust biphase decoder.

Update: I tried it out and it works: I'm getting a reliable stream of bits, decoded from the biphase data! Now to figure out how to decode preambles and store the data in the hub of the Propeller for processing.