I am currently working on a system to monitor the garage door status from my flat. Both places are 7 floors apart, and I need to send the data wirelessly. I chose to operate on the 433MHz carrier, and I ordered 2 PTR8000 modules: http://www.electrodragon.com/w/NRF905_Transceiver_433MHz-Wireless_Module



The PTR8000 is based on the dual band sub 1GHz NRF905 chipset from NORDICSEMI: http://www.nordicsemi.com/eng/Products/Sub-1-GHz-RF/nRF905



I first needed to validate that both modules can communicate over the distance separating the 2 places. To do so, I set up a simple a configuration consisting of 2 independent TI STELLARIS LAUNCHPAD boards acting as the receiver and transmitter, and connected to their resepctive PTR8000 module over SPI. The following diagram shows signal connections:





The transmitter sends packets at maximum power gain every second or so using 4 bytes addresses and 2 bytes payloads. Also, packet auto retransmission and CRC have been disabled. The receiver waits for incoming data. It prints different messages on the UART and turns LEDs on off if the carrier is detected, if data are received, and if they are correct. The code is versionned on GITHUB: https://github.com/texane/nrf



This post refers to the commit: a36d24b3f8fa57ffbddd691cd9b3b63c9fd4a0ad



The directories:

unit/range/rx_nrf905

unit/range/tx_nrf905



contain the code for receiver and transmitter, respectively.

The NRF905 related code is written from scratch. Thus, errors are likely to occur during the first development steps. A typical programming error results in no data being transmit or received. But even if both module communicate, it does not necessarly mean that their configuration is the expected one.



Suppose that both module carrier frequencies are set to the same wrong value. This can easily occur if a SPI register offset is invalid, due to some typo for instance. This register would keep its default, still valid, value. The same applies for other paramters: power gain, address and payload width ... While there are obvious advantages when sharing a code base between several components, there can also be problems.



Thus, I wanted to verify that NRF905 chipset configuration was the expected one. It happens that I recently started to learn more about software digital radio (SDR). For this purpose, I purchased a RTLSDR dongle:

http://www.terratec.net/fr/produkte/Cinergy_T_Stick_RC_97821.html



It is based on the RTL2832U chipsets. Some people discovered that it is possible to access raw I/Q samples, making products based on this chipset cheap SDR receivers. More information can be found here:

http://sdr.osmocom.org/trac/wiki/rtl-sdr

The project provides an API to access a rtl-sdr compatible hardware. It can configure the device (center frequency, sampling rate, gain ...) and read raw IQ samples in 2x 8 bits unsigned integer format. This library is available in the project repository: git://git.osmocom.org/rtl-sdr.git

rtl_fm is a tool included in the repository that provides demodulation on top of the rtl-sdr library. It outputs the demodulated signal in time domain, samples being in 1x 16 bits low endian signed integer format. FM demodulation is used for my purposes.

Then, all I needed to do was implementing a NRF905 frame decoder. By chance, the chipset datasheet documents nearly everything related to packet framing: http://www.nordicsemi.com/eng/content/download/2452/29528/file/Product_Specification_nRF905_v1.5.pdf



A NRF905 frame consists of: . a 10 bits preamble, . an address (up to 32 bits, 32 bits in our case), . a payload (up to 256 bits, 16 bits in our case), . a CRC (up to 16 bits, disabled in our case).



The preamble and CRC are automatically added by the NRF905. Before transmission, the frame bit stream is coded using the Manchester scheme. This encoding turns every single bit into a transition: . a 0 is turned into a transition from 1 to 0, . a 1 is turned into a transition from 0 to 1.



The following diagram represents a full frame along with the Manchester encoded version:

Manchester coding increases the number of level transitions, which is beneficial for serial asynchronous systems. The drawback is that it doubles the frame size. Thus, for an effective data rate of 50Kbps, the actual rate is 100Kbps.

The datasheet also mentions other details related to the transmission. For instance, it states that GFSK is used with a frequency deviation of 100KHz. GFSK is a special kind of FM modulation, where the time domain signal is applied a gaussian filter to smooth the level transition. I wont go into the details, as it would require an entire serie of posts about frequency modulation. In our case, the FM demodulator provided by rtl_fm and a 16x oversampling are used.



With all these information, I implemented a basic decoder to listen and print NRF905 frames. The code is available in the same github repository, directory: unit/range/nrf905_decoder

It has a lot of shortcomings and I would eventually rewrite it for more serious uses. But for testing purposes, it works well enough. It can read time domain samples produced by rtl_fm from a file or direclty from the standard input. In its current version, it expects a 16x oversampling. To run it: ./build.sh sudo rtl_fm -f 433000000 -s 1600k -g 0 | ./nrf905_decoder -

After a few hours of coding and debugging, the first frames were successfully decoded, and I was now confident about the system setup.



Another useful tool is rtlizer, a spectrum analyzer initially developped for the beaglebone black platform: http://www.oz9aec.net/index.php/beaglebone/480-rtlizer

It compiles and works well on a typical LINUX x86 platform. The output looks like this:



It is not very precise, but I used it to verify the change in transmission power gain. Also, I could find the best position to set the receiving module in terms of signal amplitude.

To conclude, the RTLSDR dongle has proven to be a cheap but very useful tool. Products can easily be found on the web. Also, there is a lot of related software, which makes the developer focus on its application specific issues.