Created
March 17, 2016 01:15
-
-
Save SyncChannel/2747e1f0950495a396ee to your computer and use it in GitHub Desktop.
LoRa FeatherWing IOX Tranceiver Mode Example Program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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