-
• #2
If the voltage really does drop below zero, your best bet is to 'bias' it up so the average voltage is at the point at which Espruino's input flips between a 0 and a 1:
3.3v | _|_ | | | | 10k Ohm | | |___| | IN | | | ------| |------|------------ Espruino Pin | | | _|_ 10uF | | | | 10k Ohm | | |___| | | GND
Those values are just total guesses, but they should work. If you have some kind of oscillocope it'd be a massive help so you can see what's going on. If that doesn't work, you may have to resort to using a separate comparator.
At that point you should be able to use
setWatch
like you suggest though. Just 2 potential issues:In
setWatch( BMCman.tick, A0, {repeat:true, edge:'both'} ) ;
, thethis
value won't be correct when you callBMCman.tick
- you actually needBMCman.tick.bind(BMCman)
to force it.Looking at that document, the time code can be about 2.4kHz - which is right on the limit of what Espruino can handle in normal JS, so you'll have to be super careful to get your code to run quickly... Possibly resorting to using espruino.com/Compilation for the watch handler.
Something like the following might be a good start though:
function start() { var d,c = ""; setWatch( function(e) {d=e.time-e.lastTime>0.00075;if(d||e.state)c+=1^d;}, A0, {repeat:true, edge:'both'} ) ; setInterval(function() { var sync = c.indexOf("0011111111111101"); // ideally you'd use 'sync' for re-syncing here console.log(c); c=""; }, 500); }
The watch handler is pretty cryptic because it's trying to be fast to execute, but:
- Using local variables to try and keep the speed up
- d is true if it's a long pulse
- if it's a short pulse and it's low, we ignore it (so we don't get 2 bits for the double-transition)
- otherwise we negate d (short pulses are 1, long are 0) and stick it on the end of the string c
- every so often we check for the sync bits - we don't do it that often because we want the bits to be handled first.
-
• #3
Thanks Gordon,
I've been developing the idea fully in JS, but from the outset I suspected I'd have to compile it, or perhaps bash it out in ASM.
function BiPhaseDecoder() { // gaps this.last_B_period = 0.0 ; this.this_period = 0.0 ; this.big_periods = 0.0 ; this.small_periods = 0.0 ; // FSM this.in_long_gap = false ; this.in_first_half = false ; // booting this.till_booted = 32 ; // arbitrary // The bit I'm decoding this.bit = -1 ; // register Event this.bitEvent = function(){}; } // process BiPhaseDecoder.prototype.tick = function( event_data ) { // get the time since last crossing this.this_period = (event_data.time - event_data.lastTime) ; // determine if it's a long or short period // cf: http://www.avrfreaks.net/forum/tut-pc-avr-softunderstanding-bi-phase-mark-coding // "If it's more than 3/4 of the bit period, you've just received a zero; // otherwise, you got half of a one." // Note: by only ever comparing current period to long-ifyied last period, we // can tolerate increases in speed of transmission, if gradual; and need no // a priori data on expected rate / samps per sec. if( (this.this_period * 4.0) > (this.last_B_period * 3.0) ) { // this is a long period this.last_B_period = this.this_period ; this.in_long_gap = true ; // get stats this.big_periods += this.this_period ; this.big_periods *= 0.5 ; } else { // otherwise a short period this.last_B_period = this.this_period * 2.0 ; // last_B_period is always big this.in_long_gap = false ; // get stats this.small_periods += this.this_period ; this.small_periods *= 0.5 ; } // if this_period > (3/4 * last_B_period) // a long gap == bit 0; or two short gaps == bit 1 if( this.in_long_gap ) { this.in_first_half = false ; this.bit = 0 ; } else { if (this.in_first_half) { this.in_first_half = false ; this.bit = 1 ; } else { this.in_first_half = true ; this.bit = -1 ; // not ready to TX yet } } // if in_long_gap if( this.till_booted < 0 ) { // emit the bit if ready if( (this.bit >= 0) ) { this.bitEvent( this.bit ) ; } } else { // it will take some time to get a good sampling of big and small periods this.till_booted-- ; // keep flushing the stats till it stabilizes this.big_periods = 0.0 ; this.small_periods = 0.0 ; // possibly, 'if( Math.abs( (small * 2.0) - big ) < 1e-5 ) till_booted = -1 ;' } // if booted } ;
Which is pretty heavy, but easier to debug. This method makes no assumptions about the short bit period, and would tolerate a 'ripple' in the transmission rate. First step would be minifying it I guess, and maybe ditching the avg. gap length I'm keeping.
I'm then pushing the 'bit' into a Uint16Array - like a LIFO - lots of shifts and carrys (probably better in ASM too) then it's just 'bitfield[4] & 0x3FFD' to find the sync word.
I didn't know about the x.y.bind(x) gotcha - thanks for that.
Hi,
I'm developing a system to read LTC timecode (cf wiki, Good Article), which is an audio signal (I'd guess between .32V and .77V RMS). TL;DR the links, it's a binary pattern in Bi-phase mark coding. I want to sense the period between zero crossings to decode the signal. Will reading a Pin in "both" mode:
have the desired result, or should I use a Zero-Crossing detection circuit to condition the signal to a rising edge before sensing it?
Thanks.