RFM12B library

I’ve been using the RF12 library from Jeelabs for some time for my Moteino testing. This worked just fine and it was a great starting point. However some things were really confusing and I spent a lot of time redoing the same thing over and over again (eg. copy paste from known working code) just because there was a lot of code-overhead to do simple things like sending, receiving, and ACK management, and of course I couldn’t remember any of the functions or macros. Right from start, the need emerged to tweak it into a more flexible and more configurable library, so I kept hacking and modding it until it dawned on me… a new library had to be born. So I decided to completely rewrite it, and wrap the useful functionality in a dedicated C++ class. I modified some of the core features of the Jeelabs version, like adding another header byte to allow 7-bit source and destination addresses (Jeelabs only supports either source or destination in an attempt to save 1 byte), and allow low level configuration of the radio. This yielded a clean and easy to use, yet powerful library (at least it made my life easy). Here’s a summary:

  • easy API with a few simple functions for basic usage
  • 127 possible nodes on 256 possible networks
  • 66 128 bytes max message length
  • customizable transmit power (8 levels) for low-power transmission control
  • customizable air-Kbps rate allows fine tuning the transmission reliability vs speed (transmitting slower is more reliable but takes more time which implies more power usage)
  • Sleep/Wakeup functionality for power saving
  • Low battery detector with customizable low voltage threshold
  • Interrupt driven
  • Support for targeted ACK instead of broadcasted ACK (possible because of the new source byte in the header)
  • encryption with XXTEA algorithm by David Wheeler, adapted from http://en.wikipedia.org/wiki/XXTEA
  • Support for these chips: ATMega8 family (ATmega168, ATMega328) ATMega2560, ATMega1280, ATMega644P, ATTiny84, ATTiny44, ATMega32u4. So far only tested on ATMega 328/P
  • The source code and examples are on GitHub: RFM12 Library

I did some basic testing of the most common features. I’m posting this in hope that others will find it useful, start using it and provide some feedback. This code is also part of an effort to promote the Moteino wireless arduino clone and make it an ubiquitous platform for building very low cost internet of things.

Here is the packet structure for those interested:RFM12B_PacketStructThe CTL bit in the first header byte is set to 1 when the received packet represents an ACK. The ACK bit in the second header byte is set to 1 when a sender is requesting an ACK to the current packet.  NOTE: these bits are mutually exclusive (only either one can be set at one time), and an ACK packet can contain as much data as a normal packet – this would be useful in instances where the sent data is sent back with an ACK to be verified (even though the CRC check of each message will be an almost 100% guarantee of data integrity).

Here are diagrams for connecting the RFM12B transceiver radio to 3.3V or 5V Arduino clones nased on ATMega168/328:rfm12B--arduino-moteino-atmega328_3.3v_connections rfm12B--arduino-moteino-atmega328_5V_connections

81 thoughts on “RFM12B library

    • Hi Damon,
      The OOK functionality has been preserved. I have to say I haven’t used OOK at all so it’s not tested. I will have to refer you to any tutorials at JeeLabs for that.
      As far as I can tell there’s only 1 function in JeeLib for OOK ‘rf12_onOff’ and it is replaced by ‘RFM12B::OnOff’ in my version of the library. So I believe you should get the same results if you use it the same.
      -Felix

  1. In trying to compile Wattmote I have an error.. LowPower.h “File not Found” and a search of my computer leaves no resule I mmissed it somets… in the off hand chance I missed it somehow… I would Love to combine the RX and TX modules to make a “transceiver”… Any easy Idea’s

    Bob (Docedison @ Arduino Forum)

      • Yes I do understand the differences.. What I meant was a function that could tell the module when to transmit and when to receive or when receiving would interfere with critical processes, inhibit it for a more appropriate time.
        In this manner it would be trivial to attach a radio to any sketch/device.. Just add the specific SPI I/O and the radio and ‘code’. What I am extremely interested in is the cost of the radio PCB and it’s availability. I have a smal handful of ‘extra’ radio’s, 5 or 6

          • What about the RFM22 – 3 radio’s? and how’s your stock of Motino’s I would like to buy three tonight.

            Bob

          • I just got some RFM22s, I will start playing with these when i have some time.
            One of the parts supplier still hasn’t shipped (since the weekend when I placed the order) because of backlogs caused by the snow storm early this week. So looks like I might not get parts this week…out of my control. You may place a pre-order if you’d like and I’ll process it in the order it was received, or you may wait till I have stock again. Thanks.

  2. Got it.. as much as I harp about Mr Google… on the forum… I was too smart?… I needed to PM you to ask about what I should have done in the first place… All compiles now. Thank You Sir, hope to be testing later today…

    Bob (Docedison @ Arduino Forum)

  3. Hey there. Great project, just ordered a couple. I looked in github and couldn’t find a library “glossary” of sorts. Where can I ind one?
    Thanks :-)

  4. I struggled quite awhile to understand JeeLib and eventually got it all working. And I was a big fan of the JeeNode until I chanced upon the Moteino. That’s it, I’m hooked. Your comparison graphic says it all: what a bargain, good show! I’ll definitely be getting more. Would like more RAM if that can be arranged. I’ll be switching over my projects to use your library. A couple of them are already built with JeeNodes, a couple are Unos with RFM12Bs on proto-shields.

    p.s. I’m trying to help raise Moteino awareness in the Arduino community on my blog. I also started an internal email newsgroup at work, about 45 people so far. A little company called Tektronix, you might have heard of them ;-)

    • Thanks Mike for sharing! I used Tek equipment in school and loved it and I hope one day I will afford a Tek scope.

  5. Hi Felix,

    Quick question regarding radio.SetCS(), should that come before, or after radio.Initialize()? Or some place else?

    Thanks,
    Mike

  6. a bit more detail: I have two Moteinos (thanks!) and two JeeNodes, and they all work fine with your Send and Receive examples. But I also have two Unos, with custom RFM12B shields. They work fine with JeeLib, but so far I can’t get them to work with your RFM12B library. They use Arduino D9, instead of D10, for CS (a.k.a. SS). In JeeLib, I need to call rf12_set_cs() before rf12_initialize(). I’m not sure in your library? I’ve tried it before, after, and both before and after, but no luck. I took a quick look at your CPP file, and it looks like the radio.SetCS() should come before radio.Initialize(). Is there anything else I need to do? I vaguely remember seeing something, someplace, about D10 still be reserved for the SPI bus. I’m not using it for anything else, I just happened to use D9 on my shield. My next step will be to modify my shield to use D10. Or maybe it’s something else all together?

    • Frankly I haven’t tried the lib on other CS pins so it’s possible there’s a bug in the lib around that. I won’t be able to look into this right away. I would definitely call SetCS() before Initialize().

      • Hi Felix,
        I tested SetCS(), before Initialize(), in the Send sketch, on the Moteino. I can set it to 8, 9, or 10 and the Moteino works for all those settings. So it seems that SetCS() is effectively doing nothing? I’m stumped.
        Mike

      • Hi Felix,
        I found the reason: Initialize() sets cs_pin = SS_BIT
        I commented that line out, and now SetCS() works as expected. The downside, SetCS() is now _required_ before Initialize(). I’m sure you can come up with a more elegant solution.
        Mike

  7. Hi Felix,
    I just ordered a couple RFM12B-S2 Wireless Transceivers before I found your site. I was looking for some code that would compile first time so I would be ready to run when the RFM12B’s arrive.

    Just wanted to let you know after several hours of looking and testing….your programs were the first that compiled first time!! – I tried a few more of your samples and they did also –
    Amazing work – thanks for sharing!

    Rick

  8. Hi Felix,

    I am using two atmega328 and RFM12B and your arduino library. Each RFM12B is connected to one atmega328. One atmega328 is using your “Send” example and the second one is running your “Receive” example. The problem I have is that on the sender’s serial i get:

    “Sending[1]:ab – waiting for ACK…nothing…”

    and on the receiver’s serial i get:

    “Listening…
    BAD-CRC ”

    For atmega328 do i need to change anything in the header file? I am struggling to understand what can be going wrong.
    Any advice?

    Saud

    • How is the RFM12B connected to your atmegas?
      The Send/Receive should work. There’s also the Test_2way_gateway and Test_2way_node examples that are more comprehensive.
      Make sure you adjust the settings in the sketch to your hardware frequency.

      • I did try but I was getting the same thing. I bought a new rfm12b and I tried the same code with atmega328 (with 16Mhz external crystal). Now I dont get anything. The program seems to get stuck in radio.Initialize(NODEID, RF12_433MHZ, NETWORKID). I checked the rf module and I noticed that the nIRQ pin is staying high for ever (2.5V).

        Any idea what can be going wrong?

        • It could be an init delay issue. You have to have either a delay in the init function (I commented it out from the library) or do it using the fuses. Moteinos come with fuses that introduce enough delay for the RFM12B to startup correctly.

          • Can you please guide me through? How and how much delay do i need to add?

            Iv got atmega328 with external crystal 16Mhz (with 12pF capacitors). My fuse setting is as follwoing:

            EXTENED = 0xFD
            HIGH = 0xDE
            LOW = 0xFF

            Do i need to change this? sorry im a bit new to this.

            Thanks

          • Try ext:FD, hi:DC, lo:DE – this is what Moteino R2 uses. Otherwise add a delay(60) at the beginning of the init() function.

        • I tried changing the fuse settings and adding the delay but i still get the same problem. Do i need to edit anything in any of the files for atmega328? Do i have to change anything in the send and receive examples?

          • Are you using the latest version of this library? What is your wiring to RFM12B? The IRQ pin is active low, so it’s normal to be HIGH most of the time. Are you powering from 3.3V (and not 5v!)?
            Perhaps try the Jeelib RF12 library .. maybe there’s a bug in my library that I’m unaware of .. even though as long as you’re using the same wiring it should just work.

        • btw my circuit design is the same as you have shown in the diagram above except that the pins you have labellled are different from atmega328. ive got

          nSEL –> SS (pin 16) – with the potential divider
          SCK –> SCK (pin 19) – with the potential divider
          SDI –> MOSI (pin 17) – with the potential divider
          SDO –> MISO (pin 18)
          NIRQ –> INT0 (pin4)

          Grounds are all connected together (commened)
          for 3.3V im using a voltage regulator (L78L33). The atmega328 is powered from a power supply (fixed 5V points). I am using this 5V from the supply along with the L78L33 to regulate the voltage to 3.3V (3.25V to be exact). The ground of the regulator is commoned with the supply.
          Will the sender module go pass the initialising stage if i dont have the receiver module switched on? because my understanding is that in the initialisation the modules are trying to synchronise. Please correct me if im wrong.

      • I just tried the jeelabs library but that doesnt seem to work either. I tried the pingpong example and on the serial I am getting some random gibberish. Any more ideas?

        • I would double check the circuit, id neither libraries work something is not right in your circuit.

        • I have double and triple checked my circuit. When I flash any arduino examples (such as blink) it works fine. I even tried getting a new RFM12b and trying it but I got the same issue.

          If i have only one atmega328 + rfm12b switched on (lets say the sender), will it go past the initialization function? Because I think in the initialization the two modules synchronise. If one is not switched on then it wouldnt synchronise. Am i correct? Please correct me if im wrong as im only learning :)

          • There is no synchronization or anything like that. Again, there’s no indication there’s anything wrong with the library or examples, not having your hardware in front of me I’m afraid there isn’t much else I can advise…

  9. I’m attempting to use your library on my ATmega644p based board but it’s not working. CS pin connected to D18 (pin PC2), so I modified RFM12.h file like so:
    #elif defined(__AVR_ATmega644P__)
    #define RFM_IRQ 10
    #define SS_DDR DDRC
    #define SS_PORT PORTC
    #define SS_BIT 2

    Yet it still doesn’t work, it just hands at initialize :( Any suggestions?

    • Haven’t tried this on a 644 but make sure all the pins are right. The IRQ pin should be a hardware interrupt capable pin. Don’t forget the pins are defined as PORT bits not actual digital pin numbers.

  10. Thanks Felix!
    I think I have IRQ connected to correct pin. It’s hooked up to Pin10 which is PD2 (INT0) on my chip.
    From what I understand only PORT defined pin is SS right? Since I have SS_BIT set to 2, it should give me PORC2 and DDRC2…
    Not sure why it’s not working :(
    BTW, ATMega644 definition came from original Jeelabs library?

    • Yes the 644 section came from the Jeelib version. Do you have a logic analyzer to check if the signals are the right ones?
      Unfortunately I don’t have an atmega644 to test the lib. Perhaps googling for the same issue might reveal something …
      Adding Serial.print(…) statements in the library itself (at different points) could help discovering the issue (that’s my last resort when I debug something like this).
      Did you try the Jeelib version? Does that work with the same settings?

  11. Nah, Jeelib’s version doesn’t work either. I think it must be something with my circuitry. I’m using hex buffer to convert 5V data to 3V… I wish I had oscilloscope (and knew hot to use it too) :)

    • Yeah check your circuit. Again the library is interrupt based so that will make a difference. Just wondering why you’re using a 644 when you could use the atmega32u4, same in price, more timers/PWMs, USB, etc

      • YES!!! I got it working, my circuit was fine. Issue is buggy software written for ATMega644p. Never ever use Sanguino. I had so many issues with it (i.e. many ports defined incorrectly)… I switched to ATMega1280p (which is pin compatible with ATMega644p so no hardware changes needed) and with Optiboot it works like a charm! :)
        You can make your library compatible with it by chaning:
        #elif defined(__AVR_ATmega644P__)
        to
        #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)

  12. Hi Felix:
    Can you elaborate on how the CTL and ACK flags (in the packet header) work?

    Thanks, Don

    • Hi Don, I added the details you’re asking for in the body of the post, under the packet structure image.

  13. Felix,
    I’m trying to use Sleep(0) and Sleep(-1) method calls to disable/enable the RFM12B module on a JeeNode so I can access an SD card via SPI (to avoid any SPI collisions). I ran a simple test calling Sleep(0) and then transmitted a packet from a second JeeNode to the one with the sleeping RFM12B, but the ‘sleeping’ JeeNode detects and receives the packet, implying that the RFM12B isn’t actually asleep. Have you tested this method and this functionality, or am I missing something here?

    Thanks, Bill

    • Please use radio.Sleep() and radio.Wakeup() methods instead. While my version is somewhat similar to the Jeelib library I do not support that library.
      When you are not interacting with the radio, your CS is not asserted so you don’t have to worry about collisions as long as your SD card is on a separate CS signal.
      I have not worked a lot with Jeenodes, reason why Moteino is around actually. I think the RFM12B is connected the same way to the atmega on jeenodes (CS on D10, IRQ on D2). There are different sleeping modes in the Jeelib, that’s why I’m saying use the radio.Sleep() and radio.Wakeup() since they do what their names imply without weird parameters that you can only guess what they mean… My boards/radios and library WILL sleep when you call Sleep() – proved in the low power tests.

  14. Similar to one above. I am having trouble programming this from Atmel Studio direct to chip. Examples work fine if I use Arduino IDE and then program with resulting hex file. But if I use hex file generated by Atmel Studio I get corrupted data and CRC errors in receiver. I have proved the transmit example works fine. There is something subtly different that I cannot work out. Possibly timing in the SPI interface?

  15. Hey Felix. These things work great “out of the box” with your Send & Receive examples. Since I’m trying to transfer an Nano+XBee project to your platform, and since these are my first steps in the RF world, I’d appreciate your input on this:
    My project involves sending continuous data from an optical encoder on the “sending” unit to a stepper motor on the receiving unit. The data needs to be continuous and responsive – every small rotation on the optical encoder needs to rotate the stepper. Is this even possible with all the ACK, GATEWAYID sending and all?
    Or is it simply my ignorance, because these things are handled on the XBee as well, only in the background, and so I’ve never worried myself?

    Thank you.

    • As long as you’re within “range” your messages should not be lost unless there’s collisions but the library accounts for that. Yes it is possible using ACKs to make sure messages are received and retry if no ACK is received by the sender. Xbee may handle the ACK internally but you don’t know for sure if messages are received. If the Xbees are not within range you will not receive your messages will be sent but you won’t know if anything was received, unless you make your own protocol to send an ACK from the other Xbee upon receiving a message. So the RFM12B has some advantage in this regard (built in the library), at least you know when messages are lost and can retry.

    • Ok, figured that one out for myself – but need some help with the radio.Send function structure. Is there anywhere I can find a detailed function set and description?

  16. Hi. Is it right that you have support for attiny44 84? As far I can see these don’t support SPI.

    • Yes but I haven’t tested it. This support is inherited from the Jeelib version. See the header file for the pin mappings for attiny44/84.

  17. Hi
    thank for the great library.
    Does the library also work with the rfm12 modules?
    i just tryed it but can’t get it working.

      • Setting the Network ID to 212 did the trick. The rfm12 modules only support this id. Maybe you should change your examples.

        How do you avoid collisions when using more than two nodes?

        • Good to know but sorry – my stuff is not based on rfm12 but on rfm12b. I’d like to not confuse the rest of 99% of users.

  18. Hello,

    Is it possible to choose the frequency band in this RFM12B Library?
    If so, how can I do that?

    Thanks a lot.

      • OK, thanks.

        I was reading the document but I didn’t see anything regarding the frequency channel inside the frequency band.
        Is it possible to choose the frequency channel? Or there’s a limitation to do that i.e. we can only use one channel?

        In the datasheet of RFM12 from HopeRF I read we can choose the channel and define its bandwidth. But from your library I didn’t see anything related to channel selection.
        Thanks a lot.

        • The channel is hard coded in the initialization function. The frequency is centered at the band frequency (433, 868, 915). You can change this in the init function yourself or add a function to the library to do this if you need to, but for 99% of users this is not necessary and would just increase the library size.

          • What you want to do is called “Frequency hopping” and is an advanced feature. While you can do this with RFM12B most people won’t need anything like that. You can contribute to the library if you’d like to make it frequency hopping capable. I just don’t have the time to do that at the moment. Such functionality need to be coded carefully not to increase the RAM/flash footprint too much.

  19. I was wondering what values to use to lower the air-kbps. I see where to do it, but I’m not sure what values to use. I want to configure the rate to 9.6kbps.

  20. thank you it works really good, just wired it and i tried the examples and boom !!!! transmitting and recieving…

  21. hi there

    love the library, only got one issue though, im using a RFM12B chip on a arduino uno, but the arduino is also connected to an ethernet shield which uses the same SS pin, can i change the SS pin that your library uses to communicate with the RFM12B to pin 9 or something like that?

    • Ahh… yes you can but you will have to change the library itself, there’s a changeCS function but it won’t work as expected, someone submitted a pull request I think on github with a suggested fix so you may look that up. In any case you should be able to do that without a problem, just make sure you always keep the SS pin (D10) as OUTPUT regardless which other pins you use for SPI enables.

      • hey mate, thanks for giving me a hand with that, ive run into another issue though, ive tried both your send/receive and LEDgateway/node example, the problem is ive been told that the chips i have possibly arnt RFM12B chips, im trying to find out if they are, would you know, maplin order code A60JN, the datasheet isnt exactly, helpful

        thanks!

        • That looks like a RFM12B to me. I thin the RFM12 (wihout the B) look the same but will only work on NETWORK ID 212 from what I recall.

  22. Hi. How do I send the number as text. I used an example using sprintf function and sending my work. Receive does not work. I do not know how to use scanf function. Can you add an example in RFM12 library on github for all? Thank you.

Comments are closed.