Working to debug new RadioHead (RH) library working with the RFM22 radio. Should be same for RFM69. For Teensy, RH is beta.
Changes so far:
Assuming you are not using software SPI (bit banging):
in RHHardwareSPI.cpp, the work around for the SPI.setDataMode(SPI_MODE0) problem is in this code.
Code:
void RHHardwareSPI::begin()
{
#if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_UNO32)
uint8_t dataMode;
if (_dataMode == DataMode0)
dataMode = SPI_MODE0;
else if (_dataMode == DataMode1)
dataMode = SPI_MODE1;
else if (_dataMode == DataMode2)
dataMode = SPI_MODE2;
else if (_dataMode == DataMode3)
dataMode = SPI_MODE3;
else
dataMode = SPI_MODE0;
// ADD these. Temporary work-around due to problem where avr_emulation.h does not work properly for the setDataMode() call made within the new RH lib.
SPCR &= ~SPI_MODE_MASK; // mode 0 SPI.setDataMode(dataMode);
Serial.printf("RHHardwareSPI.cpp says SPI.setDataMode(%d) changed to SPCR &= ~SPI_MODE_MASK, mode=0\n", dataMode);
And in RH_RF22.cpp - and I'd assume the same needs to be added to the RH_RF69.cpp, I added the code in the bottom of this segment:
Code:
bool RH_RF22::init()
{
if (!RHSPIDriver::init())
return false;
// Software reset the device
reset();
// Get the device type and check it
// This also tests whether we are really connected to a device
_deviceType = spiRead(RH_RF22_REG_00_DEVICE_TYPE);
if ( _deviceType != RH_RF22_DEVICE_TYPE_RX_TRX
&& _deviceType != RH_RF22_DEVICE_TYPE_TX)
{
return false;
}
// Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr>
#if defined (__MK20DX128__) || defined (__MK20DX256__)
// ARM M4 requires the below.. else pin interrupt doesn't work properly.
pinMode(_interruptPin, INPUT);
#endif
It was in the RF22 lib from the person named above but it didn't get into the RH version.
I'm still testing. Some items include missing code to enable promiscuous mode.
Note too that
the modulation mode table indexes changed-two new modes were added near the top of the table. So if you were using, say, index number 16, it is now 18. The default modulation mode is a very slow/conservative bit rate/channel width.
At this point, I have the RFM22 interrupts and transmit going. But my four radio star network with sniffer is not yet working as it did with the RF22 library. Something wrong with the addressing because I see receiver interrupts as frames arrive from the sending node.
=======
Added 23Apr14 16:23PT ===============
Add this code to enable promiscuous mode. The RH driver's setPromiscuous() method updates a variable but I have yet to see how it gets sent to hardware (reliable datagram use case).
Below "radioDriver" is the name of an instance of the
two classes needed with the RH lib+ReliableDatagram (only one class instance was needed for the RF22 lib). Seems to be so
because not all methods in the low level driver for the radio are inherited by the datagram and reliable datgram as they were in the RF22 lib.
Example:
Code:
RH_RF22 radioDriver;
RHReliableDatagram radioManager(radioDriver, 2);
Add something similar to the below for using promiscous mode:
Code:
radioDriver.setPromiscuous(config.role == role_sniffer); // does not affect radio hardware, so...
// write directly to radio for now. The class driver does not seem do so for setPromiscuous or other config items.
radioDriver.spiWrite(RH_RF22_REG_43_HEADER_ENABLE3, config.role == role_sniffer ? 0x00 : 0xff);//0's disables matching
I'm determining if other things like frequency, modulation mode, antenna switching bits can be changed at run time rather than only compile time.
My apps need to change freq., modulation mode, TX power, etc. at run time via a user interface (do so only in idle state).
MAX message size/buffer size in driver
Beware of this definition in the radio .h file (RF22, RF69, et al)
Code:
#define RH_RF22_MAX_MESSAGE_LEN 255
//#define RH_RF22_MAX_MESSAGE_LEN 50
I use 255 because the Teensy has plenty of RAM. The default is 50. Odd symptoms if message received is too large vs. this constant.
Confusing: The radio .h file has RH_RFM22_MAX_MESSAGE_LEN. The Reliable Datagram has RH_MAX_MESSAGE_LEN (no RF22 in the name). The buffer in the radio driver uses the former.
Don't use more than 255.
There is ONE receiver buffer in the drivers. It isn't double-buffered so you must quickly copy out the data and post another read if messages can come back-to-back, e.g., a star topology.
In reliable datagram mode, any one node can't send again until ACK is received. But in a star/mesh some other node may send on the tail of a different node's message
========= 24April2014============
This is a fix or a work-around for a larger problem in RH_ReliableDatagram. Applies to all radio types.
Problem:
A Node's address can be given at compile time in which case the class constructor receives the node address.
Also, the intention is that the method setThisAddress
can be used to change the node's address at run-time. A number stored in EEPROM would be recalled and used with setThisAddress().
For the Reliable Datagram case, this does not work correctly. The result is that the node maintains its compile-time address, thus the node can't be properly addressed.
A solution or work-around
In RHDatagram.cpp add one line of code:
Code:
Code:
void RHDatagram::setThisAddress(uint8_t thisAddress)
{
_driver.setThisAddress(thisAddress);
#pragma message "is this a cure for ReliableDatagram skipping Datagram's _thisAddress?"
_thisAddress = thisAddress; // local copy << ADD THIS LINE OF CODE
// Use this address in the transmitted FROM header
setHeaderFrom(thisAddress);
}
It is confusing that _thisAddress exists in the driver, in the RHDatagram, and in the RHReliableDatagram. A C++ wizard might know how this is supposed to work in terms of inheritance/priorities rather than keeping multiple copies of the same item in sync up the stack.
NOTE: I have not checked if the same issue exists for the mesh protocol.
========= 24April2014-1============
Problem:
RF22M and RFM69 radios: setPromiscuous(bool) was not in the .h for the class, nor coded in the .cpp as a
public method. Needs to be called at run time, but only if radio is in idle state.
========= 24April2014-2============
All radios: some methods, esp. in drivers, if called while not in idle state, will sometimes crash - because these access the radio via SPI, and receive or transmit interrupt will conflict with use of SPI.
Solution could be driver (force idle state) or in app "don't do that- change to idle mode".
Best would be for driver to return false on these calls if state is not idle, e.g., get temperature, get RSSI, set frequency, set modulation, ...
========= 24April2014-3============
Made a couple of changes to the RH_RF69 .h and .cpp files to reflect same changes that were made to the RH_RF22 files.
each change has a #pragma message "explanation of situation" - which will be on the console output during a compilation.
Be sure to watch for these.
========= 25April2014============
Improvement suggestion: Several places in libraries have "spin-loops" that loop until a variable/flag is altered by the interrupt service routine (ISR) for the radio. Such as transmit complete, message received, etc. At each spin loop, there should be a call to
yield(). This is in the Arduino and Teensyduino core. By default, yield() does nothing. It can be overridden by added task schedulers or other code, to use the CPU productively.
========= 25April2014============
RH_RF22.cpp change 1 of 2, below, in the class init. It now calls function rather than set = 0. matches change #2, below.
Around line #150:
Code:
#pragma message "changed this to call a function herein so antenna control bits can be set at run time."
setGpioReversed(_gpioReversed);
// Enable interrupts
RH_RF22.cpp change 2 of 2, below. Moved code from init section to this function. Reversed the 0x12, 0x15 to match _gpioReversed = 0 for HopeRF modules, 1 for Dorji and some other brands.
Code:
// should call this only in idle state.
void RH_RF22::setGpioReversed(bool reversed) {
_gpioReversed = reversed;
// Ensure the antenna can be switched automatically according to transmit and receive
// This assumes GPIO0(out) is connected to TX_ANT(in) to enable tx antenna during transmit
// This assumes GPIO1(out) is connected to RX_ANT(in) to enable rx antenna during receive
if (_gpioReversed)
{
// Reversed for HAB-RFM22B-BOA HAB-RFM22B-BO, also Si4432 sold by Dorji.com via Tindie.com.
spiWrite(RH_RF22_REG_0B_GPIO_CONFIGURATION0, 0x12) ; // RX state
spiWrite(RH_RF22_REG_0C_GPIO_CONFIGURATION1, 0x15) ; // TX state
}
else
{
spiWrite(RH_RF22_REG_0B_GPIO_CONFIGURATION0, 0x15) ; // TX state
spiWrite(RH_RF22_REG_0C_GPIO_CONFIGURATION1, 0x12) ; // RX state
}
}
Tested the changes with both HopeRF RFM22 and Dorji modules which have opposite GPIO-TXRX switch hard-wired via PCB traces.
========= 3May2014============
RadioHead for RFM69 radios.
Symptom: Software hangs waiting for first interrupt
Applies to: RadioHead 1.5 and older. <<<<<<<<<<<< CHANGED. Was 1.7 and older.
The below is already in RadioHead 1.7 and later!
Solution:
In library file RH-RF69.cpp located in the Arduino libraries folders such as (PC/Windows):
C:\Arduino\libraries\RadioHead1_5\RH_RF69.cpp
Move the pinMode() which was added for the Teensy MK20 CPU. Move the pinMode() and enclosing #if and #endif from where it was as published, to just above the attachInterrupt() calls.
Below is what it looks like after the move:
Code:
...
// Add by Adrien van den Bossche <vandenbo@univ-tlse2.fr> for Teensy
#if defined (__MK20DX128__) || defined (__MK20DX256__)
// ARM M4 requires the below. else pin interrupt doesn't work properly.
pinMode(_interruptPin, INPUT);
#endif
_deviceForInterrupt[_interruptCount] = this;
if (_interruptCount == 0)
attachInterrupt(_interruptPin, isr0, RISING);
...
========= 3May2014-1============
Tested OK with
RadioHead 1.7 (must have for Teensy)
RFM69 radio on Teensy 3.1 and on Anarduino AVR mega32 board.
These two MCUs swap messages using the test program 2nd version uploaded as an attachment in these threads.
Next is to test RadioHead with RFM22 radios - had worked OK with older RadioHead version.
========= 3May2014-2============
Latest version of two-node test program:'
Purpose of program: First-use troubleshooting aid for two radios. Same code on both. MCUs controller these radios may differ, e.g., AVR plusTeensy 3 ARM.
Change source code #define for frequency. Now set to 433MHz and default modulation mode.
Compiled for RF69 radios. Change class names in code to use RFM22 (or other?)
Usage:
- Uses default SPI port. On Teensy 3 ARM, the SPI clock is moved to pin 14.
- Pin 13 is remapped back to the LED. This is done after the SPI port initializes as it undoes this.
- edit source as above. compile and download to each of two radios. Change LED pin # if need be.
- Open terminal window promptly.
- LED on board should go on, then off if hardware init scuceeded (e.g., SPI port connections)
- Terminal program should show that first transmission succeed and a transmit complete interrupt occurred OK.
- The two nodes (radio+MCU) now exchange messages every second or so.
- Each node chooses which node address to use to ensure each node's address differs (client/server IDs in the #defines).
- If a node receives no message in 5 seconds, it broadcasts a message and tries to receive again. Forever.
- For each message received, terminal displays from,id,rssi,message text
- While in this loop, LED is on when message is received and until ACK is sent
========= 9May2014============
RH_RF69 lib v1.8 - new
Note for RF69 users: default Transmitter power is +13dBm which is the max that the RF69W does. For the RF69HW your app may change to +18 if you need that.
The RF69W, if set above +13, seems to disable the transmitter entirely.
But in v1.8 - no interrupts. It's because v1.8 changed the default pin number from 0 to 2. Affects any MCU that had been wired up for pin 0.
So in your application, code this, or any other pin #
add these in your application
// for RFM69 module variants
#define RF69_1_SLAVE_SELECT_PIN SS // 10
#define RF69_1_INTERRUPT_PIN 2
Then in your app, change the instance of the radio driver class as:
// Singleton instance of the radio driver.
// Override the default pin numbers...
RH_RF69 driver (RF69_1_SLAVE_SELECT_PIN, RF69_1_INTERRUPT_PIN);
I'm testing the new modulation mode constants in v1.8. V1.7 had some values that did not work properly.
For this, I am about finished with a newer/better test / demo program which I'll upload.
steve
EDIT
to correct typo above: { should have been ( in two places
The pin # change was in the release notes but I missed it.