342 lines
8.3 KiB
C++
Executable file
342 lines
8.3 KiB
C++
Executable file
/*
|
|
RFM95.cpp - Library for RFM95 LoRa module.
|
|
Created by Leo Korbee, March 31, 2018.
|
|
Released into the public domain.
|
|
@license Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
|
Thanks to all the folks who contributed on the base of this code.
|
|
(Gerben den Hartog, et al - Ideetron.nl)
|
|
*/
|
|
|
|
#include "Arduino.h"
|
|
#include "RFM95.h"
|
|
#include <SPI.h>
|
|
|
|
// constructor
|
|
RFM95::RFM95(int DIO0, int NSS)
|
|
{
|
|
_DIO0 = DIO0;
|
|
_NSS = NSS;
|
|
// init tinySPI
|
|
SPI.setDataMode(SPI_MODE0);
|
|
SPI.begin();
|
|
}
|
|
|
|
|
|
/*
|
|
*****************************************************************************************
|
|
* Description: Function used to initialize the RFM module on startup
|
|
*****************************************************************************************
|
|
*/
|
|
void RFM95::init()
|
|
{
|
|
// set pinmodes input/output
|
|
pinMode(_NSS, OUTPUT);
|
|
pinMode(_DIO0, INPUT);
|
|
|
|
// Set default Datarate Config SF7BW125
|
|
_sf = 0x74;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
|
|
// NSS for starting and stopping communication with the RFM95 module
|
|
digitalWrite(_NSS, HIGH);
|
|
|
|
//Switch RFM to sleep
|
|
RFM_Write(0x01,0x00);
|
|
|
|
//Set RFM in LoRa mode
|
|
RFM_Write(0x01,0x80);
|
|
|
|
//Set RFM in Standby mode wait on mode ready
|
|
RFM_Write(0x01,0x81);
|
|
/*
|
|
while (digitalRead(DIO5) == LOW)
|
|
{
|
|
}
|
|
*/
|
|
delay(10);
|
|
|
|
//Set carrair frequency
|
|
// 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
|
|
RFM_Write(0x06,0xD9);
|
|
RFM_Write(0x07,0x06);
|
|
RFM_Write(0x08,0x8B);
|
|
|
|
// Minmal Power
|
|
//RFM_Write(0x09,0xF0);
|
|
|
|
//PA pin (maximal power)
|
|
RFM_Write(0x09,0xFF);
|
|
|
|
//BW = 125 kHz, Coding rate 4/5, Explicit header mode
|
|
RFM_Write(0x1D,0x72);
|
|
|
|
//Spreading factor 7, PayloadCRC On
|
|
RFM_Write(0x1E,0xB4);
|
|
|
|
//Rx Timeout set to 37 symbols
|
|
RFM_Write(0x1F,0x25);
|
|
|
|
//Preamble length set to 8 symbols
|
|
//0x0008 + 4 = 12
|
|
RFM_Write(0x20,0x00);
|
|
RFM_Write(0x21,0x08);
|
|
|
|
//Low datarate optimization off AGC auto on
|
|
RFM_Write(0x26,0x0C);
|
|
|
|
//Set LoRa sync word
|
|
RFM_Write(0x39,0x34);
|
|
|
|
//Set IQ to normal values
|
|
RFM_Write(0x33,0x27);
|
|
RFM_Write(0x3B,0x1D);
|
|
|
|
//Set FIFO pointers
|
|
//TX base adress
|
|
RFM_Write(0x0E,0x80);
|
|
//Rx base adress
|
|
RFM_Write(0x0F,0x00);
|
|
|
|
//Switch RFM to sleep
|
|
RFM_Write(0x01,0x00);
|
|
}
|
|
|
|
|
|
/*
|
|
*****************************************************************************************
|
|
* Description : Funtion that writes a register from the RFM
|
|
*
|
|
* Arguments : RFM_Address Address of register to be written
|
|
* RFM_Data Data to be written
|
|
*****************************************************************************************
|
|
*/
|
|
|
|
void RFM95::RFM_Write(unsigned char RFM_Address, unsigned char RFM_Data)
|
|
{
|
|
//Set NSS pin Low to start communication
|
|
digitalWrite(_NSS,LOW);
|
|
|
|
//Send Addres with MSB 1 to make it a write command
|
|
SPI.transfer(RFM_Address | 0x80);
|
|
//Send Data
|
|
SPI.transfer(RFM_Data);
|
|
|
|
//Set NSS pin High to end communication
|
|
digitalWrite(_NSS,HIGH);
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************************
|
|
* Description : Funtion that reads a register from the RFM and returns the value
|
|
*
|
|
* Arguments : RFM_Address Address of register to be read
|
|
*
|
|
* Returns : Value of the register
|
|
*****************************************************************************************
|
|
*/
|
|
|
|
unsigned char RFM95::RFM_Read(unsigned char RFM_Address)
|
|
{
|
|
unsigned char RFM_Data;
|
|
|
|
//Set NSS pin low to start SPI communication
|
|
digitalWrite(_NSS,LOW);
|
|
|
|
//Send Address
|
|
SPI.transfer(RFM_Address);
|
|
//Send 0x00 to be able to receive the answer from the RFM
|
|
RFM_Data = SPI.transfer(0x00);
|
|
|
|
//Set NSS high to end communication
|
|
digitalWrite(_NSS,HIGH);
|
|
|
|
//Return received data
|
|
return RFM_Data;
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************************
|
|
* Description : Set Datarate and Spreading Factor
|
|
*
|
|
* Arguments : datarate Lora Datarate Enum (see RFM95.h)
|
|
*****************************************************************************************
|
|
*/
|
|
|
|
void RFM95::RFM_Set_Datarate(lora_dr_t datarate) {
|
|
switch(datarate) {
|
|
case SF7BW125:
|
|
_sf = 0x74;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
break;
|
|
case SF8BW125:
|
|
_sf = 0x84;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
break;
|
|
case SF9BW125:
|
|
_sf = 0x94;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
break;
|
|
case SF10BW125:
|
|
_sf = 0xA4;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
break;
|
|
case SF11BW125:
|
|
_sf = 0xB4;
|
|
_bw = 0x72;
|
|
_mc = 0x0C;
|
|
break;
|
|
case SF12BW125:
|
|
_sf = 0xC4;
|
|
_bw = 0x72;
|
|
_mc = 0x0C;
|
|
break;
|
|
default:
|
|
_sf = 0x74;
|
|
_bw = 0x72;
|
|
_mc = 0x04;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************************
|
|
* Description : Function for sending a package with the RFM
|
|
*
|
|
* Arguments : *RFM_Tx_Package Pointer to arry with data to be send
|
|
* Package_Length Length of the package to send
|
|
*****************************************************************************************
|
|
*/
|
|
|
|
void RFM95::RFM_Send_Package(unsigned char *RFM_Tx_Package, unsigned char Package_Length)
|
|
{
|
|
unsigned char i;
|
|
// unsigned char RFM_Tx_Location = 0x00;
|
|
|
|
//Set RFM in Standby mode wait on mode ready
|
|
|
|
RFM_Write(0x01,0x81);
|
|
/*
|
|
while (digitalRead(DIO5) == LOW)
|
|
{
|
|
}
|
|
*/
|
|
delay(10);
|
|
|
|
//Switch DIO0 to TxDone
|
|
//RFM_Write(0x40,0x40);
|
|
//Set carrier frequency
|
|
|
|
/*
|
|
fixed frequency
|
|
// 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
|
|
_rfm95.RFM_Write(0x06,0xD9);
|
|
_rfm95.RFM_Write(0x07,0x06);
|
|
_rfm95.RFM_Write(0x08,0x8B);
|
|
*/
|
|
|
|
|
|
//Channel 0 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
|
|
RFM_Write(0x06,0xD9);
|
|
RFM_Write(0x07,0x06);
|
|
RFM_Write(0x08,0x8B);
|
|
// EU863-870 specifications
|
|
/*
|
|
// TCNT0 is timer0 continous timer, kind of random selection of frequency
|
|
switch (TCNT0 % 8)
|
|
{
|
|
case 0x00: //Channel 0 868.100 MHz / 61.035 Hz = 14222987 = 0xD9068B
|
|
RFM_Write(0x06,0xD9);
|
|
RFM_Write(0x07,0x06);
|
|
RFM_Write(0x08,0x8B);
|
|
break;
|
|
case 0x01: //Channel 1 868.300 MHz / 61.035 Hz = 14226264 = 0xD91358
|
|
RFM_Write(0x06,0xD9);
|
|
RFM_Write(0x07,0x13);
|
|
RFM_Write(0x08,0x58);
|
|
break;
|
|
case 0x02: //Channel 2 868.500 MHz / 61.035 Hz = 14229540 = 0xD92024
|
|
RFM_Write(0x06,0xD9);
|
|
RFM_Write(0x07,0x20);
|
|
RFM_Write(0x08,0x24);
|
|
break;
|
|
// added five more channels
|
|
case 0x03: // Channel 3 867.100 MHz / 61.035 Hz = 14206603 = 0xD8C68B
|
|
RFM_Write(0x06,0xD8);
|
|
RFM_Write(0x07,0xC6);
|
|
RFM_Write(0x08,0x8B);
|
|
break;
|
|
case 0x04: // Channel 4 867.300 MHz / 61.035 Hz = 14209880 = 0xD8D358
|
|
RFM_Write(0x06,0xD8);
|
|
RFM_Write(0x07,0xD3);
|
|
RFM_Write(0x08,0x58);
|
|
break;
|
|
case 0x05: // Channel 5 867.500 MHz / 61.035 Hz = 14213156 = 0xD8E024
|
|
RFM_Write(0x06,0xD8);
|
|
RFM_Write(0x07,0xE0);
|
|
RFM_Write(0x08,0x24);
|
|
break;
|
|
case 0x06: // Channel 6 867.700 MHz / 61.035 Hz = 14216433 = 0xD8ECF1
|
|
RFM_Write(0x06,0xD8);
|
|
RFM_Write(0x07,0xEC);
|
|
RFM_Write(0x08,0xF1);
|
|
break;
|
|
case 0x07: // Channel 7 867.900 MHz / 61.035 Hz = 14219710 = 0xD8F9BE
|
|
RFM_Write(0x06,0xD8);
|
|
RFM_Write(0x07,0xF9);
|
|
RFM_Write(0x08,0xBE);
|
|
break;
|
|
// FSK 868.800 Mhz => not used in this config
|
|
// 869.525 - SF9BW125 (RX2 downlink only) for package received
|
|
|
|
}
|
|
*/
|
|
|
|
//SF7 BW 125 kHz
|
|
RFM_Write(0x1E,_sf); //SF7 CRC On
|
|
RFM_Write(0x1D,_bw); //125 kHz 4/5 coding rate explicit header mode
|
|
RFM_Write(0x26,_mc); //Low datarate optimization off AGC auto on
|
|
|
|
//Set IQ to normal values
|
|
RFM_Write(0x33,0x27);
|
|
RFM_Write(0x3B,0x1D);
|
|
|
|
//Set payload length to the right length
|
|
RFM_Write(0x22,Package_Length);
|
|
|
|
//Get location of Tx part of FiFo
|
|
//RFM_Tx_Location = RFM_Read(0x0E);
|
|
|
|
//Set SPI pointer to start of Tx part in FiFo
|
|
//RFM_Write(0x0D,RFM_Tx_Location);
|
|
RFM_Write(0x0D,0x80); // hardcoded fifo location according RFM95 specs
|
|
|
|
//Write Payload to FiFo
|
|
for (i = 0;i < Package_Length; i++)
|
|
{
|
|
RFM_Write(0x00,*RFM_Tx_Package);
|
|
RFM_Tx_Package++;
|
|
}
|
|
|
|
//Switch RFM to Tx
|
|
RFM_Write(0x01,0x83);
|
|
|
|
//Wait for TxDone
|
|
//while( digitalRead(_DIO0) == LOW )
|
|
//{
|
|
//}
|
|
|
|
while((RFM_Read(0x12) & 0x08) != 0x08)
|
|
{
|
|
}
|
|
|
|
//Clear interrupt
|
|
RFM_Write(0x12,0x08);
|
|
|
|
//Switch RFM to sleep
|
|
RFM_Write(0x01,0x00);
|
|
}
|