433mhz Espruino <-> Arduino

Posted on
Page
of 2
/ 2
Next
  • I seem to be having a hard time making 433mhz work, at all.

    Receiver connected to C0, transmitter on A0.

    Transmitter is powered by vbat.

    setWatch(function (e){console.log(e);},C0,{repeat:true});
    

    When the receiver is powered by 3.3v, nothing comes out, even if I hold it an inch away and toggle transmitter on and off.

    Doing analogReads indicated that the voltage was very low (results like 0.01).

    When the receiver is powered by vbat (4.3v), I get constant events like this:

    { "lastTime": 1124.25785541534, "time": 1124.25871372222, "pin": C0, "state": true }
    { "lastTime": 1124.25871372222, "time": 1124.26307678222, "pin": C0, "state": true }
    { "lastTime": 1124.26307678222, "time": 1124.26428127288, "pin": C0, "state": true }
    { "lastTime": 1124.26428127288, "time": 1124.27121448516, "pin": C0, "state": true }
    { "lastTime": 1124.27121448516, "time": 1124.27125263214, "pin": C0, "state": false }
    { "lastTime": 1124.27125263214, "time": 1124.27619934082, "pin": C0, "state": true }
    { "lastTime": 1124.27619934082, "time": 1124.27624320983, "pin": C0, "state": false }
    { "lastTime": 1124.27624320983, "time": 1124.28102111816, "pin": C0, "state": true }
    { "lastTime": 1124.28102111816, "time": 1124.29145908355, "pin": C0, "state": true }
    { "lastTime": 1124.29145908355, "time": 1124.29166603088, "pin": C0, "state": false }
    { "lastTime": 1124.29166603088, "time": 1124.29167938232, "pin": C0, "state": true }
    { "lastTime": 1124.29167938232, "time": 1124.29274654388, "pin": C0, "state": true }
    { "lastTime": 1124.29274654388, "time": 1124.29405975341, "pin": C0, "state": true }
    { "lastTime": 1124.29405975341, "time": 1124.30696010589, "pin": C0, "state": true }
    { "lastTime": 1124.30696010589, "time": 1124.30718421936, "pin": C0, "state": false }
    { "lastTime": 1124.30718421936, "time": 1124.30720996856, "pin": C0, "state": true }
    { "lastTime": 1124.30720996856, "time": 1124.30725002288, "pin": C0, "state": false }
    { "lastTime": 1124.30725002288, "time": 1124.31108379364, "pin": C0, "state": true }
    { "lastTime": 1124.31108379364, "time": 1124.31595802307, "pin": C0, "state": true }
    { "lastTime": 1124.31595802307, "time": 1124.31667995452, "pin": C0, "state": true }
    { "lastTime": 1124.31667995452, "time": 1124.31785392761, "pin": C0, "state": true }
    { "lastTime": 1124.31785392761, "time": 1124.32804393768, "pin": C0, "state": false }
    { "lastTime": 1124.32804393768, "time": 1124.32841300964, "pin": C0, "state": true }
    { "lastTime": 1124.32841300964, "time": 1124.32851505279, "pin": C0, "state": false }
    { "lastTime": 1124.32851505279, "time": 1124.32971382141, "pin": C0, "state": false }
    { "lastTime": 1124.32971382141, "time": 1241.55311012268, "pin": C0, "state": true }
    
    

    analogRead() shows it as going between near 0 and near 1 (er, maybe higher than that pin should get, since it's not 5v tolerant)

    I get the same results using an Arduino to listen to the receiver. Nothing I can do seems to make any change in the behavior of the receiver. Move it around? no change. Put it in a metal box with a metal lid and leave only space for the wires to get out? No change.

    I'm using what looks to be the exact same kind of transmitter/receiver that the tutorial uses.

    My thinking is that the receiver must be defective, unless there are any other things to check?

  • I think maybe the 3.3v suggestion was a bit optimistic. I tried on a second RX module and had no luck with it either - I think maybe I was just lucky with the first one I tried (or I had an exceptionally strong transmitter).

    What you're getting at Vbat voltages looks about right though. The 433Mhz band is insane. It's unregulated and is used for so much stuff that there's pretty much constant noise on it.

    As I understand it, the receivers have an automatic gain control on them, so the idea is when something nearby transmits, it drowns out everything else for a short time and hopefully you get the right signal - however most stuff sends the signal a few times just to be sure!

    Anyway, it makes it pretty important that the receiver code on the Espruino executes really quickly, as you could be getting 500-1000 pulses per second.

  • Yuck!
    The problem to me looks like the fact that, by the looks of that log, it's almost always high? Wouldn't that leave no time to get in a transmission, or am I missing something?

    My plan was to use these to communicate between an Espruino and scattered ATTinys (running off 5v wallwarts) controlling clusters of 1W LEDs. That's also what I was hoping I could do with the NRF24s. So far the dream (of an Espruino wirelessly controlling a network of lesser minions) has remained elusive.

  • About NRF24 - did you see that post (I forget who it was from now) about just adding a decoupling capacitor? Apparently it solves the stability issue...

    About the signal being high - I doubt it's the case - you'd have to look with an oscilloscope I'm afraid (or you could record just a short section of the data into memory and then print that). My guess is:

    • Espruino can't print that much data out fast enough
    • It has to block waiting for the print to finish
    • The input buffer gets full and events get missed - in this case it just happens that they're the events where the signal is lowered

    ATTinys should be fine to decode the signal though - you just need to make sure it's complex enough (CRC?) that you don't get invalid data.

    Even if the signal is high most of the time, when you transmit it should be fine. The automatic gain will cause the sensitivity of the receiver to lower, so that when your signal stops you get a '0' received (until the sensitivity recovers).

    If you're making your own signal format, it seems a good form is:

    • A ~4ms '1' signal - which is easy to detect and which gives the receiver time to adjust
    • A series of pulses - PWM is easiest, maybe 0.7ms for a 0, and 1.3ms for a 1, with a gap of ~0.5ms
    • You could end with a big pulse as well so you know that the transmission has ended, but just making sure you have maybe 20 pulses after the long one is probably good enough.
  • With the NRF's, I was never able to transmit anything whatsoever between an arduino and espruino. I made a thread on it here. IIRC, I could get arduinos to talk to arduinos, and espruinos to talk to espruinos, but I could never make them talk to eachother, even after pouring over the library code on both sides. Was never able to figure out why they couldn't talk. I think another person here had had the same problem, and he didn't figure it out either.

    How on earth would I create a data stream like that with PWM? I'd need to change the duty cycle after each pulse...

    For some reason, I seem to be having a horrible time making any sense of this, and I don't know why. I think one of the big problems for me right now is that I don't have either a known working transmitter or a known working receiver to go from. I also.. usually when I look at a problem, I can see a path forward... but I'm having a really hard time with this. I just have no idea how to approach it... if the receiver output a low continuously unless there was a signal, it'd be easy, but I just have no clue how to pick out a signal surrounded by gibberish.

  • Well, my RX unit is defective NOW...

    I got VCC and GND backwards, and within a few seconds, I smelled hot electronics and the op-amp was too hot to touch. Now even connected correctly, it doesn't work, and the op-amp rapidly heats up.

    This has not been a good week for me - I've broken $15 in parts in just the past 2 days.

    The only way I can think of to send those pulses from Espruino is this - am I missing something?

    var txpin=A1;
    
    function sendTest() {
      digitalPulse(txpin,1,4); //4ms start
      digitalPulse(txpin,1,0); //wait for 4ms to finish
      digitalPulse(txpin,0,0.5); //pause after 4ms
      digitalPulse(txpin,0,0); //wait to finish
      digitalPulse(txpin,1,1.3); //send a 1
      digitalPulse(txpin,1,0);  // wait to finish
      //and so on...
    }
    

    Are the digitalPulse(txpin,state,0); lines necessary? Will this work, or will there be gaps that throw off the timing? Of course, I can't test anything since I burned out my receiver.

  • Argh, shame about the receiver :(

    Yes, I remember about the NRF... I never understood why it didn't work either. There must have been something that was missing. I guess you could try swapping the NRF module between Arduino and Espruino while it was powered (so it kept all its settings), and it might be easier to compare then I guess.

    Me saying PWM was a bit confusing - what I meant was basically 'not Manchester Encoding'...

    digitalPulse is the way to go - you don't need the ,0 bits because digitalPulse waits until the last pulse is over before doing the new one. The remote control socket example does that kind of thing already: http://www.espruino.com/Remote+Control+S­ockets#line=70,71,73,74

    In terms of the receiver, just write the code to read your message, and pray :) It always surprised me just how well the message was extracted from all the noise on the airwaves.

    On the Arduino I guess you'd have to write an interrupt routine and then use some kind of timer to measure the pulse lengths... I'd imagine someone already has a decoder that could be tweaked - although I did see one or two on YouTube that made me cringe :)

  • Got my new receivers. After a few extremely frustrating evenings, I've got the basics working....

    I send it like this:

    
        var txpin=A1;
    
    function sendTest2() {
         for (i = 0; i < 20; i++) { //20ms long training burst. Had crap results with shorter ones.
            digitalPulse(txpin,1,0.5); 
            digitalPulse(txpin,0,0.5); 
        } 
        digitalPulse(txpin,1,0.5); //end training burst
        digitalPulse(txpin,0,2);   //sync
        digitalPulse(txpin,1,0.7); //send a 0
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,1.3); //send a 1
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,0.7); //send a 0
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,1.3); //send a 1
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,1.3); //send a 1
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,0.7); //send a 0
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,1.3); //send a 1
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,1,1.3); //send a 1
        digitalPulse(txpin,0,0.5); //pause
        digitalPulse(txpin,0,0);
        digitalWrite(txpin,0);
    }
    
    
    
    
    [#define](http://forum.espruino.com/sear­ch/?q=%23define) ListenST 1
    [#define](http://forum.espruino.com/sear­ch/?q=%23define) rxpin 19
    
    int lastPinState;
    unsigned long lastPinHighTime;
    unsigned long lastPinLowTime;;
    unsigned long lastTempHighTime=0;
    unsigned long lastTempLowTime=0;
    unsigned long rxdata;
    int lastTempPinState;
    int bitsrx;
    int rxing;
    int MyState;
    unsigned long curTime;
    
    void setup() {
            lastPinState=0;
            lastPinLowTime=0;
            lastPinHighTime=0;
            rxdata=0;
            bitsrx=0;
            rxing=0;
            MyState=2;
        Serial.begin(9600);
    }
    
    void loop() {
            curTime=micros();
        onListenST();
    }
    void onListenST() {
        int pinState=digitalRead(rxpin);
                if (pinState==lastPinState) {
            return;
        } else {
                  lastPinState=pinState;
            }
        if (pinState==0) {
            lastPinLowTime=curTime;
            unsigned long bitlength=lastPinLowTime-lastPinHighTime­;
                    //Serial.println("bitlength:");
                    if (bitlength < 1400 && bitlength > 600) {
                      //Serial.println(bitlength);
                    }
            if (bitlength > 1500) {
                //bogus bit
                            // Serial.println(bitlength);
                resetListen();
                return;
            } else if (rxing==1) {
                            //Serial.print("Receiving");
                           // Serial.println(bitlength);
                if (bitlength > 575 && bitlength < 750) {
                    rxdata=rxdata<<1;
                    Serial.print("F");
                                    Serial.println(bitlength);
                } else if (bitlength > 1200 && bitlength < 1350 ) {
                    rxdata=(rxdata<<1)+1;
                    Serial.print("T");
                                    Serial.println(bitlength);
                } else {
                    //Serial.println(bitlength);
                    resetListen();
                    return;
                }
                bitsrx++;
                if (bitsrx==8) {
                    Serial.println("Got 8 bits");
                    Serial.println(rxdata);
                    resetListen();
                }
                return;
            }   
        } else {
            lastPinHighTime=curTime;
                    if (lastPinHighTime-lastPinLowTime > 1900 && lastPinHighTime-lastPinLowTime <2100) {
              //Serial.println("Starting");
                      rxing=1;
                      return;
                    }
            if (lastPinHighTime-lastPinLowTime > 700 && rxing==1) {
                            //Serial.print("oddly long delay during rx");
                    //Serial.println(lastPinHighTime-lastPin­LowTime);
                resetListen();
                return;
            }
        }
    }
    
    void resetListen() {
            //Serial.print("end");
        bitsrx=0;
        rxdata=0;
            rxing=0;
    }
    
    

    Obviously, I need to do some work on both ends.

    Do you have any thoughts on how to improve the Espruino side, while making sure that the code executes fast enough?

  • Thanks for your post... it is something on my list for having 'close'-remote sensors - sitting on a ATtiny85 or other Espruino and communicate 'cordless' with Espruino board for collection/logging and display.

  • Cool :-) That sounds like you're going the opposite direction, though - from a tiny, to an Espruino - I can see lots of uses for that, I might need that too.

    I'll keep you (and the rest of the forum) abreast of the progress.

  • Great! In terms of making it simpler/faster, what about:

    function sendTest2(data) {
         var d = digitalPulse, p=txpin;
         //20ms long training burst. Had crap results with shorter ones.
         for (i = 0; i < 20; i++) { 
            d(p,1,0.5); 
            d(p,0,0.5); 
        } 
        d(p,1,0.5); //end training burst
        d(p,0,2);   //sync
       //send 1s or 0s, and pause
        data.forEach(function(v) {
          d(p,1,v?1.3:0.7); 
          d(p,0,0.5);
        });
        // wait for finish
        d(p,1,0);
    }
    var data = [0,1,0,1,1,0,1,1];
    sendTest2(data);
    

    So:

    • keeping comments out of loops helps with speed
    • copying digitalPulse into the function and using a small variable name helps
    • by pulsing to 1 at the end, you shouldn't need the digitalWrite(0) at the end

    I'm actually really surprised you need the training pulses... Personally I'd have just sent out one long pulse at the start:

    function sendTest2(data) {
         var d = digitalPulse, p=txpin;
         d(p,1,5);
         d(p,0,0.5);
         //send 1s or 0s, and pause
        data.forEach(function(v) {
          d(p,1,v?1.3:0.7); 
          d(p,0,0.5);
        });
        // wait for finish
        d(p,1,0);
    }
    

    Then hopefully you could just detect that pulse in the receiver and use it as a 'start of frame' - I think it's just a longish burst of transmit that is needed to let the receiver get its gain set properly. It should work, but then I guess it may not :)

    About going the other way - I'm actually really considering trying to build in some simple functionality for reading radio/IR signals (effectively specifying min + max pulse widths for a start pulse, 0 and 1). That'd let it handle noise a lot better, and would mean it could go to sleep right after processing a pulse - it would massively increase battery life on the receiver end.

  • What I was told on the Arduino forum is that the the receivers autoadjust their gain towards a ~50% duty cycle, so if the training burst is a solid pulse, that causes it to crank down the gain down too much.

    About going the other way - I'm actually really considering trying to build in some simple functionality for reading radio/IR signals (effectively specifying min + max pulse widths for a start pulse, 0 and 1)

    Oh cool!

  • the receivers autoadjust their gain towards a ~50% duty cycle

    Ahh - that makes a lot of sense. Thanks for letting me know! It would explain why the Oregon Scientific thing in the other thread works that way.

    Interesting that the remote control sockets don't work like that. It looks like they just send the same packet lots of times, so effectively use the first packet as a way to autoadjust the receiver - it is roughly 50% duty cycle after all!

    I guess it's not actually such a bad idea... Nice and simple...

  • A nice 'out of the box' thinking... - or, more precisely - 'all things considered' get's you two birds with one stone... and not even throwing the stone... ;-)

  • I've reworked both sides for a 32-bit message including a checksum (32 is nice, since I can receive it by leftshifting it onto an unsigned long), going to test it tonight.

    I'm going to have to make some decisions about how many bits to use for the address (so I can have multiple devices in my room, each looking for a different address) and how many to use for the checksum (thus determining how many I've got left for data).

  • Test sending code on Espruino side - this was what I was using for testing different training bursts. Can also just be used to benchmark signal integrity. Sends 32-bit packets - 28 bits data, 4 bits checksum. Bad checksums are rare, but not unheardof.

        var txpin=A1;
    
    function sendCmd(add,cmd,param,ext) {
      ext=ext?ext&15:0;
        var csc=add^cmd^param;
        csc=(csc&15)^(csc>>4)^ext;
        var b=(add<<20)+(cmd<<12)+(param<<4)+ext;
        var d = digitalPulse;
        var p=txpin;
        for (i = 0; i < tp; i++) {
            d(p,1,op); 
            d(p,0,zp); 
        } 
        d(p,1,0.5); //end training burst
        d(p,0,2);
        //send 1s or 0s, and pause
        for (j=27;j>-1;j--) {
            d(p,1,((b>>j)&1)?1.1:0.6); 
            d(p,0,0.65);
        }
        for (j=3;j>-1;j--) {
            d(p,1,((csc>>j)&1)?1.1:0.6); 
            d(p,0,0.65);
        }
        // wait for finish
        d(p,0,0);
      digitalWrite(p,0);
    }
    
    function testRun(train,opp,zpp,number,interval) {
      tp=train;
      op=opp;
      zp=zpp;
      var ad=Math.round(255*Math.random());
      var pr=Math.round(255*Math.random());
      var cm=Math.round(198*Math.random());
      var ex=Math.round(16*Math.random());
      inter=setInterval("sendCmd(ad,cm,pr,ex);­ad=pr=Math.round(255*Math.random());cm=M­ath.round(198*Math.random());ex=Math.rou­nd(16*Math.random());",interval);
      setTimeout("clearInterval(inter);",numbe­r*interval);
      setTimeout("sendCmd(31,200,150,10);conso­le.log('done')",(number+5)*interval);
    }
    
    

    Test receiving code on Arduino side:

    
    [#define](http://forum.espruino.com/sear­ch/?q=%23define) rxpin 19
    
    int lastPinState;
    unsigned long lastPinHighTime;
    unsigned long lastPinLowTime;;
    unsigned long lastTempHighTime=0;
    unsigned long lastTempLowTime=0;
    unsigned long rxdata;
    int lastTempPinState;
    int bitsrx;
    int rxing;
    int MyState;
    unsigned long curTime;
    int count=0;
    int badcsc=0;
    
    
    void setup() {
            lastPinState=0;
            lastPinLowTime=0;
            lastPinHighTime=0;
            rxdata=0;
            bitsrx=0;
            rxing=0;
            MyState=2;
        Serial.begin(9600);
    }
    
    void loop() {
            curTime=micros();
        onListenST();
    }
    
    void onListenST() {
        int pinState=digitalRead(rxpin);
            if (pinState==lastPinState) {
            return;
        } else {
                  lastPinState=pinState;
            }
        if (pinState==0) {
            lastPinLowTime=curTime;
            unsigned long bitlength=lastPinLowTime-lastPinHighTime­;
            if (bitlength > 1500) {
                resetListen();
                return;
            } else if (rxing==1) {
                if (bitlength > 475 && bitlength < 650) {
                    rxdata=rxdata<<1;
                    //Serial.print("F");
                    //Serial.println(bitlength);
                } else if (bitlength > 1000 && bitlength < 1150 ) {
                    rxdata=(rxdata<<1)+1;
                    //Serial.print("T");
                                    //Serial.println(bitlength);
                } else {
                    resetListen();
                    return;
                }
                bitsrx++;
                if (bitsrx==32) {
                    Serial.print("Got 32 bits ");
                    Serial.print((rxdata>>24)&0xFF);
                    Serial.print(":");
                    Serial.print((rxdata>>16)&0xFF);
                    Serial.print(":");
                    Serial.print((rxdata>>8)&0xFF);
                    Serial.print(":");
                    Serial.println((rxdata)&0xFF);
                    Serial.println(rxdata);
                    parseRx(rxdata);
                    resetListen();
                }
                return;
            }   
        } else {
            lastPinHighTime=curTime;
                    if (lastPinHighTime-lastPinLowTime > 1900 && lastPinHighTime-lastPinLowTime <2100 && rxing==0) {
                      rxing=1;
                      return;
                    }
            if (lastPinHighTime-lastPinLowTime > 800 && rxing==1) {
                            Serial.println(bitsrx);
                resetListen();
                return;
            }
        }
    }
    
    void resetListen() {
            //Serial.print("end");
        bitsrx=0;
        rxdata=0;
            rxing=0;
    }
    void parseRx(unsigned long rxd) {
        Serial.println("Parsing: ");
        unsigned char rcvB0=(rxd>>24)&0xFF;
        unsigned char rcvCmd=(rxd>>16)&0xFF;
        unsigned char rcvParam=(rxd>>8)&0xFF;
        unsigned char rcvB3=(rxd)&0xFF;
        unsigned char rcvAdd=rcvB0&0x3F;
        unsigned char rcvExtParam=(rcvB3>>4);
        unsigned char calccsc=(rcvB0^rcvCmd^rcvParam);
        calccsc=(calccsc&15)^(calccsc>>4)^rcvExt­Param;
        rcvB3=rcvB3&15;
        
        if (calccsc==rcvB3) {
                    if (rcvCmd==200) {
                        Serial.print(count);
                        Serial.println(" received.");
                        count=0;
                        Serial.print(badcsc);
                        Serial.println(" .");
                        badcsc=0;
                    } else {
                        count++;
                    }
            Serial.println("Valid transmission received!");
        } else {
            Serial.print(calccsc);
            Serial.println("No good!");
            badcsc++; 
        }
    }
    
    

    I settled on a 20ms training burst with 0.4ms up 0.4ms down. Bit lengths were adjusted a bit from earlier to better balance the duty cycle, which might become more relevant if i was sending longer packets. I decided to structure the command as:

    2 bits (reserved)
    6 bits (device address)
    8 bits (command)
    8 bits (params)
    4 bits (extended params)
    4 bits (checksum)

    
    var txpin=A1;
    
    
    function sendCmd(add,cmd,param,ext) {
      ext=ext?ext&15:0;
        var csc=add^cmd^param;
        csc=(csc&15)^(csc>>4)^ext;
        var b=(add<<20)+(cmd<<12)+(param<<4)+ext;
        var d = digitalPulse;
        var p=txpin;
        for (i = 0; i < 25; i++) {
            d(p,1,0.4); 
            d(p,0,0.4); 
        } 
        d(p,1,0.5); //end training burst
        d(p,0,2);
        //send 1s or 0s, and pause
        for (j=27;j>-1;j--) {
            d(p,1,((b>>j)&1)?1.1:0.6); 
            d(p,0,0.65);
        }
        for (j=3;j>-1;j--) {
            d(p,1,((csc>>j)&1)?1.1:0.6); 
            d(p,0,0.65);
        }
        // wait for finish
        d(p,0,0);
      digitalWrite(p,0);
    }
    
    

    And the parserx will be:

    
    void parseRx(unsigned long rxd) {
        Serial.println("Parsing: ");
        unsigned char rcvB0=(rxd>>24)&0xFF;
        unsigned char rcvCmd=(rxd>>16)&0xFF;
        unsigned char rcvParam=(rxd>>8)&0xFF;
        unsigned char rcvB3=(rxd)&0xFF;
        unsigned char rcvAdd=rcvB0&0x3F;
        unsigned char rcvExtParam=(rcvB3>>4);
        unsigned char calccsc=(rcvB0^rcvCmd^rcvParam);
        calccsc=(calccsc&15)^(calccsc>>4)^rcvExt­Param;
        rcvB3=rcvB3&15;
        if (calccsc==rcvB3) {
            if (rcvAdd==MyAddress) {
                Serial.println("Valid transmission received!");
                //Handle the command
            } else {
                Serial.println("Wrong address - not for me");
            }
        } else {
                    Serial.print(calccsc);
            Serial.println("No good!");
                    badcsc++; 
        }
    }
    
    

    Also - what a difference an antenna makes. Just poking a dupont male jumper into that hole (no solder or anything) and letting it dangle has a huge effect on packet loss...

  • Nothing other than incremental progress to report, though making the prototype board was interesting (still driving it off some knockoff arduino, instead of a tiny - I still need the serial debugging; I'm constantly missing the interactive development that we have on the Espruino - but that's what I get for wanting a $6 BOM including the MCU).
    That board is the closest I've done to a 2-layer board at home - the big part with the heatsinks is at +5v (also serves as heatsink), the other part is ground. They were not done via toner transfer, but by masking it off with tape by hand. One thing that's really surprising to me is just how flexible that 0.012" board is - I can just see the board flexing and all the parts flying off.

    I've been trying to flesh out the code for the slaves so they can react to temperature and light levels (I want them to watch the light opposite where their emitter is pointed, so when the rest of the room lights are off, these will turn off - but I want to do it in an extensible way, and also to streamline the process of making different kinds of slaves.

    Once that's sorted, I'll begin work on the much more interesting issue of receiving on the Espruino, and maybe even requesting and sending back data (for example, to make a remote sensor that will send back temperature or whatever data).

  • Man, I just can't seem to get receiving to work on the Espruino.

    I've got transmit and receive working on arduino, and transmit working on Espruino...

    Does anyone have any idea why my code isn't working?

    I'm using the same protocol that I posted the transmit code for above - it is unchanged.

    I based the receiver code on the demo code for the remote sockets. I just can't get it to work.

    With the console.log()'s in, it was constantly reporting things that looked like the start of a message (I don't recall this happening on the Arduino - there were a few false starts, but nothing like this many). With or without logging, it bogs the Espruino down something fierce.

    
    var t,n;
    var b;
    var d;
    var wr;
    var wf;
    
    // When the signal rises, check if it was after ~2ms of delay - if so (and if we have a code) display it.
    function sigOn(e) {
      var d = e.time-t;
      if (d>0.0017 && d<0.0022) {
        //console.log("starting receive "+d);
        n=0;
        b=0;
        c=0;
      }
      t = e.time;
    }
    
    // When the signal falls, measure the length of our pulse. 
    // If it was within range, record a 1 or a 0 depending on the length. 
    // If it wasn't in range, zero it
    function sigOff(e) {
      var d = e.time-t;
      t = e.time;
      if (d>0.0004 && d<0.0013){
        b++;
        if (b < 28){
          n = (n<<1) | ((d>=0.0007)?1:0);
        } else {
          c = (c<<1) | ((d>=0.0007)?1:0);
        }
      } else if (b>0) {
        n=0;
        b=0;
        c=0;
        if (b > 8) {
          console.log(b);
        }
      }
      if (b==32) {
        parseRx();
      }
    }
    
    function parseRx() {
      var ext=n&0x0F;
      var b2=(n>>4)&0xFF;
      var b1=(n>>12)&0xFF;
      var b0=(n>>20)&0xFF;
      var csc=c&0x0F;
      ncsc=b0^b1^b2;
      ncsc=(ncsc&0x0F)^((ncsc>>4)&0x0F)^ext;
      console.log("B0:"+b0+" B1:"+b1+" B2:"+b2+" ext:"+ext+" csc:"+csc+" calccsc:"+ncsc);
      if (ncsc==csc) {
        processRx(b0,b1,b2,ext);
      } else {
        console.log("Bad checksum!");
      }
    }
    
    function startListen() {
      wr=setWatch(sigOn,C6,{repeat:true,edge:"­rising"});
      wf=setWatch(sigOff,C6,{repeat:true,edge:­"falling"});
      console.log("Listening started");
    }
    
    function stopListen() {
      clearWatch(wr);
      clearWatch(wf);
      n=0;b=0;c=0;
    }
    
    

    Any thoughts?

  • Have you looked at the signal with a scope? I guess there's probably quite a lot of noise.

    It might be that the time taken to execute the code means that not everything gets processed in time and the input buffer overflows. You could check that with E.getErrorFlags()

    You could try having a single watch (which would halve the effort Espruino was having to do). I'd suggested this code in another thread, and something like that might work?

    Also, I'd really consider replacing:

        b++;
        if (b < 28){
          n = (n<<1) | ((d>=0.0007)?1:0);
        } else {
          c = (c<<1) | ((d>=0.0007)?1:0);
        }
    

    with:

    n="";
    // ....
    n+=(d>0.0007)?1:0;
    

    and then just working out what c should be later on with .substr.

    That'll execute a lot faster, and has the bonus that you can just check the length of 'n' rather than keeping a separate variable.

    I guess you could also use an Espruino (or the same one?) to generate a signal - without using the radio modules. That way you can make sure the decoder works before you start having to deal with all the noise coming in.

  • yup, i'm getting FIFO_FULL errors even with logging off.

    Current test code:

    
    var n="";
    var t;
    var b;
    var d;
    var wr;
    var wf;
    var rxing=0;
    var lt;
    
    function sigOff(e) {
      d=e.time-lt;
      lt=e.time;
      if (e.state) {
        if (d>0.0017 && d<0.0022) {
          rxing=1;
        }
      } else if (rxing) {
        if (d>0.0004 && d<0.0013){
          n+=(d>0.0008)?1:0;
        }else{
          n="";
          rxing=0;
        }
        if (n.length==32) {
          console.log(n);
          console.log("We made it!");
        }
      }
    }
    
    function startListen() {
      //wr=setWatch(sigOn,C6,{repeat:true,edge­:"rising"});
      wf=setWatch(sigOff,C6,{repeat:true,edge:­"both"});
      console.log("Listening started");
    }
    
    

    Basically, it seems that the noise comes in faster than the Espruino can process it, so it's bogged down before a signal even gets transmitted. I think the reason it's getting as many false starts as it is, is that it's missing intervening noise, and this gap is mistaken for the pause at the start of the transmission. Even the training burst could be contributing...

    It works if it's connected to the sender with a wire, which confirms that the noise is likely the problem.

  • The only answer to this is now a piece of inline assembler that listens for/detects a valid preamble and then sends an event to/calls JavaScript code to read and process the 'good sound'. Looking forward to see this 'ENI' (...like JNI) example mastered and published... ;-)

  • I think you may still be able to get it faster. I'd forgotten that the code I suggested triggered on both edges. You may be able to use 'lastTime' to measure the pulse width, while only triggering on the falling edge:

    function sigOff(e) {
      var d=e.time-e.lastTime;
      if (d>0.0004 && d<0.0013) n+=(d>0.0008)?1:0;
      else{
        if (n.length==32) console.log(n);
        n="";
      }
    }
    
    wr=setWatch(sigOn,C6,{repeat:true,edge:"­falling"});
    

    You may also be able to use debounce to remove the check for small pulses, but I'd try that code first. it does rely on finding an abnormal pulse after the data is sent, but you can pretty much rely on that - otherwise I guess you could have an interval that checked the length of n every 100ms.

    I'd be interested to know how it goes. If we get something working well, I'd really like to turn it into a module that others can use.

  • Well I'll be damned. Works like a charm, despite the fact that it doesn't even try to look for the sync pulse, or expunge munged packets on the basis of pulses of the wrong length... Edit: oh ya, you do ditch received data on the basis of bad lengths - that makes more sense..

    It does still throw up the FIFO_FULL error flag though (also, you can just forget about typing stopListen if doing it interactively - while listening, it barely responds - i got 1 character in each time it successfully read a transmission)

    I guess the next step is to demonstrate two-way communication with a pair of them.

    
    var n="";
    var wr;
    
    function sigOff(e) {
      var d=e.time-e.lastTime;
      if (d>0.0004 && d<0.0013) n+=(d>0.0008)?1:0;
      else{
        if (n.length==32)  parseRx(n);
        n="";
      }
    }
    
    function parseRx(rcv) {
      console.log(rcv);
      var ext=parseInt(rcv.substr(24,4),2);
      var b2=parseInt(rcv.substr(16,8),2);
      var b1=parseInt(rcv.substr(8,8),2);
      var b0=parseInt(rcv.substr(0,8),2);
      var csc=parseInt(rcv.substr(28,4),2);
      ncsc=b0^b1^b2;
      ncsc=(ncsc&0x0F)^((ncsc>>4)&0x0F)^ext;
      console.log("B0:"+b0+" B1:"+b1+" B2:"+b2+" ext:"+ext+" csc:"+csc+" calccsc:"+ncsc);
      if (ncsc==csc) {
        clearWatch(wf);
        //processRx(b0,b1,b2,ext);
      } else {
        console.log("Bad checksum!");
      }
    }
    
    function startListen() {
      wf=setWatch(sigOff,C6,{repeat:true,edge:­"falling"});
      console.log("Listening started");
    }
    
    function stopListen() {
      clearWatch(wf);
      n="";
    }
    
    

    This is still not really suitable for remotely controlling the Espruino, since it practically hangs when not receiving - but it's certainly fine for receiving data that it's expecting, which I think is the more attractive use case anyway.

  • Glad it's going! Might be worth trying debounce? that'll do a lot of processing natively which might help matters.

    This is definitely something I want to work on though, so if you have any ideas about additions to Espruino that might help with this I'd be all ears... even better if it's something general that might have some use for other things.

    I'm sort of considering a 'soft usart' as well, so it's possible that all of this could tie in to a kind of general purpose signal decoder.

  • Oh, I hadn't thought of that. So debounce:0.1 is supported? I certainly need less than 1ms of debounce. I always forget that in Espruino, we can usually pass decimal values to things and have it work.

    I'll try that.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

433mhz Espruino <-> Arduino

Posted by Avatar for DrAzzy @DrAzzy

Actions