
This program is guided to help establish a connection between two RFM95 900MHz LoRa radio modules using Maxim Integrated's Feather MCUs (MAX32630FTHR Mbed and the MAX32620FTHR Mbed). Once the radios are configured after powering on and if the radios are wired correctly, the two radios will self identify as either a master or a slave, and will then proceed to PING and PONG back and forth. Information about what is happening between the radios can be seen if the two boards are hooked up to a USB COM port through the included DAPLINK modules.
Dependencies: BMI160 BufferedSerial SX1276GenericLib USBDeviceHT max32630fthr
Fork of MAX326xxFTHR_LoRa_RFM95 by
RFM95 LoRa Example Ping Pong Program
Getting Started
This program has the support for sx1276 (Adafruit RFM95W LoRa Radio Transceiver Breakout - 900 MHz) and (Adafruit LoRa Radio FeatherWing - RFM95W 900 MHz) to work with a few different mbed boards (see PinMap.h for supported boards). However, this specific program is set up to work with the following mbed boards and RFM95 915MHz LoRa radios and the given pin diagrams without modifications: MAX32620FTHR and MAX32630FTHR.
Configuring the LoRa Radio
The setup for the radio can be found in <<SX1276GenericPingPong/GenericPingPong.cpp>>
, which can be found by navigating from the root directory. Setup for the radio starts on line #14 in <<SX1276GenericPingPong/GenericPingPong.cpp>>
.
Choosing the Correct Frequency
This program was written with libraries compatible with RFM95 LoRa 900MHz Radio modules. The radio's frequency is able to be tuned dynamically, however this program configures the frequency by programming registers at device power on. The 900MHz module supports both 868MHz and 915MHz operation. Check local laws for which band around 900MHz is set aside for the scientific, commercial, and/or license free usage in your country. The supported frequencies can be found in <<SX1276GenericLib.lib/sx1276/sx1276.h>>
They are also listed below for convenience:
SX1276GenericLib.lib/sx1276/sx1276.h
typedef enum { RF_FREQUENCY_868_0 = 868000000, //Hz RF_FREQUENCY_868_1 = 868100000, //Hz RF_FREQUENCY_868_3 = 868300000, //Hz RF_FREQUENCY_868_5 = 868500000, //Hz RF_FREQUENCY_915_0 = 915000000, //Hz RF_FREQUENCY_915_1 = 915100000, //Hz RF_FREQUENCY_915_3 = 915300000, //Hz RF_FREQUENCY_915_5 = 915500000, //Hz } rf_frequency_t;
Please chose a supported frequency above that is compatible with your RFM95 (or likewise single band compatible sx1276 radio) module and change line #22 in <<SX1276GenericPingPong/GenericPingPong.cpp>>
to the correct enum above.
Wiring
This program is aimed at working without modifications with RFM95W LoRa 900MHz modules in both a Breakout board and a FeatherWing version.
FeatherWing setup
This wiring diagram is useful if your RFM95W LoRa 900MHz module is a Feather wing made by Adafruit.
Before jumpers are soldered in:
After jumpers are soldered in:
Note: The default pin configurations for the radio in this program (found in <<PinMap.h>>
under targets MAX32630FTHR and MAX32630FTHR ) can be changed to suite additional modifications built from a fork of this program repo. If this is the case, the diagrams above will need to be changed to suite the new pin map.
For more information, a detailed wiring guide for the RFM95W Featherwing can be found here.
Breakout Board
For a breakout board, the following wiring diagram will work with both the MAX32630FTHR and the MAX32630FTHR mbed boards if wired in the same locations:
Before the RFM95W is connected with wires:
After the RFM95W is connected with wires:
The representations of the connections above can be found in<<PinName.h>>
under targets MAX32630FTHR and MAX32630FTHR.
This default pin configuration will set you up with a connection to the MCU.
For more information, a detailed wiring guide for the RFM95W Brakout Board can be found here.
Antenna
Since this is radio communication, we are going to need antennas to be attached to both of the Radios used in this example.
For more information on how to solder an antenna to the RFM95, please click here
SX1276GenericPingPong/GenericPingPong.cpp
- Committer:
- Helmut64
- Date:
- 2017-05-10
- Revision:
- 1:65d602e2d746
- Parent:
- 0:c43b6919ae15
- Child:
- 3:dc560d3e9070
File content as of revision 1:65d602e2d746:
/* * This file contains a copy of the master content sx1276PingPong * with adaption for the SX1276Generic environment * (c) 2017 Helmut Tschemernjak * 30826 Garbsen (Hannover) Germany */ #include "mbed.h" #include "PinMap.h" #include "GenericPingPong.h" #include "sx1276-mbed-hal.h" #include "main.h" #ifdef FEATURE_LORA /* Set this flag to '1' to display debug messages on the console */ #define DEBUG_MESSAGE 1 /* Set this flag to '1' to use the LoRa modulation or to '0' to use FSK modulation */ #define USE_MODEM_LORA 1 #define USE_MODEM_FSK !USE_MODEM_LORA #define RF_FREQUENCY RF_FREQUENCY_868_1 // Hz #define TX_OUTPUT_POWER 14 // 14 dBm #if USE_MODEM_LORA == 1 #define LORA_BANDWIDTH LORA_BANKWIDTH_125kHz #define LORA_SPREADING_FACTOR LORA_SF7 #define LORA_CODINGRATE LORA_ERROR_CODING_RATE_4_5 #define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx #define LORA_SYMBOL_TIMEOUT 5 // Symbols #define LORA_FIX_LENGTH_PAYLOAD_ON false #define LORA_FHSS_ENABLED false #define LORA_NB_SYMB_HOP 4 #define LORA_IQ_INVERSION_ON false #define LORA_CRC_ENABLED true #elif USE_MODEM_FSK == 1 #define FSK_FDEV 25000 // Hz #define FSK_DATARATE 19200 // bps #define FSK_BANDWIDTH 50000 // Hz #define FSK_AFC_BANDWIDTH 83333 // Hz #define FSK_PREAMBLE_LENGTH 5 // Same for Tx and Rx #define FSK_FIX_LENGTH_PAYLOAD_ON false #define FSK_CRC_ENABLED true #else #error "Please define a modem in the compiler options." #endif #define RX_TIMEOUT_VALUE 3500 // in ms //#define BUFFER_SIZE 32 // Define the payload size here #define BUFFER_SIZE 64 // Define the payload size here /* * Global variables declarations */ typedef enum { LOWPOWER = 0, IDLE, RX, RX_TIMEOUT, RX_ERROR, TX, TX_TIMEOUT, CAD, CAD_DONE } AppStates_t; volatile AppStates_t State = LOWPOWER; /*! * Radio events function pointer */ static RadioEvents_t RadioEvents; /* * Global variables declarations */ SX1276Generic *Radio; const uint8_t PingMsg[] = { 0xff, 0xff, 0x00, 0x00, 'P', 'I', 'N', 'G'};// "PING"; const uint8_t PongMsg[] = { 0xff, 0xff, 0x00, 0x00, 'P', 'O', 'N', 'G'};// "PONG"; uint16_t BufferSize = BUFFER_SIZE; uint8_t *Buffer; DigitalOut *led3; int SX1276PingPong() { #if( defined ( TARGET_KL25Z ) || defined ( TARGET_LPC11U6X ) ) DigitalOut *led = new DigitalOut(LED2); #elif defined(TARGET_NUCLEO_L073RZ) DigitalOut *led = new DigitalOut(LED4); // RX red led3 = new DigitalOut(LED3); // TX blue #else DigitalOut *led = new DigitalOut(LED1); led3 = led; #endif Buffer = new uint8_t[BUFFER_SIZE]; *led3 = 1; #ifdef B_L072Z_LRWAN1_LORA Radio = new SX1276Generic(NULL, MURATA_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5, LORA_ANT_RX, LORA_ANT_TX, LORA_ANT_BOOST, LORA_TCXO); #else // RFM95 Radio = new SX1276Generic(NULL, RFM95_SX1276, LORA_SPI_MOSI, LORA_SPI_MISO, LORA_SPI_SCLK, LORA_CS, LORA_RESET, LORA_DIO0, LORA_DIO1, LORA_DIO2, LORA_DIO3, LORA_DIO4, LORA_DIO5); #endif uint8_t i; bool isMaster = true; dprintf("SX1276 Ping Pong Demo Application" ); dprintf("Freqency: %.1f", (double)RF_FREQUENCY/1000000.0); dprintf("TXPower: %d dBm", TX_OUTPUT_POWER); #if USE_MODEM_LORA == 1 if (LORA_BANDWIDTH == LORA_BANKWIDTH_125kHz) { dprintf("Bandwidth: %d kHz", 125); } else if (LORA_BANDWIDTH == LORA_BANKWIDTH_250kHz) { dprintf("Bandwidth: %d kHz", 250); } else if (LORA_BANDWIDTH == LORA_BANKWIDTH_500kHz) { dprintf("Bandwidth: %d kHz", 500); } else { dprintf("Unkown Bandwidth: %d kHz", LORA_BANDWIDTH); } dprintf("Spreading factor: SF%d", LORA_SPREADING_FACTOR); #elif USE_MODEM_FSK == 1 dprintf("Bandwidth: %d kHz", FSK_BANDWIDTH); dprintf("Baudrate: %d", FSK_DATARATE); #endif // Initialize Radio driver RadioEvents.TxDone = OnTxDone; RadioEvents.RxDone = OnRxDone; RadioEvents.RxError = OnRxError; RadioEvents.TxTimeout = OnTxTimeout; RadioEvents.RxTimeout = OnRxTimeout; Radio->Init( &RadioEvents ); // verify the connection with the board while( Radio->Read( REG_VERSION ) == 0x00 ) { dprintf("Radio could not be detected!"); wait( 1 ); } switch(Radio->DetectBoardType()) { case SX1276MB1LAS: if (DEBUG_MESSAGE) dprintf(" > Board Type: SX1276MB1LAS <"); break; case SX1276MB1MAS: if (DEBUG_MESSAGE) dprintf(" > Board Type: SX1276MB1LAS <"); case MURATA_SX1276: if (DEBUG_MESSAGE) dprintf(" > Board Type: MURATA_SX1276_STM32L0 <"); break; case RFM95_SX1276: if (DEBUG_MESSAGE) dprintf(" > HopeRF RFM95xx <"); break; default: dprintf(" > Board Type: unknown <"); } Radio->SetChannel(RF_FREQUENCY ); #if USE_MODEM_LORA == 1 if (LORA_FHSS_ENABLED) dprintf(" > LORA FHSS Mode <"); if (!LORA_FHSS_ENABLED) dprintf(" > LORA Mode <"); Radio->SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON, LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, LORA_IQ_INVERSION_ON, 2000 ); Radio->SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR, LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH, LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON, 0, LORA_CRC_ENABLED, LORA_FHSS_ENABLED, LORA_NB_SYMB_HOP, LORA_IQ_INVERSION_ON, true ); #elif USE_MODEM_FSK == 1 dprintf(" > FSK Mode <"); Radio->SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0, FSK_DATARATE, 0, FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON, FSK_CRC_ENABLED, 0, 0, 0, 2000 ); Radio->SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE, 0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH, 0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, FSK_CRC_ENABLED, 0, 0, false, true ); #else #error "Please define a modem in the compiler options." #endif if (DEBUG_MESSAGE) dprintf("Starting Ping-Pong loop"); Radio->Rx( RX_TIMEOUT_VALUE ); while( 1 ) { #ifdef TARGET_STM32L4 WatchDogUpdate(); #endif switch( State ) { case RX: *led3 = 0; if( isMaster == true ) { if( BufferSize > 0 ) { if( memcmp(Buffer, PongMsg, sizeof(PongMsg)) == 0 ) { *led = !*led; dprintf( "...Pong" ); // Send the next PING frame memcpy(Buffer, PingMsg, sizeof(PingMsg)); // We fill the buffer with numbers for the payload for( i = sizeof(PingMsg); i < BufferSize; i++ ) { Buffer[i] = i - sizeof(PingMsg); } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } else if( memcmp(Buffer, PingMsg, sizeof(PingMsg)) == 0 ) { // A master already exists then become a slave dprintf( "...Ping" ); *led = !*led; isMaster = false; // Send the next PONG frame memcpy(Buffer, PongMsg, sizeof(PongMsg)); // We fill the buffer with numbers for the payload for( i = sizeof(PongMsg); i < BufferSize; i++ ) { Buffer[i] = i - sizeof(PongMsg); } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } else // valid reception but neither a PING or a PONG message { // Set device as master ans start again isMaster = true; Radio->Rx( RX_TIMEOUT_VALUE ); } } } else { if( BufferSize > 0 ) { if( memcmp(Buffer, PingMsg, sizeof(PingMsg)) == 0 ) { *led = !*led; dprintf( "...Ping" ); // Send the reply to the PING string memcpy(Buffer, PongMsg, sizeof(PongMsg)); // We fill the buffer with numbers for the payload for( i = sizeof(PongMsg); i < BufferSize; i++ ) { Buffer[i] = i - sizeof(PongMsg); } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } else // valid reception but not a PING as expected { // Set device as master and start again isMaster = true; Radio->Rx( RX_TIMEOUT_VALUE ); } } } State = LOWPOWER; break; case TX: *led3 = 1; if( isMaster == true ) { dprintf("Ping..." ); } else { dprintf("Pong..." ); } Radio->Rx( RX_TIMEOUT_VALUE ); State = LOWPOWER; break; case RX_TIMEOUT: if( isMaster == true ) { // Send the next PING frame memcpy(Buffer, PingMsg, sizeof(PingMsg)); for( i = sizeof(PingMsg); i < BufferSize; i++ ) { Buffer[i] = i - sizeof(PingMsg); } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } else { Radio->Rx( RX_TIMEOUT_VALUE ); } State = LOWPOWER; break; case RX_ERROR: // We have received a Packet with a CRC error, send reply as if packet was correct if( isMaster == true ) { // Send the next PING frame memcpy(Buffer, PingMsg, sizeof(PingMsg)); for( i = 4; i < BufferSize; i++ ) { Buffer[i] = i - 4; } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } else { // Send the next PONG frame memcpy(Buffer, PongMsg, sizeof(PongMsg)); for( i = sizeof(PongMsg); i < BufferSize; i++ ) { Buffer[i] = i - sizeof(PongMsg); } wait_ms( 10 ); Radio->Send( Buffer, BufferSize ); } State = LOWPOWER; break; case TX_TIMEOUT: Radio->Rx( RX_TIMEOUT_VALUE ); State = LOWPOWER; break; case LOWPOWER: sleep(); break; default: State = LOWPOWER; break; } } } void OnTxDone( void ) { Radio->Sleep( ); State = TX; if (DEBUG_MESSAGE) dprintf("> OnTxDone"); } void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) { Radio->Sleep( ); BufferSize = size; memcpy( Buffer, payload, BufferSize ); State = RX; if (DEBUG_MESSAGE) dprintf("> OnRxDone: RssiValue=%d dBm, SnrValue=%d", rssi, snr); dump("Data:", payload, size); } void OnTxTimeout( void ) { *led3 = 0; Radio->Sleep( ); State = TX_TIMEOUT; if(DEBUG_MESSAGE) dprintf("> OnTxTimeout"); } void OnRxTimeout( void ) { *led3 = 0; Radio->Sleep( ); Buffer[BufferSize-1] = 0; State = RX_TIMEOUT; if (DEBUG_MESSAGE) dprintf("> OnRxTimeout"); } void OnRxError( void ) { Radio->Sleep( ); State = RX_ERROR; if (DEBUG_MESSAGE) dprintf("> OnRxError"); } #endif