Last active
September 19, 2024 14:43
-
-
Save SyncChannel/b5c099a8eb8e7235aa8c to your computer and use it in GitHub Desktop.
LoRa FeatherWing IOX Beacon Mode Example Program
This file contains hidden or 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 Beacon Mode Example Program | |
* By: Dan Watson | syncchannel.blogspot.com | |
* Date: 3-12-2016 | |
* Version: 0.1 Initial Release | |
* | |
* Example Beacon Mode Program for the LoRa FeatherWing IOX for Adafruit Feather | |
* Tested with Feather M0, 32U4, and HUZZAH ESP8266 | |
* However, you only have one analog input on HUZZAH (1V input max!) | |
* | |
* This program configures the Feather as a transmit-only beacon. It transmits a payload of data | |
* at a set interval using the LoRa long range wireless protocol. This program is intended as | |
* a companion to the LoRA FeatherWing IOX Tranceiver Example Program, which can receive the | |
* beacon transmissions, or the Adafruit IO Gateway Program, which can also upload the data to | |
* your Adafruit IO feeds | |
* | |
* 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. | |
* | |
* Based on a library by Gerben den Hartog | |
* https://github.com/Ideetron/RFM95W_Nexus | |
* http://www.ideetron.nl/LoRa | |
* | |
* 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 13 //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 output (for HUZZAH ESP8266) (optional) | |
#define LEDINVERT false | |
// 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 | |
// Message counter will increment every time a message is sent | |
uint16_t messageCounter = 0; | |
// Holder for the user data payload bytes | |
uint8_t RFM_Tx_Package[PACKAGE_LENGTH]; | |
// 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() | |
{ | |
//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); | |
// Load header info into the payload | |
RFM_Tx_Package[0] = 0xD7; // First two bytes are always D7 D7 | |
RFM_Tx_Package[1] = 0xD7; | |
RFM_Tx_Package[2] = 0x20; // Node address | |
RFM_Tx_Package[3] = 0x01; // Message type 0x01 = Temperature Report | |
RFM_Tx_Package[4] = 0x00; // Will be High byte of sensor data | |
RFM_Tx_Package[5] = 0x00; // Will be Low byte of sensor data | |
RFM_Tx_Package[6] = 0x00; // Will be High byte of battery voltage reading | |
RFM_Tx_Package[7] = 0x00; // Will be Low byte of battery voltage reading | |
RFM_Tx_Package[8] = 0x00; // Will be High byte of message counter | |
RFM_Tx_Package[9] = 0x00; // Will be Low byte of message counter | |
//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() | |
{ | |
uint32_t gotMillis = millis() + 5000; | |
digitalWrite(LED, HIGH^LEDINVERT); | |
messageCounter++; | |
// Get sensor reading (MCP-9701 temperature sensor) and battery voltage reading | |
// The data will be sent as raw analog readings. The receiving node will do conversions | |
uint16_t sensor_holder = analogRead(A0); // Raw sensor reading | |
uint16_t batt_holder = analogRead(A7); // Battery voltage reading. Read A7 for Feather M0, and A9 for 32U4 | |
// Update the payload contents | |
RFM_Tx_Package[4] = (sensor_holder >> 8); | |
RFM_Tx_Package[5] = sensor_holder; | |
RFM_Tx_Package[6] = (batt_holder >> 8); | |
RFM_Tx_Package[7] = batt_holder; | |
RFM_Tx_Package[8] = (messageCounter >> 8); | |
RFM_Tx_Package[9] = messageCounter; | |
// Send the payload! | |
RFM_SendPackage(RFM_Tx_Package); | |
// At higher Spreading Factors, the transmission takes long enough to make the LED blink visible | |
// Add a slight delay if you want the LED notification of a transmission to be longer | |
// delay(50); | |
digitalWrite(LED, LOW^LEDINVERT); | |
while(gotMillis > millis()) | |
{ | |
// Make the main loop take five seconds to complete every time | |
// For ESP8266, include a small delay to prevent the watchdog from timing out | |
delay(10); | |
} | |
} | |
/* | |
* 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