RFM12 Tutorial – Part 3a

Hmm Its been a while since I revisited the RFM12 tutorials, so I thought I’d better write the next one. Unfortunately it’s going to be too long to fit in one post so I’ll be splitting it across a couple of posts.

The last two tutorials covered a brief introduction and the physical connection to the MCU. In this article I’m going to cover the internal commands and how we go about controlling to the RFM12 module.

It’s all done with Smoke and Mirrors!

Well not really, I wish it were that simple…as mentioned previously that the RFM12 needs to be connected as described in the previous article via SPI, the second thing we need to do is access the the internal registers of the RFM12 for it to be useful.

The SPI transfers 16-bit commands to the RFM12, as part of the SPI transfer process it will receive results (if any) back to the MCU. These commands do specific things, such as set the band, turn on the Transmitter and so on, therefore to get an understanding of what we need to do, we need to understand what the various commands do.

It also helps if you to have the RFM12 data sheet open as go through this as I’ll be explaining things in roughly the same order as found on the current data sheet, most of this information is direct out of the datasheet.

SPI Interface

Just before we go through the commands, we need to be able to talk to the RFM12, and seeing that we have the SPI and NSEL correctly setup as described in Part 2 we need some routines to talk to the RFM12 and it’s registers.

There are basically two ways to do this, 1) Bit banging the SPI or 2) using on-board hardware SPI peripheral. The Hope RF programming guide offers a solution to bit banging the SPI interface so I won’t cover it here.

The following function for the AVR will provide hardware SPI support. The important thing to note is the RFM12 SPI speed needs to be kept within the RFM12 Specs <=2.5MHz

// pins used for the RFM12B interface
#define RFM_IRQ  2
#define SPI_SS   10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_SCK  13
static void spi_initialize () {
    DDRB &= ((1<<DDB2)|(1<<DDB1)|(1<<DDB0)); //spi pins on port b MOSI SCK,SS outputs     
#if F_CPU <= 10000000
    // clk/4 is ok for the RF12's SPI
    SPCR = _BV(SPE) | _BV(MSTR);
    // use clk/8 (2x 1/16th) to avoid exceeding RF12's SPI specs of 2.5 MHz
    SPCR = _BV(SPE) | _BV(MSTR) | _BV(SPR0);
    SPSR |= _BV(SPI2X);
    digitalWrite(SPI_SS, 1);   // Pull SPI_SS High
static uint16_t rf12_xfer (uint16_t cmd) {
    // the 2 loops below each spin 4 usec with a 2 MHz SPI clock
    uint16_t reply;
    digitalWrite(SPI_SS, 0);      // SPI_SS Low
    SPDR = cmd >> 8;
    while (!(SPSR & _BV(SPIF)))
    reply = SPDR << 8;
    SPDR = cmd;
    while (!(SPSR & _BV(SPIF)))
    reply |= SPDR;
    digitalWrite(SPI_SS, 1);     // SPI_SS High
    return reply;

Communicating with the RFM12

Before sending any commands the the RFM12 the NSEL Pin needs to be pulled low, then pulled high when the command has been sent.

The MPU communicates with the RFM12 over the SPI by clocking 16-bit commands serially in via the SDI (MOSI) pin on the rising edge of the SCK.

The data sent to the RFM12 consist of a command code then followed by a number of parameter or data bits, this command code and parameter/data bits total 16-bits in length.

The command/data structure is then send MSB first so bit 15 is the first bit to be sent followed by bit14 and so on. At the same time data is being clocked into the RFM12 on the SDI Pin, results (if any) are also being clocked out via the SDO (MISO) pin into the MCU MSB first, e.g. bit15 is clocked out first, then bit14 and so on.


RFM12 communicates back -NIRQ

While the NIRQ is not a required connection, it is handy for the RFM12 module to let the MPU know than an event of significance has occurred, and should be handled, instead of tying the MPU up with polling the RFM12 module to see if things have happened.

But suffice to say, the NIRQ is an interrupt generated by the RFM12 module which pulls the NIRQ pin low whenever the following occur:

  • The TX register is ready to receive the next byte (RGIT)
  • The FIFO has received the pre-programmed amount of bits (FFIT)
  • Power-on reset (POR)
  • FIFO overflow (FFOV) / TX register under run (RGUR)
  • Wake-up timer timeout (WKUP)
  • Negative pulse on the interrupt input pin nINT (EXT)
  • Supply voltage below the pre-0programmed value is detected (LBD)

Handling the NIRQ will be covered in a future Transmitting and Receiving article.

Onto the Commands

There are 15 commands that deal with configuration, control and status of the RFM12 module. these are listed below:

UPDATE: Try this handy utility as you play with registers, it’s a RFM12b command calculator (thanks Frans, aka fotoopa, for the link!) http://www.technofun.org/blog/2009/01/24/rfm12-rfm12b-calculator/

Command Description
1 Configuration Setting Frequency band, crystal oscillator load capacitance, baseband filter bandwidth, etc
2 Power Management Receiver/Transmitter mode change, synthesizer, xtal osc, PA, wake-up timer, clock output can be enabled here
3 Frequency Setting Data frequency of the local oscillator/carrier signal
4 Data Rate Bit rate
5 Receiver Control Function of pin 20, Valid Data Indicator, baseband bw, LNA gain, digital RSSI threshold
6 Data Filter Data filter type, clock recovery parameters
7 FIFO and Reset Mode Data FIFO IT level, FIFO start control, FIFO enable and FIFO fill enable
8 Receiver FIFO Read RX FIFO can be read with this command
9 AFC AFC parameters
10 TX Configuration Control Modulation parameters, output power, ea
11 Transmitter Register Write TX data register can be written with this command
12 Wake-Up Timer Command Wake-up time period
13 Low Duty-Cycle Command Enable low duty-cycle mode. Set duty-cycle
14 Low Battery Detector and Microcontroller Clock Divider LBD voltage and microcontroller clock division ratio
15 Status Read Command Status bits can be read out

1) Configuration Settings Command

The configuration command as the name suggests is used to configure the RFM12 (POR denotes the Power on Reset Values)

bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 POR
1 0 0 1 0 0 0 el ef b1 b0 x3 x2 x1 x0 0x8008

el (bit 8): Enable internal data register.

ef (bit 7): Enable fifo mode.

The el and ef bits are used to determine how the data is moved out of the RFM module. Most of the time you will be using FIFO mode as this simplifies things.

bits 6 – 1 (b1 – b0): This determines the band of the RFM12 module being used and needs to match the physical RFM12 module you are physically using e.g. you don’t set the band for 433 if you are using 915Mhz module.

b1 b0 Frequency Band (MHz)
0 0 315
0 1 433
1 0 868
1 1 915

bits 4 – 1 (x3 – x0): Determines the load capacitance of the onboard crystal. This allows fine tuning of the crystal frequency. Defaults of 12.5pf should be used.

The calibration procedure uses these settings to adjust the CLK output to 10Mhz. This procedure is in the data sheet, but is pretty vague, basically hook up a frequency counter or Oscilloscope up to the CLK pin of the RFM12B module, change the Frequency of CLK to 10mhz and measure it, it it’s not at 10MHz then use the load capacitance (x3-x0) to adjust it so it reads 10MHz. From the couple of modules I’ve tested they have all been ok at the default of 12.5pF

x3 x2 x1 x0 Load Capacitance (pF)
0 0 0 0 8.5
0 0 0 1 8.0
0 0 1 0 9.5
0 0 1 1 10.0
1 1 1 0 15.6
1 1 1 1 16.0

2) Power Management Command

The power management command controls the power to the RFM12 sub-modules, it allows you to select what circuit within the RFM12 is turned on/off. So by disabling these circuits when not required you can control the amount power savings of the device.

bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 0 0 0 0 1 0 er ebb et es ex eb ew dc 0x8208


Bit Function of the control bit Related blocks
er Enables the whole receiver chain RF front end, baseband, synthesizer, oscillator
ebb The receiver baseband circuit can be separately switched on Baseband
et Switches on the PLL, the power amplifier, and starts the transmission (If TX register is enabled) Power amplifier, synthesizer, oscillator
es Turns on the synthesizer Synthesizer
ex Turns on the crystal oscillator Crystal oscillator
eb Enables the low battery detector Low battery detector
ew Enables the wake-up timer Wake-up timer
dc Disables the clock output (CLK) Clock output buffer

The ebb, es, and ex bits are provided to optimize the TX to RX or RX to TX turnaround time as shown in the table below

Symbol Parameter Notes Min Typ Max Units
tsx Crystal oscillator startup time Crystal ESR < 100 5 ms
T tx_rx_XTAL_ON Transmitter -Receiver turnover time Synthesizer off, crystal oscillator on during TX/RX change with 10 MHz step 450 us
T rx_tx_XTAL_ON Receiver -Transmitter turnover time Synthesizer off, crystal oscillator on during RX/TX change with 10 MHz step 350 us
tx_rx_SYNT_ON Transmitter -Receiver turnover time Synthesizer and crystal oscillator on during TX/RX change with 10 MHz step 425 us
T rx_tx_SYNT_ON Receiver -Transmitter turnover time Synthesizer and crystal oscillator on during RX/TX change with 10 MHz step 300 us

This gives you an idea how the control bits are logically connected:

3) Frequency Control Command

Within each band (433, 868 or 915Mhz) we have control over what frequency the RFM12 module communicates on. So we can have various communication links occurring at the same time on the same band, but using different frequencies, or if we are getting interference on one frequency we can switch to another clear one.

Depending on what the band is determines the resolution of the frequency steps.

bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 1 0 f11 f10 f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 0xA680

The frequencies available to each band are described below in this table

Band (MHz) Resolution (KHz) Min (MHz) Max (MHz)
433 2.5 430.24 439.75
868 5.0 860.48 879.51
915 7.5 900.72 929.37

The 12-bit number representing the frequency can be calculated by:

#define RF12_FREQUENCY_CALC_433(f) (((f)-430000000UL)/2500UL)  // Calculate the RFM12 register value for a given Frequency at 433MHz in 2.5khz increments
#define RF12_FREQUENCY_CALC_868(f) (((f)-860000000UL)/5000UL)    // Calculate the RFM12 register value for a given Frequency at 868MHz in 5.0Khz increments
#define RF12_FREQUENCY_CALC_915(f) (((f)-900000000UL)/7500UL)    // Calculate the RFM12 register value for a given Frequency at 915MHz in 7.5Khz increments

The 12-bit frequency value must be between 96 and 3903, if not then they will be set to these values automatically.

IMPORTANT: It is also important that you keep within your countries ISM spectrum management guidelines i.e. allowable frequencies and their use when selecting your operating frequencies.

4) Data Rate Command

This command sets the bitrate of the transmitted data or the expected bitrate of the received data. This is the RAW physical bitrate of the module.

bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 1 0 0 0 1 1 0 cs r6 r5 r4 r3 r2 r1 r0 0xC623

cs: is set if the bitrate is < 2700 bps

Here is a table I’ve prepared for common values.

Bit Rate r6 – r0 Value
115200 0x02
57600 0x05
38400 0x08
28800 0x0B
19200 0x11
9600 0x23
4800 0x47
2400 cs =1  0x11
1200 cs = 1  0x1E

If you want to calculate your own bitrates use the formula:

//calculate setting for datarates >= 2700 Baud
#define RF12_DATARATE_CALC_HIGH(baud) ((uint8_t)(344828UL/baud)-1)
//calculate setting for datarates < 2700 Baud
#define RF12_DATARATE_CALC_LOW(baud) ((uint8_t)(43104/baud)-1)

When setting bitrates you also need to take into account the receiver bandwidth settings (See Receiver control command below)

5) Receiver Control Command

bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 POR
1 0 0 1 0 p20 d1 d0 i2 i1 i0 g1 g0 r2 r1 r0 0x9080

Bit 10 (P20): sets the function of INT/VDI pin on the RFM12 module, it configures it as input (Interrupt from MPU) or output (VDI Valid Data Indicator). The VDI is the default setting. This goes high when valid data has been detected by the RFM12 module, valid data is data that has made it past the Sync pattern. If set as Interrupt input, we can use this to send an interrupt the RFM12. The RFM12 will then stop what it’s doing and wait for the next command.

p20 Function of pin 20
0 Interrupt input
1 VDI output

Bits 9-8 (d1 to d0): VDI (valid data indicator) signal response time setting:

d1 d0 Response
0 0 Fast
0 1 Medium
1 0 Slow
1 1 Always on

[1]” src=”http://blog.strobotics.com.au/wp-content/uploads/2009/07/clip_image0021_thumb.jpg” border=”0″ alt=”clip_image002[1]” width=”448″ height=”266″>


Bits 7-5 (i2 to i0): Receiver baseband bandwidth (BW) select:

The receiver bandwidth is the amount of frequency above and below centre frequency we are receiving on (See the Frequency command for more information on changing the frequency) that the receiver is sensitive to. So if 400Khz is select as the Receiver bandwidth and 915Mhz is the centre frequency, then the receiver will looking for a signal anywhere +200Khz above 915 and 200Khz below, i.e. 914.800 – 915.200.

The bandwidth settings is linked to both the data rate, and Tx Modulation (Deviation)commands. When data rate is fastest a higher bandwidth is required. There are optimal settings for the Bandwidth and Modulation for different data rates as shown below. Having too much bandwidth can cause a higher SNR and can cause packet corruption. Not enough bandwidth and the incorrect signal is not received.

Incorrectly setting Bandwidth and Deviation (Modulation) is usually one of the common problems.

Table of optimal bandwidth and transmitter deviation settings for given data rates (the data sheet was a bit vague in this area and did not specify frequencies etc so I don’t know how valid they are at different frequency bands but they could be used as a starting point)

Data Rate [bps] Bandwidth [KHz] Modulation (Deviation) [KHz]
1200 67 45
2400 67 45
4800 67 45
9600 67 45
19200 67 45
38400 134 90
57600 145 90
115200 200 120


i2 i1 i0 BW [kHz]
0 0 0 reserved
0 0 1 400
0 1 0 340
0 1 1 270
1 0 0 200
1 0 1 134
1 1 0 67
1 1 1 reserved

Bits 4-3 (g1 to g0): LNA gain select:

The LNA gain (Low Noise Amplifier) can be selected according to RF signal strength. It can be useful in an environment with strong interferers. Or alternately if you have two RFM12 modules in close proximity then you can drop the sensitivity of the Low Noise Amplifier.

g1 g0 relative to maximum [dB]
0 0 0
0 1 -6
1 0 -14
1 1 -20

Bits 2-0 (r2 to r0): RSSI detector threshold:

r2 r1 r0 RSSIsetth [dBm]
0 0 0 -103
0 0 1 -97
0 1 0 -91
0 1 1 -85
1 0 0 -79
1 0 1 -73
1 1 0 -67
1 1 1 -61

Similar Posts:

Print Friendly

Author: Stephen Eaton

Geek at heart. Loves to tinker and find out how things work, which inevitably leads to items in pieces and not working for much longer :)

37 thoughts on “RFM12 Tutorial – Part 3a”

  1. Nice description Stephen!
    I’ve done also more tests now. As hardware I use the DE1 FPGA controller board just because this go faster for me and my basis system is also FPGA. But my receiver come also into the AVR controller.

    Just now 2 modules works here. Only tested at short distance but into the near future I will test it at normal distance too. I just put the picture results of the logicanalyser onto my Flickr site:
    As you can see the speed is very high, tested at the max baudrate. Speed is very important by my application.

    Did you see the simple calculator for all the parameters of the RFM12B module? see this link:

    I use this calculator and it works nice! With a simple screenshot you can save all the settings as documentation for later use.

    Now I continue the tests and i let you know when new results are available.

    Frans (fotoopa).

  2. Thanks for the link Frans, I’ve just updated this article with it, very useful.

    Looks like you are making great progress, I noticed from the logic traces that you are not using interrupt driven Tx? I guess with FPGA you could run the Tx in parallel to what you are doing, so no need to generate an interrupt.

    I will be interested to see how you go with distance at the maximum bit rate.

  3. Yes Stephen, I just polling the statusbit. Hardware always works parallel and fast. The SPI speed is less important, you have always to wait to send the next cmd or data. But the baudrate is of course extremely decisive.

    To reach optimal speed for the fire command I preset the communication into a preamble sync mode. I know beforehand the periode when a trigger will follow ( camera is set to record with the second shutter closed and wait for trigger via the laser detection of the flying insect) During this waiting periode I send continue the preamble B8AAh command, so the receiver have good sync and wait only for the 16bit synccode and next execution command. As soon as I have a triggercommand from the laser system I send the fire command, B82Dh, B8D4h,B843h,B847h and after this a few preamble codes but this have no more influence on the fire command speed. By this way I save minimum 2 preamble codes and for high baudrates the receiver is long before good in sync.

    But there is more. Because remote wireless have a minimum delay ( in my case near 430 usec) I have to adjust this delay with the non remote flashes on the unit. Also the remote flashes need mostly higher power and this higher power give longer flashtimes. For very high speed like this flying insects you need to adjust all this timings so that they are equal divide. This optimal central timing position can be calculated from all the powers of the used flashes because the central unit know all this information. On this way you avoid that the fix flashes fire long before the background flashes fires. For normal non highspeed work this is not so critical, as long as your flashes falls into the camera window ( let say 1/250 or 4 msec) But for very high speed even a few 100 usec are important otherwise you have some blur into the fast moving parts.

    I will give into the next days more details on my Flickr site of all this timings and results. Also distance tests will be done.


  4. This afternoon I have updated the hardware sequencer for best results. The shortest delay with a command of 8 bits after the synccode show a delay of 288 usec at 115 Kbaud. This is really very short. The receiver code is now moved to a second harware CPLD unit. At short distance this setup is 100% reliable. I hope to test this next Thursday at longer distance. ( Have first to cycle 70 km with my wife tomorrow, but this is very good to dream of all the hardware routines during this trip).

    Frans. (fotoopa)

  5. @fotoopa

    I like your idea of continually sending pre-amble packets until you trigger then sending sync and trigger octets, that would save overheads of a the preamble and FSK alignment when timing is tight.

    As for timing I agree that high speed is possible over the air and was looking at doing something similar for my canon camera.

    If I know the time of flight etc then we could pre-empt the flash trigger and time it so the shutter and flashes fire at correct time.

    However for an on camera trigger only (luckily you have the benefit of laser so you can time/pre-empt things), I think I need to access canons ettl protocol via the other hot shoe contacts which will give me this information (based on Bill Grundmans work of the ettl protocol reverse engineering) as syncing with the hot shoe trigger signal will be too late.


  6. Hi Stephen,

    For on camera trigger I will take the startsignal from the X-sync connector. With the tests now, we know that the minimum delay is 360 usec. Tests on the Nikon flashes show an extra delay of 30 usec between fire and really flashlight on the photo detector. Let say the total minimum delay come near 400 usec. If you use front curtain sync mode the remote flashes can start after this 400 us delay. This is without any trouble for the normal speeds like 1/250 on most cameras. This must works for Canon camera’s as well.
    For rear-curtain sync, there may be a timings problem if the used flashpower is high. But this is the case for all rear-curtain sync modes and max camera speed on X-sync mode. So the better methode could be to set the camera in front-curtain sync and add a delay (func) from the used power and the desired rear-curtain result.

    For my system with the second shutter, the settings are similar. Only a longer delay is need and I must provide a safely delay so that I always flash with second shutter full open. This shutter have also a non stable zone. This zone depends also from temperature. If it’s warm the minimum delay is near 5.5ms but in the night at lower temperature this delay is near 6.5ms.

    Today I have tested 2 RFM12B units at 10m and 2 walls at 115 kbaud on 868 Mhz and everything works like a train. 100% reliable, every push give a flash on the remote unit. As you can see, the hardware solutions works very quickly. I have put the RFM12B modules on 2 separate breadbords and 2 FPGA DE1 Terasic boards for this tests.

    I have place an order for 3 SC-27 Nikon flash cables for TTL flash drive. Divide each cable in 2 pieces I have 6 connection Nikon cables. The other side of the cable can be replaced with a lowcost connector to my modules.

    Now I will calculate all the timings for optimal symetric flash timings in function of all the used powers. More power need to shift to the right into the camera flash window opening. This is only need for highspeed photography. Timings are calcultated into the central remote controller.

    This give my the necessity to send extra parameters to each flash. This parameter is a offset delay that the flash have to add when he receive the fire signal. This is needed because the fire signal go the same time to all the flashes online. Into the next days/weeks I will set all this parameters and drawings on my Flickr site. Also I will measure some timings from the X-sync of the camera and the relation with all this timings for remote control.

    Your last info about the newer RFM controllers is very nice. A big positieve point is the higher sensivity of the receiver and higher power of the transmitter resulting into a reliabe communication. But I have now 10 RFM12B modules instock. I will use them first.


  7. Hi stefan
    i m using RFM12B for a project in 433MHz band.I am having a problem in it.I use one module in receiver mode using internal FIFO and wait for nIRQ to go low so that i read a byte from the FIFO.The FIFO overflow is set to 8 bits.Another module is transmitting data with some delay of one sec between two consecutive bytes.The problem is than with in this delay the controller reads 0x00 from the FIFO and nIRQ also goes low.This happen after the sync word detection.If i transmit 0x31 and 0x32 with one sec delay the receiver gets 0x31 0x00 0x00 0x00 0x00 0x32 so within this time gap the nIRQ continuously goes low showin that it has recieved a valid byte.Can u tell me why this happens and how to fix this.

  8. @aamirsherkhan

    It sounds as though your Rx is loosing lock due to the delay between bytes being transmitted.

    You should be aiming to send a continuous stream of data bytes once you turn your TX on have sent the pre-amble and sync bytes. i.e. no interruptions between 1st and last data bytes being sent.

    What I suggest due to the delay between the bytes is to send each byte of data within a packet. i.e.

     (7 bytes)
    turn your Tx on before you send and then off once sent.  

  9. Hello Stephan

    When RFM12B is tested continuously for a few hours i.e. data reception and transmission for every second. The RFM12B module does not respond to RF data receive after a few hours.In DCLK and NIRQ lines, the frequency is incorrect. Can anybody help as to why this is happening?. Also if Turn OFF and turn on the module it works fine again.

    Thank you in Advance

    Nithin Prakash

  10. Hi Stephen,

    I´v read your blogs with interest. I too have been struggling with these. As a matter of fact with their little brother and sister: RFM01 and RTX02 I believe they are called. The chips are actually made (or sold) by Silicon Labs and they do have a lot of extra information on them. Including an application that lets you define all your parameters and it will then create a header file for you to use.
    However, I am puzzled by a few things. They claim to have a proper SPI interface but I don’t think they do. For one their data send protocol doesn’t match which is something they even mention in their datasheets.
    But what I do not understand is how the SCK pin works. As far as I can see they do need a clock from the master. If the master is your MCU then I don’t know how you could do that without actually using your MCU’s SCK port?! Well, you could actually generate the clock yourself by using a timer. However in all the sample code I have seen floating around including yours, the SCK is just an outport pin that is pulled low and released again. Am I wrong in this?


    P.S. Sorry for bumping this thread…

    1. @willem apologies for the late response (I had missed it earlier)

      you are correct the SCK is provided by the MCU, bu tyou don’t have to use the MCU SCK port, the SCK is used to clock in (and out) the bits that make up the command being sent to the RFMxx. you can bit bang the spi quite easily, I initially did this on the PICs as I couldn’t get the onboard SPI working, AVR the onboard SPI works a treat. below is what I did to bitbang the SPI

      Write a Command to the RFM Module using SPI

      Requires: 16bit valid command
      Returns: 16bit result from transaction

      This is a bi-directional transfer.
      A command is clocked out to the RFM a bit at a time.
      At the same time a result is clocked back in a bit at a time.

      uint WriteCMD(uint CMD)

      uint RESULT = 0; // Holds the received SDI
      uchar n=16; // number of bits in SPI Command we need to send
      SCK=0; // SCK LOW
      rfm12_cs = 0; // CS LOW
      while(n--) // Send All 16 Bits MSB First
      if (CMD&0x8000)
      Write1(); // Write 1 via SDI
      Write0(); // Write 0 via SPI

      CMD<<=1; // Shift left for next bit to send
      RESULT<<=1; // Shift left for next bit to receive
      if(SDI) // Check if we received a high on SDI
      RESULT |= 0x0001; // RESULT LSB = 1
      SCK=0; // SCK LOW
      rfm12_cs = 1; // CS HIGH - Finished Sending Command

      the bit banging is done in these

      // Bitbang binary 1 via SPI
      void Write1(void)



      // bitbang binary 0 via SPI
      void Write0(void)



  11. Hi Stephen

    I am trying to get the RFM12 to work with the PIC16F877A, but I am totally lost about how to get the rf module configured. I got my two pic devices working fine in SPI, wired up. But when I try to integrate the rf module, it doesn’t seem to work at all. I’ve got a couple of questions baffling me, hope you can answer them for me.
    1. How should the rfm12 module be connected to the pic? according to the rf12 programming guide example 2, it used RB7 – 4, but the SPI interface uses RC5 – 3.
    2. How are the rf module parameters configured? I understand the configuration commands are given in the programming guide, but I don’t know how they are sent to the rf module, but using the code in the programming guide?
    3. If I get the rf module setup, how do I send data out, do I write to SSPBUF or do I have to use some other function?

    Thanks in advance

  12. @stephen: LOL. I did check very regularly for a response from you but then gave up, thinking you had moved on to bigger and better things. And now, 31st dec., I happened to stumble back here and found out you answered more than a month ago. So sorry, but thanks a lot!

    In the meantime, I did manage to get it working though. Both RFM01 and RFM02 and RFM12B. In 868 and 433 frequencies and mixing them as well. Once you get the hang of it they are great and seem to be pretty robust as well.

    I received a lot of support from Hope (and some help). But using a logic analyzer is the thing that really helped me progress this.

    Thanks and all the best for the new year!

  13. Happy New Year everyone!

    I am sorry, I just couldn’t let go. Still working on RFM12B communication and I found out that in my case I get better results transmitting using a slightly different method then I have seen in Hope and other code. For writing the data I use:
    void rf_write_data( BYTE data )
    WORD status;

    WAIT6u; // just make sure our clock pulse is longer than freq./4

    while( nIRQ );

    status = rf_write_cmd( 0x0000 );
    if( (status&0x8000) == 0x8000 )
    rf_write_cmd( 0xB800 + data );

    This is, as you can see, very similar to the way I receive data:
    BYTE rf_read_data( void )
    WORD status;
    WORD data;

    WAIT6u; // just make sure our clock pulse is longer than freq./4

    while( nIRQ );

    status = rf_write_cmd( 0x0000 );
    if( (status&0x8000) == 0x8000 )
    data = rf_write_cmd( 0xB000 );

    return (data&0x00FF);


  14. Hi Stephen

    I was looking at the RFM12.H header file you have created and found a mysterious RFM12_PLL_LPX in the PLL setting command definitions. In the latest data sheet this location is a fixed 1. Is this a throwback to an old version of silicon?


  15. @realheaven

    The SCK is used in the SPI communications and is part of the SPI standard. The SCK is provided by the MCU, not the RFM12.

    The on-board Crystal can provide a CLK output to drive a MCU or anything else that requires an oscillator and can be controlled up to 10MHZ. I use this to test my SPI communications between the MCU and the RFM12. i.e. I put a frequency counter or oscilloscope onto the CLK pin of the RFM12 and then send through a command to the to change the frequency.

  16. Hey Stephen,

    Thanks For that nice article, everything is working just fine !!!

    i am using two pic mcu and two rf12 433MHZ and i used the hope rf bit banging code and its working just fine.

    my question is when i send the preamble and the sync why i dont see them in the receiver buffer of the pic receiver i only see the Data bytes sent ?

  17. sync bytes are the bytes to sync between TX and RX and not counted in your RX data. they would be automatically abolished when processing. if you wanna know exactly that process just contact Hoperf for more information!

  18. Hello-
    The part that I am really confused about is the RF communications.
    I have configured the RFM chips through the SPI on my PICF18452, and thanks to these awesome tutorials, it went pretty well.

    I need help understanding how to send and receive data through the FSK. I can see on the few coding examples that they first turn on TX, send a Preamble bit, then some synch.
    But how would I have known this without the examples? And, the examples don’t exactly match each other.
    Some pseudo code would be really helpful.

    WriteCMD(0x8238); // Turn on Transmitter
    delay_ms(1); // turn on delay

    rf_SendByte(0xAA); // PreAmble

    rf_SendByte(0x2D); // Sync

    // then how do you send data?
    // and how do you receive it?

    1. Hi sophi,

      This is what I had the most dramas with when I first started, what is working? Is it transmittng? Is it receiving? and of course the hoperf examples are hard to follow and just didnt work for me, so can be very frustrating.

      I would suggest you look at RFM12 library at http://jeelabs.net/projects/cafe/wiki/RF12 These work reliably and is what I have used in my past projects. Although they are AVR they are good to see how things are done.

      First Steps, make sure that the SPI is working on both ends, write a test sequence to change the clock output frquency and make sure this is working, if it’s not then nothing will work.

      When transmitting it is very important to:
      1) Write the first two bytes to the RFM12 before turning the transmitter on. These will usually be Pre-amble
      2) have no interruption in the Tx Sequence, i.e. no pauses or delays.
      3) no debug code in the Tx routines.

      If there is a pause in the Tx sequence then the Rx will loose sync and you need to restart the preamble/sync sequence.

      End your transmit packet with two preamble bytes before turning off the Tx. This will make sure the that all packets are sent.

      So to send data:

      write preable x2
      Turn on Tx
      Send out each byte in the packet you want to transmit. e.g. rf_SendByte(first_octect); ….. rf_SendByte(last_octect);
      Send out x2 preamble, e.g. rf_SendByte(0xAA); rf_SendByte(0xAA);
      turn off Tx

  19. Hi Stephen,
    Thanks for your reply- the pseudo code is helpful.
    My SPI communications is working…I can see the SPI CLK signal on scope and also I turn off the crystal output on the RFM12B.

    I’m using a PIC.
    I do not think I am successfully transmitting.
    I do not know how to tell if I am transmitting. I don’t have an RS232 output set up on my board or a spectrum analyzer. I have an oscilloscope which can see a 9600 baud rate CLK signal and SPI data. I also have an LED attached.

    1. Besides the FIFO, how else could you be TXing and RXing data? I have tied the FSK/DATA/nFFS pin high based on part 2 of these tutorials. One of the data sheets says it should be tied low for FIFO, but it is not definitive. Hope RF has a schematic showing FSK tied high, but who knows if they are using the FIFO.

    2. After the configuration routine, do I need to chip select before and after each byte of data (actual transmit data) that gets sent?

    3. My problem is now the NIRQ pin. At first it was low all the time, but now I start my configuration code sending 0x0000. Now it is high all the time and I don’t see it go low ever. I have a 4.7k pullup on the NIRQ to 3.3V.

    What pin can I look on to see if anything gets transmitted? I think nothing is transmitting since the NIRQ never goes low. Or does the NIRQ move too fast for my oscilloscope (60MHz, but I’m not sure what that really means since I can’t even see my MCU crystal, 20MHz signal on it)
    Thank you so much for your help!!
    Here’s the code (after the config)
    output_low(PIN_C0); // chip select
    for (i=0;i<5;i++)
    while(input(PIN_C1)) // NIRQ is high
    spi_write(0xAA); // preamble
    spi_write(0xAA); // preamble
    spi_write(0x2D); // Synchron pattern from power on reset FIFO and Reset Mode command
    spi_write(0xD4); // Synchron pattern from power on reset FIFO and Reset Mode command
    spi_write(0x82); // turn on TX from Power Management register, first byte
    spi_write(0x38); // turn on TX from Power Management register, second byte
    // 13. Transmitter Register Write Command POR B8AA, so need to start every transmission with 0XB8
    spi_write(0xB8); // this command byte is used to write a data byte to the RF12
    spi_write(0xF0); // this information should get transmitted with the previous byte
    spi_write(0xAA); // preamble, clear buffer
    spi_write(0xAA); // preamble, , clear buffer
    spi_write(0x82); // turn off TX from Power Management register, first byte
    spi_write(0x11); // turn off TX from Power Management register, second byte

  20. I just added an LED on/off at the end of the loop. I can see that the data is clocking on the RFM-SDI and I can see the SPI clock too.
    So I’m sure that data is going from PIC to RFM.
    So my question is still, how do I know the data is then leaving the RFM12B module?
    Is there an RFM pin I should look at ?(I’ve looked at them all and don’t know what to see)
    I disconnected the FSK pullup for now since I’m not sure if it should be tied high or low or if it matters.

    What dramas! LOL!

  21. This project has helped a lot.
    Hope there is still help you there.
    I have my transmitter working, but I can’t get nIRQ to go high so I can use interrupts.

    Which settings affect the nIRQ in TX mode.
    John Z.

    1. @John Z

      first read the status register and see if there are any interrupts pending, any of the followin will cause the nIRQ to be pulled low

      The TX register is ready to receive the next byte (RGIT)
      The FIFO has received the pre-programmed amount of bits (FFIT)
      Power-on reset (POR)
      FIFO overflow (FFOV) / TX register under run (RGUR)
      Wake-up timer timeout (WKUP)
      Negative pulse on the interrupt input pin nINT (EXT)
      Supply voltage below the pre-0programmed value is detected (LBD)

  22. Hi Stephen,

    This is really a great tutorial page, thank you for your post.
    At the moment I am trying to get a set of RFM12B (433MHz) up and running. However they do not seem to work as I expect them to work.
    In my search I encountered some weird behavior, perhaps you have an explanation for the observed behavior.

    My approach so far:
    1) make sure SPI is properly working, which it does.
    – sending a status read command results nicely in a POR bit high and rest low
    2) change the CLK frequency and monitor the result on a scope
    – it works perfectly, so I am confident that both spi work and that I am able to send commands, and the RFM modules are receiving them and are working.
    3) without sending any configuration commands when turning on the chips, steps 1 and 2 work. However, as soon as I send the first configuration command (0x8208, which should be the same as the configuration at startup) nothing changes, but after a status read command (0x0000) the clock output is disabled (CLK is 0).
    Obviously I also tried to send a (0x8209) with identical result, moreover, sending (0x8209) does not even shutdown the CLK by itself.

    Directly after turning the module on, I was able to turn on/off the CLK pin by sending 0x8201 (turn off) and 0x8200 (turn on). As soon as I send one status read command (0x0000), CLK is dead all the time….

    I getting rather desperate now, so any suggestions would be very much appreciated.


    1. G’day Dirk,

      What are your voltage supplies like, reset all tied high? it’s been a while since I’ve played with these, but something does not sound right. what is the IRQ status during this? can you read the status after sending the problem command?


  23. Hello Stephen,

    Thanks for your quick reply!
    It looks as if I have found the problem for the problem described above. I do not have a module working (i.e. sending and receiving data), but I am now able to get the response I expect when sending the commands controlling the CLK output pin.

    I found a small bug in the SPI routine: I read the output pin after pulling the clock pin high, reading it before seems to solve the problem. The weird thing is that even with the routine that included the bug it seems was sometimes possible to have communication with the module.

    To reply to your questions:
    > I think the voltage supply is decent enough: the module does not reset.
    > IRQ pin is low before first status read, high afterwards
    > Status register only has a high POR bit at first read, in subsequent reads status register is equal to 0.
    > Even after writing the problem commands I was able to read the status register…

    My next try is to send a bunch of configuration commands and see if I can get some communication between two modules going. Do you have any suggestions for intermediate tests to do, in order to make sure that the modules are configured correctly?

    Thanks again for your great tutorial! It has been the most valuable source of information for me in getting this far with the RFM modules!


  24. Hello Stephen,

    I’ve been trying to use the code you made available and been going through some trouble. I’m using PIC18F4550 and RFM12B on both sides of the (not yet) communication. I’m also using the MPLAB IDE, so I had to make some changes to your code and this may be the reason why it is not working.

    I think the first problem to be solved is in the tx side, since the LED is supposed to blink after the transmittion and it is not doing so.

    I commented this part of your code in both sides becouse I simply did not know what was it about, can you make it clear for me?

    osccon = 0x70; // 8Mhz internal OSC
    ansel = 0; // all is digital i/o on PortA
    option_reg.NOT_RBPU = 0; // enable pullup resistors on PB
    option_reg.INTEDG = 0; // falling edge interrupt

    I suppose the second line is just to deal with the disable of the analogic functions, but the other ones I don’t have a clue!

Leave a Reply