I recently developed a protocol agnostic driver library for HopeRF’s RFM69 modules. Protocol agnostic means that you get full control over the module and the data packets that you want to send or receive. You can use this library for receiving packets from existing commercial devices like temperature sensors, or you can set up your own RF network using your own protocol.
The library is written in C++ and targets the STM32 microcontroller family. But it can be easily ported to other devices by changing very little code.
Features
- Protocol agnostic
- Support for RFM69W and RFM69HW devices (maximum output power +20 dBm)
- Only SPI signals are mandatory
- CSMA/CA algorithm can be enabled (channel free detection)
- Easily portable to other controllers (default: STM32)
- No register handling necessary
- Read RSSI values after reception of a packet
- OOK mode supported (default: FSK)
- Continuous data mode supported (default: packet oriented)
- Written in C++
- Polling based library
You can find the MIT licensed library in my GitHub repository.
Enjoy! 😉
Hello Andres,
I have a STM32 Nucleo F4 series. Could you please provide a schema how to connect the RFM69HW (433Mhz) on it?
Hi mosix,
the RFM69 module has a very simple pinout. I can show you an extract of one of my schematics.
See here:
A few notes:
The S1-* nets connect to SPI1 of the STM32 in my case. Just select a (free) SPI on your Nucleo board.
S1-NSS needs an external or internal pull-up resistor. The same applies to RF-RES which is the reset line of the module.
The other connections are not mandatory, their use depend on the application you want to develop (see: datasheet).
Many thanks! 🙂
Hi there, I’m new to STM32 and I was wondering how to get this code uploaded to my Maple Mini STM32 board, what IDE do you use?
Hi Dan,
I am using Eclipse and the GCCARM Embedded Toolchain for my projects, both very powerful and available for free.
If you are new to the STM32 world, maybe consider using the CooCox IDE (with GCCARM). I haven’t used it myself but I heard that the IDE should be beginner-friendly.
There is also a blog called “MCU on eclipse”, which could give you a good start if you decide for Eclipse.
Due to lack of time I cannot give you a tutorial of how to write a simple program for the STM32 microcontrollers and use my library, sorry.
If you are able to write simple programs (like blink an LED, do something with SPI), the next step in including my library should be quite easy.
But I hope this helps nonetheless.
Kind regards,
André
Thank You for your reply! I’ll check it out.
Excellent work. I am getting an issue though. I am trying to test it by sending and receiving through two different RFM69 modules attached to the same STM32 discovery board at different SPIs (SPI2 for sending, SPI3 for receiving). I used the code that you had provided in the GitHub repo’s readme for testing Tx and Rx. I am not receiving any packets though. I can confirm that the SPIs are working by reading register 0x10 and get a value of 36 from both modules.
My code in main.cpp is like so:
mstimer_init();
RF_Begin();
while(1){
RF_SendTest();
char* value = RF_RecvTest();
}
Function RF_Begin() looks like so:
spiRF.setPrescaler(SPI_BaudRatePrescaler_2);
spiRF.init();
spiRFRx.setPrescaler(SPI_BaudRatePrescaler_2);
spiRFRx.init();
// setup RFM69 and optional reset
GPIO_InitTypeDef RFResetPin;
RFResetPin.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_1;
RFResetPin.GPIO_Mode = GPIO_Mode_OUT;
RFResetPin.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA,&RFResetPin);
rfm69.setResetPin(GPIOA, GPIO_Pin_2);
rfm69rx.setResetPin(GPIOA,GPIO_Pin_1);
rfm69.reset();
rfm69rx.reset();
// init RF module and put it to sleep
rfm69.init();
rfm69.sleep();
rfm69rx.init();
rfm69rx.setMode(RFM69_MODE_RX);
//rfm69rx.sleep();
// set output power
rfm69.setPowerDBm(10); // +10 dBm
rfm69rx.setPowerDBm(10); // +10 dBm
// enable CSMA/CA algorithm
rfm69.setCSMA(false);
rfm69rx.setCSMA(false);
And the RFM objects are declared at global level like so:
// setup SPI and RF
SPI spiRF(SPI2);
RFM69 rfm69(&spiRF, GPIOB, GPIO_Pin_11, false); // false = RFM69W, true = RFM69HW
SPI spiRFRx(SPI3);
RFM69 rfm69rx(&spiRFRx,GPIOB,GPIO_Pin_10,false);
I debugged into the RX function and it seems the FIFO ready flag is not being set. Inside the _receive function, the second “if” statement that checks for this flag fails because reading 0x28 register returns 0x60 instead of 0x04. I tried to bypass it but it ends up picking up gibberish. What could be wrong?
Hi Azmath,
thank you for your comment.
Everything seems reasonable so far.
If this is really your main loop you are showing, try adding a delay (as a start >100 ms) because otherwise you would be sending permanently without pause. I don’t know if this could be a problem.
When you connect two RF modules to one discovery board, I assume that the distance between them is quite low (a few centimeters maybe). You should therefore limit the output power to maybe 0 dBm or even lower. Otherwise you could overdrive the input stage which might result in your problem.
Register value 0x60 in register 0x28 means that there was received something (FIFO not empty) but probably not a complete or invalid packet because the CRC check failed (no payload ready flag).
You could also try lowering the SPI speed of both SPI interfaces. Even if the transfer essentially seems to work (confirmed by reading register 0x10), there may be problems writing or reading other registers.
Since you are able to debug, please also check the return code of the function “waitForPacketSent” which is called in the send function (this is not done in my library at the moment). Maybe the sending part of your system goes into a timeout for whatever reason.
If none of the above works, please also provide the following information:
1. What STM32 are you using?
2. Is this really a RFM69W or maybe a RFM69HW?
3. What happens in RF_SendTest?
4. What happens in RF_RecvTest?
5. Try small payloads at the beginning (< 10 bytes). 6. Try enhancing the function "setCustomConfig" or even "writeRegister" so that the register contents are read back and verified. 7. Maybe connect a logic analyser and verify that the sending and receiving part is handled correctly. Things to look for: Clock too fast, chip select released/acquired too early/late. I hope this helped! Kind regards, André
Thanks for replying! It was the distance being too short I guess. I used a different RF transmitter (from a different device) and it receives fine! Thanks a lot!
Good work !
I use simple PCB with STM32 and 2 modules (only one mount at time).
Also RadioHead perfect library for most RF modules (star or P2P mode)
http://www.airspayce.com/mikem/arduino/RadioHead/
Hi Andres,
I recently got a pair to RMF69HCW radios. The datasheet states the its capable of up to 300kbps but it seams that the highest data transfer rate achievable is only about 16kbps. I’m trying to find a site that pushed this radio to is limits and details the settings used to achieve it. I’m trying to transfer a large amount of data as fast as possible between 2 nodes in a network. I’ve searched high and low to try to figure this one out.
Any help would be greatly appreciated.
Regards,
Sidney
Hi Sidney,
I haven’t used these modules for speeds greater than 57,6 kbps myself, but this baudrate works quite well in my setup.
These are the settings I use in this constellation (just copied from one of my projects):
static const uint8_t rfm69_ismmod_config[][2] =
{
{0x02, 0x00}, // RegDataModul: Packet mode, FSK, no shaping
{0x03, 0x02}, // RegBitrateMsb: 57,6 kbps
{0x04, 0x2C}, // RegBitrateLsb
{0x05, 0x03}, // RegFdevMsb: 50 kHz
{0x06, 0x33}, // RegFdevLsb
{0x19, 0x42}, // RegRxBw: 125 kHz
{0x2C, 0x00}, //RegPreambleMsb
{0x2D, 0x03}, //RegPreambleLsb, 3 bytes preamble
{0x2E, 0x88}, //enable Sync.Word, 1+1=2 bytes
{0x2F, 0x41}, //SyncWord = 48h
{0x30, 0x48}, //SyncWord = 48h
{0x37, 0xD0}, //RegPacketConfig1, CRC calculation, variable packet length, whitening
{0x38, 0x40}, //RegPayloadLength, max 64 bytes payload
{0x3C, 0x8F}, //RegFiFoThresh, TxStart on FifoNotEmpty, 15 bytes (default)
{0x58, 0x2D}, //RegTestLna, increase sensitivity with LNA (Note: consumption also increase!)
{0x01, 0x04} //Enter standby mode
};
There are some things to consider when trying to push RF modules to its limits:
I hope this helps in achieving your goal. Good luck!
Kind regards,
André
Loointi the registersking for info on how to set frequency, Im using an arduino – would it be possible to use your library in conjunction with the arduino IDE to set frequency or can I set it with a calculation and a few hex pokes
Hi Mike,
in theory this library should be compatible with Arduino because it is standard C++ code. But I have never done anything with Arduino, so I cannot give you any support on this subject.
Regarding the setting of the frequency… This is quite easy, look at the source code of rfm69.cpp in the function RFM69::setFrequency. There are 3 registers (0x07-0x09) which are responsible for setting the carrier frequency.
So even when you do not use this library, you can easily adopt the function to your own needs or to another library if this particular function is missing.
I hope this helps!
Kind regards,
André
Hi André,
I’m working with nRF52 and I’m using Nordic SDK and plan to use your library to make my device dual band (BLE + 433MHz radio). I believe I should use the SPI library that is defined by Nordic SDK, however I don’t know how to merge your library with Nordic DK. Do you have any insight in this?
Thanks,
Samuel
Hi Samuel,
it actually does not matter which SPI library you use as long as you present this library a common interface.
If you look at the constructor of my RFM69 class, you notice that it depends on a “SPIBase” class. This is an abstract class (“interface class”) which is defined in spibase.hpp. You have to write a C++ class which implements these abstract functions and matches your hardware.
The hardware-dependent code is not really scope of this library. I merely included some example implementations for the STM32L1 and STM32F0 devices in my library, copied from my other projects.
I haven’t done anything with the nRF52 yet. Probably the easiest way to get this library to work with the nRF52 is to write a wrapper class which inherits from the SPIBase class. In this new wrapper class, you call the SPI functions from the Nordic SDK, which hopefully should exist.
I hope this helps!
Kind regards,
André
Hi André,
I’m trying to get a RFM69 and a NRF905 to talk to each other. I’ve been trying since a week without any success. Each RF module is wired up to it’s own STM32F401. I’m using your RFM69-STM32-master library as a starting point. For the nrf905 I wrote my own class. Although I’ve been reading the 2 datasheets back and forth I can’t come up with a set of configurations.
So I wonder has anybody a configuration for the RFM69 which makes it understand what a NRF905 is sending (and vice versa). The configuration for the NRF905 is relatively simple which means there aren’t too many choices.
My setup is this (config reg 0 … config reg 9)
{0x75,0x0e,0x33,0x18,0x18,0xCC,0xCC,0xCC,0xCC,0x18}
which means:
868.2 MHz
3 byte address for RX and TX
24 bytes payload for RX and TX
address 0xCC 0xCC 0xCC
CRC off
Now I’m looking for a configuration which puts the RFM69 in a compatible mode. (Or any other compatible setups.)
BTW: André, you wrote in one of your first posts:
“S1-NSS needs an external or internal pull-up resistor. The same applies to RF-RES which is the reset line of the module.”
I don’t understand this. Both are inputs to the RFM69 and are driven from DigitalOut pins of the STM32. So I don’t see what pull-up resistors should accomplish. ??
Any help is greatly appreciated!
Ronald
Hi Ronald,
sorry, I cannot help you with the problem regarding the NRF905 because I haven’t done anything with this module.
I can only comment to the pull-up resistors:
Technically you are right. The lines can be actively driven via a push-pull output stage of the controller and you should be fine. But in many cases, reset lines and chip select lines are pulled up externally so that the device doesn’t do anything “stupid” during the power-on phase of the circuit when the main controller is not yet ready. This becomes essentially important when there are more devices connected to the same SPI bus. Often there are also weak internal pull-ups integrated in the IC so that the external ones become redundant.
Kidn regards,
André
Thanks for the quick answer, André !
Do you happen to know an other place/forum where they deal with both RFM69 and NRF905 ?
Cheers,
Ronald
Hi!
You could try looking at another library called “RadioHead”:
http://www.airspayce.com/mikem/arduino/RadioHead/
On the main page it says that support for both devices is included. But I don’t know if the (default) settings are compatible.
Other than that, sorry, I have no idea.
Still I hope this helps.
Kind regards,
André
Hi André.. I´m Eugenio from Argentina.. thanx for your work.. I´m trying to set the fequency in 425Mhz and read RSSI values to compare with a value saved in a variable in an infinity loop, if the RSSI value readed is higher than the value saved, then, a D output must be set to High .. I used RFM69CW-433S2 join to STM32F030… how can I do that? I can´t find any example to be modified.. thanx again!