RFM12B & RFM69CW

Posted on
  • Has anyone done anything with these on the Espruino platform?
    They are used extensively in other projects it would be handy to have a module for them.

  • Personally I haven't, but I'd be very interested if someone did produce a module for them. It doesn't look hard. I'm not sure what they add over the NRF modules though?

    Ideally we'd come up with some kind of shared 'low power radio' module that would use either that or the NRF, and would handle syncing transmitters/receivers so that you didn't have to have the receiver on all the time (which draws 11mA).

  • They operate at a lower radio frequency and you can get quite a bit more distance on them.
    I have one of the wireless modules here so maybe I will have a play around. I guess I just need to connect it up to the SPI interface and work from there...

  • Ahh, good point. Yes - that'd make a big difference...

  • I had a look but if I'm honest I don't know where to start.

    Once its connected is there any way I can just test by reading some information on it?

  • Which one are you trying, the RFM12B?

    The info you need will be in the datasheet and the arduino library

    You can follow the steps that the library uses to initialise: https://github.com/LowPowerLab/RFM12B/blob/master/RFM12B.cpp#L114

    Looks like the XFER function's equivalent in Espruino is just:

    function XFER(cmd) {
     SPI1.send([cmd>>8,cmd], cs_pin);
    }
    

    so you can start off with:

    var C = {
     RF_SLEEP_MODE : 0x8205,
     RF_WAKEUP_MODE : 0x8207,
     RF_TXREG_WRITE : 0xB800
    };
    
    function init() {
     // setup spi
     // then...
      XFER(0x0000); // intitial SPI transfer added to avoid power-up problem
      XFER(C.RF_SLEEP_MODE); // DC (disable clk pin), enable lbd
      
      // wait until RFM12B is out of power-up reset, this takes several *seconds*
      XFER(C.RF_TXREG_WRITE); // in case we're still in OOK mode
      while (digitalRead(RFM_IRQ) == 0)
        XFER(0x0000);
     // ...
    }
    

    So if the function finishes then at least you've had some success in talking to the chip and getting it to lower the IRQ line.

    That last bit is nasty though, and if it works I'd consider re-writing it as:

    if (!digitalRead(RFM_IRQ)) {
      console.log("IRQ shouldn't be low right now!");
      return;
    }
    var interval = setInterval(function() {XFER(0x0000);}, 10);
    setWatch(function() {
      clearInterval(interval);
      console.log("IRQ lowered");
      // do next stuff
    }, RFM_IRQ, {edge:"falling", repeat:false});
    
  • Progress...

    function XFER(cmd) {
    SPI1.send([cmd>>8,cmd], B8);
    }
    
    var C = {
    RF_SLEEP_MODE : 0x8205,
    RF_WAKEUP_MODE : 0x8207,
    RF_TXREG_WRITE : 0xB800
    };
    
    function init() {
    // setup spi
    SPI1.setup({sck:B3,miso:B4,mosi:B5});
    // then...
    XFER(0x0000); // intitial SPI transfer added to avoid power-up problem
    XFER(C.RF_SLEEP_MODE); // DC (disable clk pin), enable lbd
    // wait until RFM12B is out of power-up reset, this takes several *seconds*
    XFER(C.RF_TXREG_WRITE); // in case we're still in OOK mode
    while (digitalRead(B9) === 0)
    XFER(0x0000);
    // ...
    }
    

    Okay so good progress.
    If I load the above code then digitalRead(B9) the interpreter returns 0.
    Run funtion init()
    Checking digitalRead(B9) returns 1

  • great! I guess it's just a matter of hacking through and implementing the rest of the initialisation code.

    I just realised I got the polarity wrong in my last bit of code :)

  • I knew it was too good to be true!

    On further investigation it appears as soon as I send the first command, in this case when init() is called the first command that is sent is 0x0000, the IRQ pin goes high and stays there unless I cycle the power to the module.

    Anyone got any suggestions?

  • Can I just check that these connections are correct.

    Espruino --> RFM12B
    SCK (B3) ----- SCK
    MISO (B4) ----- SDI
    MOSI (B5) ----- SDO
    NSS_PIN (B8) ----- nSEL (active low)
    IRQ (B9) ----- nIRQ (active low)

  • It could be the MISO and MOSI are reversed?

  • That's weird. So I started again from scratch, hence the pulling all the wires out and making sure I had got the physical connections correct.

    @TrapperBob, I tried swapping the MISO and MOSI but that is definitely not it. Definitely worth a try though!

    I setup a setWatch on the IRQ pin to log to the console when the state changes (rising and falling).
    Now when I send multiple commands I am receiving plenty of IRQ level changes on the console. I'm sure this wasn't working before and as far as I can understand this is proof that the Espruino is at least talking to the module and it is responding correctly??

    Looking at the Arduino libraries for the RFM12B, I think quite a bit of the code is related to some sort of software SPI. We don't have to worry about this on the Espruino :)

  • @StuntMonkeh it seems like good news if the IRQ line is moving.

    Yes, IIRC quite a lot of the top part of the RFM12B file is for bit-bashed SPI - which isn't needed :)

  • WHAT THE HELL!!!! Its stopped working, I unplugged the board for some reason and then had to plug back in and reload the code and now it doesn't work.

    This is what I have. I was simply running spiInit() and it was triggering the IRQ up and down.

    var C = {
      // maximum transmit / receive buffer: 3 header + data + 2 crc bytes
      RF_MAX : (RF12_MAXDATA + 5),
      
      // RF12 command codes
      RF_RECV_CONTROL : 0x94A0,
      RF_RECEIVER_ON : 0x82DD,
      RF_XMITTER_ON : 0x823D,
      RF_IDLE_MODE : 0x820D,
      RF_SLEEP_MODE : 0x8205,
      RF_WAKEUP_MODE : 0x8207,
      RF_TXREG_WRITE : 0xB800,
      RF_RX_FIFO_READ : 0xB000,
      RF_WAKEUP_TIMER : 0xE000,
      
    // RF12 status bits
      RF_LBD_BIT : 0x0400,
      RF_RSSI_BIT : 0x0100,
    
    // bits in the node id configuration byte
      NODE_BAND : 0xC0, // frequency band
      NODE_ID : 0x1F, // id of this node, as A..Z or 1..31
      
      RETRIES : 8, // stop retrying after 8 times
      RETRY_MS : 1000, // resend packet every second until ack'ed
    
    };
    
    var RFM_IRQ = B9;
    var SPI_CS = B8;
    var SPI_MOSI = B5;
    var SPI_MISO = B4;
    var SPI_SCK = B3;
    
    var nodeid; // address of this node
    var group; // network group
    var frequency; // Frequency within selected band
    var rxfill; // number of data bytes in rf12_buf 
    var rxstate; // current transceiver state
    var ezInterval; // number of seconds between transmits
    var ezSendBuf = new Array(RF12_MAXDATA); // an empty array of length 100
    var ezSendLen; // number of bytes to send
    var ezPending; // remaining number of retries
    var ezNextSend = new Array(2); // when was last retry [0] or data [1] sent
    var rf12_crc; // running crc value
    var rf12_buf = new Array(RF_MAX); // recv/xmit buf, including hdr & crc bytes
    var rf12_seq; // seq number of encrypted packet (or -1)
    var rf12_fixed_pkt_len; // fixed packet length reception
    var seqNum; // encrypted send sequence number
    var cryptKey = new Array(4); // encryption key to use
    //void (*crypter)(uint8_t); // does en-/decryption (null if disabled)
    
    function XFER(cmd) {
      SPI1.send([cmd>>8,cmd], SPI_CS);
    }
    
    function spiInit() {
      SPI1.setup({sck:B3,miso:B4,mosi:B5}); // setup SPI
      XFER(0x0000); // intitial SPI transfer added to avoid power-up problem
      XFER(C.RF_SLEEP_MODE); // DC (disable clk pin), enable lbd
      // wait until RFM12B is out of power-up reset, this takes several *seconds*
      XFER(C.RF_TXREG_WRITE); // in case we're still in OOK mode
      XFER(0x80C7 | (band << 4)); // EL (ena TX), EF (ena RX FIFO), 12.0pF 
      XFER(0xA000 + frequency); // 96-3960 freq range of values within band 
      XFER(0xC606); // approx 49.2 Kbps, i.e. 10000/29/(1+6) Kbps
      XFER(0x94A2); // VDI,FAST,134kHz,0dBm,-91dBm 
      XFER(0xC2AC); // AL,!ml,DIG,DQD4 
      if (group !== 0) {
          XFER(0xCA83); // FIFO8,2-SYNC,!ff,DR 
          XFER(0xCE00 | group); // SYNC=2DXX; 
      } else {
          XFER(0xCA8B); // FIFO8,1-SYNC,!ff,DR 
          XFER(0xCE2D); // SYNC=2D; 
      }
      XFER(0xC483); // @PWR,NO RSTRIC,!st,!fi,OE,EN 
      XFER(0x9850); // !mp,90kHz,MAX OUT 
      XFER(0xCC77); // OB1,OB0, LPX,!ddy,DDIT,BW0 
      XFER(0xE000); // NOT USE 
      XFER(0xC800); // NOT USE 
      XFER(0xC049); // 1.66MHz,3.1V
    }
    
    setWatch(function() {
      console.log("IRQ State");
      // do next stuff
    }, RFM_IRQ, {edge:"both", repeat:true});
    
  • Did you have some code in there that had been save()d already? That could be causing you problems I guess ...

    Maybe there is some other pin (a reset pin?) that needs its state changing first...

    Also aren't you supposed to wait for it to initialise at some point? You don't appear to be doing that...

    The code is looking good though. It'd make a module really easily.

  • I figured I must have sent the RFM12B module some commands that must have caused it to jump into life.

    I have tried sending just the first two commands and then manually sending the rest. No luck. I have had a look at different uses in other projects, all wired the same way. No reset pin.

    I had another go tonight, starting from scratch rewiring all over again but I'm back square one with the IRQ line just being triggered high as soon as I send (0x0000).

    I tried just sending the first two commands

    setWatch(function() {
      console.log("IRQ State");
      // do next stuff
    }, B9, {edge:"both", repeat:true});
    
    function XFER(cmd) {
      SPI1.send([cmd>>8,cmd], B8);
    }
    
    SPI1.setup({sck:B3,miso:B4,mosi:B5}); // setup SPI
    
    function init(){
      XFER(0x0000);
      XFER(0x8205);
    }
    
  • I'm looking at the datasheet, and it looks like the nIRQ pin is active low. Furthermore, in the case of a power-on reset, it sounds like the nIRQ should be reset by simply reading the status:

    • POR: both the nIRQ pin and status bit can be cleared by the read status command

    As I interpret that, you're getting correct behavior, so far. nIRQ starts out getting pulled low, then you read the status, which clears the interrupt, and IRQ goes high again. It wasn't clear to me that a RFM12B that's just sitting there will generate IRQ activity - especially when all the radio-related functionality was just turned off (with 0x8205)

    Why aren't you recording what the RFM12B is sending back? You should certainly be getting data back when you send 0x0000. I think looking for this would be a better way of seeing whether you're communicating with the device.

    function XFER(cmd) {
      console.log(SPI1.send([cmd>>8,cmd], B8));
    }
    
  • @DrAzzy - Added the console.log part as suggested.
    This is what the console returns.

    >digitalRead(B9)
    =0
    >init()
    [64,0]
    [0,0]
    =undefined
    IRQ State
    >digitalRead(B9)
    =1
    > 
    
  • I invested in a cheapo Saleae clone logic analyser so I can see what's going.

    It was my understanding that was lacking, its starting to make a little more sense now :)

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

RFM12B & RFM69CW

Posted by Avatar for StuntMonkeh @StuntMonkeh

Actions