In the previous post, I believe I dismissed Manchester coding too quickly as a possibility, thinking that some unwieldy analog circuitry would be necessary for its implementation. Today, I realized that it would actually be fairly easy to create a decoder using microcontroller code that would fairly easily handle arbitrary bitrates and even possibly do a decent job accounting for drift.
To explain, Manchester coding is a type of self-clocking signal (i.e., it combines data and clock lines) that guarantees either one or two edges (transitions from low to high or high to low) per bit. A logical 0 starts high and then switches to low mid-bit; a logical 1 goes low to high instead.(Described above is the IEEE version. As the image shows, it’s possible to flip the two by convention.)
What the microcontroller must do to make sense of such a signal is pretty simple, much to my delight. It’s simple because there are only two possibilities for the duration between transitions; we’ll call them D/2 for the narrow pulses and D for the wider ones. Assuming we have a decent guess at what D is (we’ll get to that), and that any two consecutive D widths are reasonably similar, we can decode the pulse train and even compensate for gradual drift of the D value. It goes something like this:
- Say we have 3 initial guesses for D, which are D0, D1, and D2. At any given moment, our estimated value of D = (D0 + D1 + D2)/3.
- At each transition, find X, the distance between this and the previous transitions.
- If X < (3/4)D, consider X to be approximately D/2. Ignore this transition and start waiting for the next one.
- If 4X < 3D then X < (3/4)D. 4X = X shifted left 2. 3D = D0 + D1 + D2. No actual multiplication or division required!
- If (3/4)D ≤ X < (3/2)D, consider X to be approximately D. Accept the current input as the next bit. Let D0 = D1, D1 = D2, D2 = X.
- If 2X < 3D then X < (3/2)D. 2X = X shifted left 1. 3D is as above.
- If X ≥ (3/2), the transmission has ended or there is an error; handle accordingly.
Using this mechanism, the average of the previous three bit widths is used as the expected width for the next bit, but the next bit can be nearly 25% narrower or 50% wider and still be valid. Since this sliding window approach is used, the bitrate could generally vary by quite a lot as long as the change is gradual. Oversampling is key here—I imagine that the receiver should try to sample at least 6 times (wild guess) the expected bitrate.
How do we set up initial guesses for D? Here’s one proposition on how to make an explicit initial sync:
- The initial guess for D would be very short, possibly shorter than any actual expected D.
- When the line is idle, it is held low, and should be held low longer than the max nominal 2D specified by the system. Consequently, if the line is low for over twice the expected 2D, the receiver should recognize an idle state.
- When a frame is about to be sent, the line goes high for exactly X = 2D as decided by the sender. At the next high-low transition, the receiver assigns D0 and D1 based on this value: D0 = X shift right 1; D1 = X – D0.
- The transition following this transition is the start bit, which is a 1 (low-to-high). The width Y of the low before the transition is approximately D/2. Assign D2 based on this value: D2 = Y shift left 1.
- Start sampling as specified from the start bit transition.
- After some fixed number of bits, the frame ends with a stop bit, which is a 0 (high-to-low). After the bit, the line is held low to indicate idle as mentioned before.
This one’s got some true promise, I think. I’m guessing it may even be possible to get it working using a high-tolerance clock on the slave micro (such as an RC network) making it potentially feasible to use even a super-cheap one, like the PIC16F54 of which I happen to have plenty lying around, without an excessive amount of tuning. I could be wrong, though. Who knows?