Skip to content

Instantly share code, notes, and snippets.

@SyncChannel
Created March 17, 2016 01:15
Show Gist options
  • Save SyncChannel/2747e1f0950495a396ee to your computer and use it in GitHub Desktop.
Save SyncChannel/2747e1f0950495a396ee to your computer and use it in GitHub Desktop.
LoRa FeatherWing IOX Tranceiver Mode Example Program
/* LoRa FeatherWing IOX Tranceiver Mode Example Program
* By: Dan Watson | syncchannel.blogspot.com
* Date: 3-12-2016
* Version: 0.1 Initial Release
*
* Example Tranceiver Mode Program for the LoRa FeatherWing IOX for Adafruit Feather
* Tested with Feather M0, 32U4 and HUZZAH ESP8266
*
* This program configures the Feather as a LoRa receiver. It is intended as a companion
* to the LoRA FeatherWing Beacon Example Program, and can receive the beacon messages.
* It can also be modified to relay serial communications between Feather nodes, amongst
* other things.
*
* This program is adapted from the RFM95W_Nexus library created by Gerben den Hartog
* It has been adapted from his code to work specifically on Adafruit Feather with
* the LoRa FeatherWing. Credit is given to Gerben for is useful library and work!
* Check out his full github repo if you are interested in LoRaWAN.
*
* This program also uses the Adafruit MCP-23008 library, which can be downloaded in
* the Arduino Library Manager. See these pages for more info:
* https://github.com/adafruit/Adafruit-MCP23008-library
* https://www.adafruit.com/products/593
*
*/
// SPI is used for the RFM module. I2C is used for the MCP-23008.
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_MCP23008.h"
// Define GPIO pin descriptions
#define LED 0 //13 for M0/32U4, 0 for HUZZAH ESP8266
// Also define the pin you selected for the MCP-23008 interrupt, if desired
// You don't need it when using the Adafruit library
// Define I/O expander connections to RFM module. These are hard wired.
#define DIO0 5
#define DIO1 6
#define DIO2 7
#define DIO3 3
#define DIO4 4
#define DIO5 0
#define CS 2
#define RFM_RESET 1
// Set this true to invert the LED outputs (for HUZZAH ESP8266) (optional)
#define LEDINVERT true
// Set frequency of RFM module
// Available frequencies depend on which RFM module you have
#define RFM_FREQ_MHZ 915000000
// Define the length of the user message payload in bytes
#define PACKAGE_LENGTH 10
// The Adafruit MCP-23008 library is very easy to use. To access a pin on the RFM module,
// use the standard digitalRead and digitalWrite commands with "iox." in front.
Adafruit_MCP23008 iox;
void setup()
{
Serial.begin(9600);
//Initialize SPI
SPI.begin();
SPI.beginTransaction(SPISettings(4000000,MSBFIRST,SPI_MODE0));
iox.begin(); // Default address
//Initialize I/O pins on MCP-23008
iox.pinMode(DIO0,INPUT);
iox.pinMode(DIO5,INPUT);
iox.pinMode(CS,OUTPUT);
// Initialize normal GPIO on the Feather
pinMode(LED,OUTPUT);
// Pull chip select high for now
iox.digitalWrite(CS,HIGH);
// Minimum of 100ms recommended to allow RFM module to start up
delay(200);
//Initialize the RFM module
RFM_Init();
// Flash LED on Feather to notify user that setup is complete
for (int i = 0; i <= 3; i++)
{
digitalWrite(LED, HIGH^LEDINVERT);
delay(100);
digitalWrite(LED, LOW^LEDINVERT);
delay(200);
}
}
void loop()
{
//Check if the RFM has received a package
if(iox.digitalRead(DIO0) == HIGH)
{
digitalWrite(LED, HIGH^LEDINVERT);
//Get package from RFM
unsigned char RFM_Package[PACKAGE_LENGTH];
RFM_ReadPackage(RFM_Package);
if (RFM_Package[0] == 0xD7 && RFM_Package[1] == 0xD7) // Valid message
{
//Send report over serial
Serial.print("Got message from Node 0x");
Serial.println(RFM_Package[2], HEX);
Serial.print("Raw Message: [ ");
for(int i = 0; i < PACKAGE_LENGTH; i++)
{
if (RFM_Package[i] < 0x10)
Serial.print("0");
Serial.print(RFM_Package[i], HEX);
Serial.print(" ");
}
Serial.println("]");
if (RFM_Package[3] == 0x01) // This is a temperature report
{
double temp = (RFM_Package[4] << 8) | RFM_Package[5];
temp = (temp*3.22 - 400) / 19.5; // Temp in degrees C, equation for MCP-9701
double batt = (RFM_Package[6] << 8) | RFM_Package[7];
batt = batt*6.44; // *3.22 to convert to mV, *2 due to divider
uint16_t messageCounter = (RFM_Package[8] << 8) | RFM_Package[9];
Serial.print("Temp: ");
Serial.print(temp);
Serial.print("*C | Batt: ");
Serial.print(batt / 1000);
Serial.print("V | Msg Count: ");
Serial.println(messageCounter);
}
} else {
Serial.println("Invalid Message Received!");
}
Serial.println("");
delay(50);
digitalWrite(LED, LOW^LEDINVERT);
}
}
/*
* Function to initialize the RFM module.
* It is highly recommended that you read the datasheet for the module, there are lots of
* settings you can adjust to improve the wireless link parameters for your specific usage
* http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf
*/
void RFM_Init()
{
//Set RFM module in sleep mode to change to LoRa mode
RFM_Write(0x01,0x00);
//Set LoRa mode
RFM_Write(0x01,0x80);
//Set RFM module in standby mode to change more settings
RFM_Write(0x01,0x81);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
// Set carrier frequency
// RFM_FREQ_MHZ / 61.035 Hz = 3 byte value to load
unsigned long freqHolder = RFM_FREQ_MHZ / 61.035; // round down
uint8_t freqLSB = freqHolder;
uint8_t freq2B = (freqHolder >> 8);
uint8_t freqMSB = (freqHolder >> 16);
RFM_Write(0x06,freqMSB);
RFM_Write(0x07,freq2B);
RFM_Write(0x08,freqLSB);
//Set maximum transmit power settings
RFM_Write(0x09,0xFF);
//Set bandwith 250 kHz, Coding rate = 4/8, Implicit header mode
RFM_Write(0x1D,0x89);
//Spreading factor 11, PayloadCRC on
RFM_Write(0x1E,0xB4);
//*NOTE: If you decide to change to Spreading Factor 6, you also need to set the following
//*two registers by uncommenting these lines
//RFM_Write(0x31,0xC5);
//RFM_Write(0x37,0x0C);
//Preamble length 0x0018 + 4 = 28
RFM_Write(0x20,0x00);
RFM_Write(0x21,0x18);
//Payload length
RFM_Write(0x22,PACKAGE_LENGTH);
//Set RFM in continues receive
RFM_Write(0x01,0x85);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
}
/* This function is used to read a value from a specific register of the RFM module
* Arguments: RFM_Adress Adress of the register to read
* Return: The value of the register is returned
*/
unsigned char RFM_Read(unsigned char RFM_Address)
{
unsigned char RFM_Data;
//Set CS pin low to start SPI communication
iox.digitalWrite(CS,LOW);
//Send Address
SPI.transfer(RFM_Address);
//Send 0x00 to receive the answer from the RFM
RFM_Data = SPI.transfer(0x00);
//Set CS high to end communication
iox.digitalWrite(CS,HIGH);
//Return received data
return RFM_Data;
}
/* This function is used to write a value to a specific register of the RFM module
* Arguments: RFM_Adress Adress of the register to be written
* RFM_Data Data that will be written
*/
void RFM_Write(unsigned char RFM_Address, unsigned char RFM_Data)
{
//Set CS pin low to start communication
iox.digitalWrite(CS,LOW);
//Send Addres with MSB 1 to make it a write command
SPI.transfer(RFM_Address | 0x80);
//Send Data
SPI.transfer(RFM_Data);
//Set CS pin high to end communication
iox.digitalWrite(CS,HIGH);
}
/* This function is used to send a message payload
* Arguments: *RFM_Package Pointer to the array with the data to send
*/
void RFM_SendPackage(unsigned char *RFM_Package)
{
//Switch RFM to standby
RFM_Write(0x01,0x81);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
//Set SPI pointer to Tx base address
RFM_Write(0x0D,0x80);
//Switch DIO to TxDone
RFM_Write(0x40,0x40);
//Write payload in to the FIFO
for(int i = 0; i < PACKAGE_LENGTH; i++)
{
RFM_Write(0x00,*RFM_Package);
RFM_Package++;
}
//Switch RFM to TX
RFM_Write(0x01,0x83);
while(iox.digitalRead(DIO0) == LOW)
{
//Wait for Tx Done
}
//Clear interrupt
RFM_Write(0x12,0x08);
//Set DIO0 to RxDone
RFM_Write(0x40,0x00);
//Set RFM in continues receive
RFM_Write(0x01,0x85);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
}
/* This function is used to receive a message/payload from the RFM module
* Arguments: *RFM_Package Pointer to the array with the data to send
*/
void RFM_ReadPackage(unsigned char *RFM_Package)
{
unsigned char RFM_Interrupt;
unsigned char RFM_PackageLocation;
//Get interrupt register
RFM_Interrupt = RFM_Read(0x12);
//Switch RFM to Standby
RFM_Write(0x01,0x81);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
//Clear interrupt register
RFM_Write(0x12,0x60);
//Get package location
RFM_PackageLocation = RFM_Read(0x10);
//Set SPI pointer to Packagelocation
RFM_Write(0x0D,RFM_PackageLocation);
//Get message
for(int i = 0; i < PACKAGE_LENGTH; i++)
{
*RFM_Package = RFM_Read(0x00);
RFM_Package++;
}
//Switch RFM to receive
RFM_Write(0x01,0x85);
while(iox.digitalRead(DIO5) == LOW)
{
//Wait for mode ready
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment