Port of lowpowerlab RFM69 Packet radio library for HopeRF RFM69H

Dependents:   Recep_spi_lib Recep_spi_lib

Fork of RFM69 by B Rey

Committer:
geekylou
Date:
Sun Dec 03 18:10:02 2017 +0000
Revision:
1:cedfa200eaeb
Parent:
0:db6e4ce9dc02
Call the interrupt handler at read time so we can handle the case of the IRQ pin already being high.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
br549 0:db6e4ce9dc02 1 //Port of RFM69 from lowpowerlab
br549 0:db6e4ce9dc02 2 //Sync'd Feb. 6, 2015
br549 0:db6e4ce9dc02 3 //spi register read/write routines from Karl Zweimuller's RF22
br549 0:db6e4ce9dc02 4 //
br549 0:db6e4ce9dc02 5 //
br549 0:db6e4ce9dc02 6 //
br549 0:db6e4ce9dc02 7 // **********************************************************************************
br549 0:db6e4ce9dc02 8 // Driver definition for HopeRF RFM69W/RFM69HW/RFM69CW/RFM69HCW, Semtech SX1231/1231H
br549 0:db6e4ce9dc02 9 // **********************************************************************************
br549 0:db6e4ce9dc02 10 // Copyright Felix Rusu (2014), felix@lowpowerlab.com
br549 0:db6e4ce9dc02 11 // http://lowpowerlab.com/
br549 0:db6e4ce9dc02 12 // **********************************************************************************
br549 0:db6e4ce9dc02 13 // License
br549 0:db6e4ce9dc02 14 // **********************************************************************************
br549 0:db6e4ce9dc02 15 // This program is free software; you can redistribute it
br549 0:db6e4ce9dc02 16 // and/or modify it under the terms of the GNU General
br549 0:db6e4ce9dc02 17 // Public License as published by the Free Software
br549 0:db6e4ce9dc02 18 // Foundation; either version 3 of the License, or
br549 0:db6e4ce9dc02 19 // (at your option) any later version.
br549 0:db6e4ce9dc02 20 //
br549 0:db6e4ce9dc02 21 // This program is distributed in the hope that it will
br549 0:db6e4ce9dc02 22 // be useful, but WITHOUT ANY WARRANTY; without even the
br549 0:db6e4ce9dc02 23 // implied warranty of MERCHANTABILITY or FITNESS FOR A
br549 0:db6e4ce9dc02 24 // PARTICULAR PURPOSE. See the GNU General Public
br549 0:db6e4ce9dc02 25 // License for more details.
br549 0:db6e4ce9dc02 26 //
br549 0:db6e4ce9dc02 27 // You should have received a copy of the GNU General
br549 0:db6e4ce9dc02 28 // Public License along with this program.
br549 0:db6e4ce9dc02 29 // If not, see <http://www.gnu.org/licenses/>.
br549 0:db6e4ce9dc02 30 //
br549 0:db6e4ce9dc02 31 // Licence can be viewed at
br549 0:db6e4ce9dc02 32 // http://www.gnu.org/licenses/gpl-3.0.txt
br549 0:db6e4ce9dc02 33 //
br549 0:db6e4ce9dc02 34 // Please maintain this license information along with authorship
br549 0:db6e4ce9dc02 35 // and copyright notices in any redistribution of this code
br549 0:db6e4ce9dc02 36 // **********************************************************************************// RF22.cpp
br549 0:db6e4ce9dc02 37 //
br549 0:db6e4ce9dc02 38 // Copyright (C) 2011 Mike McCauley
br549 0:db6e4ce9dc02 39 // $Id: RF22.cpp,v 1.17 2013/02/06 21:33:56 mikem Exp mikem $
br549 0:db6e4ce9dc02 40 // ported to mbed by Karl Zweimueller
br549 0:db6e4ce9dc02 41
br549 0:db6e4ce9dc02 42
br549 0:db6e4ce9dc02 43 #include "mbed.h"
br549 0:db6e4ce9dc02 44 #include "RFM69.h"
br549 0:db6e4ce9dc02 45 #include <RFM69registers.h>
br549 0:db6e4ce9dc02 46 #include <SPI.h>
br549 0:db6e4ce9dc02 47
br549 0:db6e4ce9dc02 48 volatile uint8_t RFM69::DATA[RF69_MAX_DATA_LEN];
br549 0:db6e4ce9dc02 49 volatile uint8_t RFM69::_mode; // current transceiver state
br549 0:db6e4ce9dc02 50 volatile uint8_t RFM69::DATALEN;
br549 0:db6e4ce9dc02 51 volatile uint8_t RFM69::SENDERID;
br549 0:db6e4ce9dc02 52 volatile uint8_t RFM69::TARGETID; // should match _address
br549 0:db6e4ce9dc02 53 volatile uint8_t RFM69::PAYLOADLEN;
br549 0:db6e4ce9dc02 54 volatile uint8_t RFM69::ACK_REQUESTED;
br549 0:db6e4ce9dc02 55 volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request
br549 0:db6e4ce9dc02 56 volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception)
br549 0:db6e4ce9dc02 57
br549 0:db6e4ce9dc02 58 RFM69::RFM69(PinName mosi, PinName miso, PinName sclk, PinName slaveSelectPin, PinName interrupt):
br549 0:db6e4ce9dc02 59 _slaveSelectPin(slaveSelectPin) , _spi(mosi, miso, sclk), _interrupt(interrupt) {
br549 0:db6e4ce9dc02 60
br549 0:db6e4ce9dc02 61 // Setup the spi for 8 bit data, high steady state clock,
br549 0:db6e4ce9dc02 62 // second edge capture, with a 1MHz clock rate
br549 0:db6e4ce9dc02 63 _spi.format(8,0);
br549 0:db6e4ce9dc02 64 _spi.frequency(4000000);
br549 0:db6e4ce9dc02 65 _mode = RF69_MODE_STANDBY;
br549 0:db6e4ce9dc02 66 _promiscuousMode = false;
br549 0:db6e4ce9dc02 67 _powerLevel = 31;
br549 0:db6e4ce9dc02 68 }
br549 0:db6e4ce9dc02 69
br549 0:db6e4ce9dc02 70 bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID)
br549 0:db6e4ce9dc02 71 {
br549 0:db6e4ce9dc02 72 unsigned long start_to;
br549 0:db6e4ce9dc02 73 const uint8_t CONFIG[][2] =
br549 0:db6e4ce9dc02 74 {
br549 0:db6e4ce9dc02 75 /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY },
br549 0:db6e4ce9dc02 76 /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping
br549 0:db6e4ce9dc02 77 /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS
br549 0:db6e4ce9dc02 78 /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555},
br549 0:db6e4ce9dc02 79 /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz)
br549 0:db6e4ce9dc02 80 /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000},
br549 0:db6e4ce9dc02 81
br549 0:db6e4ce9dc02 82 /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) },
br549 0:db6e4ce9dc02 83 /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) },
br549 0:db6e4ce9dc02 84 /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) },
br549 0:db6e4ce9dc02 85
br549 0:db6e4ce9dc02 86 // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm
br549 0:db6e4ce9dc02 87 // +17dBm and +20dBm are possible on RFM69HW
br549 0:db6e4ce9dc02 88 // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**)
br549 0:db6e4ce9dc02 89 // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)**
br549 0:db6e4ce9dc02 90 // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet)
br549 0:db6e4ce9dc02 91 ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111},
br549 0:db6e4ce9dc02 92 ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA)
br549 0:db6e4ce9dc02 93
br549 0:db6e4ce9dc02 94 // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz)
br549 0:db6e4ce9dc02 95 /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw)
br549 0:db6e4ce9dc02 96 //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 },
br549 0:db6e4ce9dc02 97 /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using
br549 0:db6e4ce9dc02 98 /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving
br549 0:db6e4ce9dc02 99 /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset
br549 0:db6e4ce9dc02 100 /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm
br549 0:db6e4ce9dc02 101 ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA
br549 0:db6e4ce9dc02 102 /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 },
br549 0:db6e4ce9dc02 103 /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib
br549 0:db6e4ce9dc02 104 /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID
br549 0:db6e4ce9dc02 105 /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF },
br549 0:db6e4ce9dc02 106 /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX
br549 0:db6e4ce9dc02 107 ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering
br549 0:db6e4ce9dc02 108 /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty
br549 0:db6e4ce9dc02 109 /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
br549 0:db6e4ce9dc02 110 //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent)
br549 0:db6e4ce9dc02 111 /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0
br549 0:db6e4ce9dc02 112 {255, 0}
br549 0:db6e4ce9dc02 113 };
br549 0:db6e4ce9dc02 114 // Timer for ms waits
br549 0:db6e4ce9dc02 115 t.start();
br549 0:db6e4ce9dc02 116 _slaveSelectPin = 1;
br549 0:db6e4ce9dc02 117
br549 0:db6e4ce9dc02 118 // Setup the spi for 8 bit data : 1RW-bit 7 adressbit and 8 databit
br549 0:db6e4ce9dc02 119 // second edge capture, with a 10MHz clock rate
br549 0:db6e4ce9dc02 120 _spi.format(8,0);
br549 0:db6e4ce9dc02 121 _spi.frequency(4000000);
br549 0:db6e4ce9dc02 122
br549 0:db6e4ce9dc02 123 #define TIME_OUT 50
br549 0:db6e4ce9dc02 124
br549 0:db6e4ce9dc02 125 start_to = t.read_ms() ;
br549 0:db6e4ce9dc02 126
br549 0:db6e4ce9dc02 127 do writeReg(REG_SYNCVALUE1, 0xaa); while (readReg(REG_SYNCVALUE1) != 0xaa && t.read_ms()-start_to < TIME_OUT);
br549 0:db6e4ce9dc02 128 if (t.read_ms()-start_to >= TIME_OUT) return (false);
br549 0:db6e4ce9dc02 129
br549 0:db6e4ce9dc02 130 // Set time out
br549 0:db6e4ce9dc02 131 start_to = t.read_ms() ;
br549 0:db6e4ce9dc02 132 do writeReg(REG_SYNCVALUE1, 0x55); while (readReg(REG_SYNCVALUE1) != 0x55 && t.read_ms()-start_to < TIME_OUT);
br549 0:db6e4ce9dc02 133 if (t.read_ms()-start_to >= TIME_OUT) return (false);
br549 0:db6e4ce9dc02 134 for (uint8_t i = 0; CONFIG[i][0] != 255; i++)
br549 0:db6e4ce9dc02 135 writeReg(CONFIG[i][0], CONFIG[i][1]);
br549 0:db6e4ce9dc02 136
br549 0:db6e4ce9dc02 137 // Encryption is persistent between resets and can trip you up during debugging.
br549 0:db6e4ce9dc02 138 // Disable it during initialization so we always start from a known state.
br549 0:db6e4ce9dc02 139 encrypt(0);
br549 0:db6e4ce9dc02 140
br549 0:db6e4ce9dc02 141 setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW
br549 0:db6e4ce9dc02 142 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 143 // Set up interrupt handler
br549 0:db6e4ce9dc02 144 start_to = t.read_ms() ;
br549 0:db6e4ce9dc02 145 while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && t.read_ms()-start_to < TIME_OUT); // Wait for ModeReady
br549 0:db6e4ce9dc02 146 if (t.read_ms()-start_to >= TIME_OUT) return (false);
br549 0:db6e4ce9dc02 147
br549 0:db6e4ce9dc02 148 _interrupt.rise(this, &RFM69::isr0);
br549 0:db6e4ce9dc02 149
br549 0:db6e4ce9dc02 150 _address = nodeID;
br549 0:db6e4ce9dc02 151 return true;
br549 0:db6e4ce9dc02 152 }
br549 0:db6e4ce9dc02 153 // return the frequency (in Hz)
br549 0:db6e4ce9dc02 154 uint32_t RFM69::getFrequency()
br549 0:db6e4ce9dc02 155 {
br549 0:db6e4ce9dc02 156 return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg(REG_FRFMID) << 8) + readReg(REG_FRFLSB));
br549 0:db6e4ce9dc02 157 }
br549 0:db6e4ce9dc02 158
br549 0:db6e4ce9dc02 159 // set the frequency (in Hz)
br549 0:db6e4ce9dc02 160 void RFM69::setFrequency(uint32_t freqHz)
br549 0:db6e4ce9dc02 161 {
br549 0:db6e4ce9dc02 162 uint8_t oldMode = _mode;
br549 0:db6e4ce9dc02 163 if (oldMode == RF69_MODE_TX) {
br549 0:db6e4ce9dc02 164 setMode(RF69_MODE_RX);
br549 0:db6e4ce9dc02 165 }
br549 0:db6e4ce9dc02 166 freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF
br549 0:db6e4ce9dc02 167 writeReg(REG_FRFMSB, freqHz >> 16);
br549 0:db6e4ce9dc02 168 writeReg(REG_FRFMID, freqHz >> 8);
br549 0:db6e4ce9dc02 169 writeReg(REG_FRFLSB, freqHz);
br549 0:db6e4ce9dc02 170 if (oldMode == RF69_MODE_RX) {
br549 0:db6e4ce9dc02 171 setMode(RF69_MODE_SYNTH);
br549 0:db6e4ce9dc02 172 }
br549 0:db6e4ce9dc02 173 setMode(oldMode);
br549 0:db6e4ce9dc02 174 }
br549 0:db6e4ce9dc02 175
br549 0:db6e4ce9dc02 176 void RFM69::setMode(uint8_t newMode)
br549 0:db6e4ce9dc02 177 {
br549 0:db6e4ce9dc02 178 if (newMode == _mode)
br549 0:db6e4ce9dc02 179 return;
br549 0:db6e4ce9dc02 180
br549 0:db6e4ce9dc02 181 switch (newMode) {
br549 0:db6e4ce9dc02 182 case RF69_MODE_TX:
br549 0:db6e4ce9dc02 183 writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER);
br549 0:db6e4ce9dc02 184 if (_isRFM69HW) setHighPowerRegs(true);
br549 0:db6e4ce9dc02 185 break;
br549 0:db6e4ce9dc02 186 case RF69_MODE_RX:
br549 0:db6e4ce9dc02 187 writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER);
br549 0:db6e4ce9dc02 188 if (_isRFM69HW) setHighPowerRegs(false);
br549 0:db6e4ce9dc02 189 break;
br549 0:db6e4ce9dc02 190 case RF69_MODE_SYNTH:
br549 0:db6e4ce9dc02 191 writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER);
br549 0:db6e4ce9dc02 192 break;
br549 0:db6e4ce9dc02 193 case RF69_MODE_STANDBY:
br549 0:db6e4ce9dc02 194 writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY);
br549 0:db6e4ce9dc02 195 break;
br549 0:db6e4ce9dc02 196 case RF69_MODE_SLEEP:
br549 0:db6e4ce9dc02 197 writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP);
br549 0:db6e4ce9dc02 198 break;
br549 0:db6e4ce9dc02 199 default:
br549 0:db6e4ce9dc02 200 return;
br549 0:db6e4ce9dc02 201 }
br549 0:db6e4ce9dc02 202
br549 0:db6e4ce9dc02 203 // we are using packet mode, so this check is not really needed
br549 0:db6e4ce9dc02 204 // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode
br549 0:db6e4ce9dc02 205 while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
br549 0:db6e4ce9dc02 206 _mode = newMode;
br549 0:db6e4ce9dc02 207 }
br549 0:db6e4ce9dc02 208
br549 0:db6e4ce9dc02 209 void RFM69::sleep() {
br549 0:db6e4ce9dc02 210 setMode(RF69_MODE_SLEEP);
br549 0:db6e4ce9dc02 211 }
br549 0:db6e4ce9dc02 212
br549 0:db6e4ce9dc02 213 void RFM69::setAddress(uint8_t addr)
br549 0:db6e4ce9dc02 214 {
br549 0:db6e4ce9dc02 215 _address = addr;
br549 0:db6e4ce9dc02 216 writeReg(REG_NODEADRS, _address);
br549 0:db6e4ce9dc02 217 }
br549 0:db6e4ce9dc02 218
br549 0:db6e4ce9dc02 219 void RFM69::setNetwork(uint8_t networkID)
br549 0:db6e4ce9dc02 220 {
br549 0:db6e4ce9dc02 221 writeReg(REG_SYNCVALUE2, networkID);
br549 0:db6e4ce9dc02 222 }
br549 0:db6e4ce9dc02 223
br549 0:db6e4ce9dc02 224 // set output power: 0 = min, 31 = max
br549 0:db6e4ce9dc02 225 // this results in a "weaker" transmitted signal, and directly results in a lower RSSI at the receiver
br549 0:db6e4ce9dc02 226 void RFM69::setPowerLevel(uint8_t powerLevel)
br549 0:db6e4ce9dc02 227 {
br549 0:db6e4ce9dc02 228 _powerLevel = powerLevel;
br549 0:db6e4ce9dc02 229 writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | (_powerLevel > 31 ? 31 : _powerLevel));
br549 0:db6e4ce9dc02 230 }
br549 0:db6e4ce9dc02 231
br549 0:db6e4ce9dc02 232 bool RFM69::canSend()
br549 0:db6e4ce9dc02 233 {
br549 0:db6e4ce9dc02 234 if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) // if signal stronger than -100dBm is detected assume channel activity
br549 0:db6e4ce9dc02 235 {
br549 0:db6e4ce9dc02 236 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 237 return true;
br549 0:db6e4ce9dc02 238 }
br549 0:db6e4ce9dc02 239 return false;
br549 0:db6e4ce9dc02 240 }
br549 0:db6e4ce9dc02 241
br549 0:db6e4ce9dc02 242 void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK)
br549 0:db6e4ce9dc02 243 {
br549 0:db6e4ce9dc02 244 writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
br549 0:db6e4ce9dc02 245 uint32_t now = t.read_ms();
br549 0:db6e4ce9dc02 246 while (!canSend() && t.read_ms() - now < RF69_CSMA_LIMIT_MS) receiveDone();
br549 0:db6e4ce9dc02 247 sendFrame(toAddress, buffer, bufferSize, requestACK, false);
br549 0:db6e4ce9dc02 248 }
br549 0:db6e4ce9dc02 249
br549 0:db6e4ce9dc02 250 // to increase the chance of getting a packet across, call this function instead of send
br549 0:db6e4ce9dc02 251 // and it handles all the ACK requesting/retrying for you :)
br549 0:db6e4ce9dc02 252 // The only twist is that you have to manually listen to ACK requests on the other side and send back the ACKs
br549 0:db6e4ce9dc02 253 // The reason for the semi-automaton is that the lib is interrupt driven and
br549 0:db6e4ce9dc02 254 // requires user action to read the received data and decide what to do with it
br549 0:db6e4ce9dc02 255 // replies usually take only 5..8ms at 50kbps@915MHz
br549 0:db6e4ce9dc02 256 bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) {
br549 0:db6e4ce9dc02 257 uint32_t sentTime;
br549 0:db6e4ce9dc02 258 for (uint8_t i = 0; i <= retries; i++)
br549 0:db6e4ce9dc02 259 {
br549 0:db6e4ce9dc02 260 send(toAddress, buffer, bufferSize, true);
br549 0:db6e4ce9dc02 261 sentTime = t.read_ms();
br549 0:db6e4ce9dc02 262 while (t.read_ms() - sentTime < retryWaitTime)
br549 0:db6e4ce9dc02 263 {
br549 0:db6e4ce9dc02 264 if (ACKReceived(toAddress))
br549 0:db6e4ce9dc02 265 {
br549 0:db6e4ce9dc02 266 //Serial.print(" ~ms:"); Serial.print(t.read_ms() - sentTime);
br549 0:db6e4ce9dc02 267 return true;
br549 0:db6e4ce9dc02 268 }
br549 0:db6e4ce9dc02 269 }
br549 0:db6e4ce9dc02 270 //Serial.print(" RETRY#"); Serial.println(i + 1);
br549 0:db6e4ce9dc02 271 }
br549 0:db6e4ce9dc02 272 return false;
br549 0:db6e4ce9dc02 273 }
br549 0:db6e4ce9dc02 274
br549 0:db6e4ce9dc02 275 // should be polled immediately after sending a packet with ACK request
br549 0:db6e4ce9dc02 276 bool RFM69::ACKReceived(uint8_t fromNodeID) {
br549 0:db6e4ce9dc02 277 if (receiveDone())
br549 0:db6e4ce9dc02 278 return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED;
br549 0:db6e4ce9dc02 279 return false;
br549 0:db6e4ce9dc02 280 }
br549 0:db6e4ce9dc02 281
br549 0:db6e4ce9dc02 282 // check whether an ACK was requested in the last received packet (non-broadcasted packet)
br549 0:db6e4ce9dc02 283 bool RFM69::ACKRequested() {
br549 0:db6e4ce9dc02 284 return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR);
br549 0:db6e4ce9dc02 285 }
br549 0:db6e4ce9dc02 286
br549 0:db6e4ce9dc02 287 // should be called immediately after reception in case sender wants ACK
br549 0:db6e4ce9dc02 288 void RFM69::sendACK(const void* buffer, uint8_t bufferSize) {
br549 0:db6e4ce9dc02 289 uint8_t sender = SENDERID;
br549 0:db6e4ce9dc02 290 int16_t _RSSI = RSSI; // save payload received RSSI value
br549 0:db6e4ce9dc02 291 writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
br549 0:db6e4ce9dc02 292 uint32_t now = t.read_ms();
br549 0:db6e4ce9dc02 293 while (!canSend() && t.read_ms() - now < RF69_CSMA_LIMIT_MS) receiveDone();
br549 0:db6e4ce9dc02 294 sendFrame(sender, buffer, bufferSize, false, true);
br549 0:db6e4ce9dc02 295 RSSI = _RSSI; // restore payload RSSI
br549 0:db6e4ce9dc02 296 }
br549 0:db6e4ce9dc02 297
br549 0:db6e4ce9dc02 298 void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK)
br549 0:db6e4ce9dc02 299 {
br549 0:db6e4ce9dc02 300 setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo
br549 0:db6e4ce9dc02 301 while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
br549 0:db6e4ce9dc02 302 writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent"
br549 0:db6e4ce9dc02 303 if (bufferSize > RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN;
br549 0:db6e4ce9dc02 304
br549 0:db6e4ce9dc02 305 // control byte
br549 0:db6e4ce9dc02 306 uint8_t CTLbyte = 0x00;
br549 0:db6e4ce9dc02 307 if (sendACK)
br549 0:db6e4ce9dc02 308 CTLbyte = 0x80;
br549 0:db6e4ce9dc02 309 else if (requestACK)
br549 0:db6e4ce9dc02 310 CTLbyte = 0x40;
br549 0:db6e4ce9dc02 311
br549 0:db6e4ce9dc02 312 select();
br549 0:db6e4ce9dc02 313 _spi.write(REG_FIFO | 0x80);
br549 0:db6e4ce9dc02 314 _spi.write(bufferSize + 3);
br549 0:db6e4ce9dc02 315 _spi.write(toAddress);
br549 0:db6e4ce9dc02 316 _spi.write(_address);
br549 0:db6e4ce9dc02 317 _spi.write(CTLbyte);
br549 0:db6e4ce9dc02 318
br549 0:db6e4ce9dc02 319 for (uint8_t i = 0; i < bufferSize; i++)
br549 0:db6e4ce9dc02 320 _spi.write(((uint8_t*) buffer)[i]);
br549 0:db6e4ce9dc02 321 unselect();
br549 0:db6e4ce9dc02 322
br549 0:db6e4ce9dc02 323 // no need to wait for transmit mode to be ready since its handled by the radio
br549 0:db6e4ce9dc02 324 setMode(RF69_MODE_TX);
br549 0:db6e4ce9dc02 325 uint32_t txStart = t.read_ms();
br549 0:db6e4ce9dc02 326 while (_interrupt == 0 && t.read_ms() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish
br549 0:db6e4ce9dc02 327 //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady
br549 0:db6e4ce9dc02 328 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 329 }
br549 0:db6e4ce9dc02 330 // ON = disable filtering to capture all frames on network
br549 0:db6e4ce9dc02 331 // OFF = enable node/broadcast filtering to capture only frames sent to this/broadcast address
br549 0:db6e4ce9dc02 332 void RFM69::promiscuous(bool onOff) {
br549 0:db6e4ce9dc02 333 _promiscuousMode = onOff;
br549 0:db6e4ce9dc02 334 //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST));
br549 0:db6e4ce9dc02 335 }
br549 0:db6e4ce9dc02 336
br549 0:db6e4ce9dc02 337 void RFM69::setHighPower(bool onOff) {
br549 0:db6e4ce9dc02 338 _isRFM69HW = onOff;
br549 0:db6e4ce9dc02 339 writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON);
br549 0:db6e4ce9dc02 340 if (_isRFM69HW) // turning ON
br549 0:db6e4ce9dc02 341 writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages
br549 0:db6e4ce9dc02 342 else
br549 0:db6e4ce9dc02 343 writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only
br549 0:db6e4ce9dc02 344 }
br549 0:db6e4ce9dc02 345
br549 0:db6e4ce9dc02 346 void RFM69::setHighPowerRegs(bool onOff) {
br549 0:db6e4ce9dc02 347 writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55);
br549 0:db6e4ce9dc02 348 writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70);
br549 0:db6e4ce9dc02 349 }
br549 0:db6e4ce9dc02 350
br549 0:db6e4ce9dc02 351 /*
br549 0:db6e4ce9dc02 352 void RFM69::setCS(uint8_t newSPISlaveSelect) {
br549 0:db6e4ce9dc02 353 DigitalOut _slaveSelectPin(newSPISlaveSelect);
br549 0:db6e4ce9dc02 354 _slaveSelectPin = 1;
br549 0:db6e4ce9dc02 355 }
br549 0:db6e4ce9dc02 356 */
br549 0:db6e4ce9dc02 357 // for debugging
br549 0:db6e4ce9dc02 358 void RFM69::readAllRegs()
br549 0:db6e4ce9dc02 359 {
br549 0:db6e4ce9dc02 360 uint8_t regVal,regAddr;
br549 0:db6e4ce9dc02 361
br549 0:db6e4ce9dc02 362 for (regAddr = 1; regAddr <= 0x4F; regAddr++)
br549 0:db6e4ce9dc02 363 {
br549 0:db6e4ce9dc02 364 select();
br549 0:db6e4ce9dc02 365 _spi.write(regAddr & 0x7F); // send address + r/w bit
br549 0:db6e4ce9dc02 366 regVal = _spi.write(0);
br549 0:db6e4ce9dc02 367
br549 0:db6e4ce9dc02 368 /* Serial.print(regAddr, HEX);
br549 0:db6e4ce9dc02 369 Serial.print(" - ");
br549 0:db6e4ce9dc02 370 Serial.print(regVal,HEX);
br549 0:db6e4ce9dc02 371 Serial.print(" - ");
br549 0:db6e4ce9dc02 372 Serial.println(regVal,BIN);*/
br549 0:db6e4ce9dc02 373 }
br549 0:db6e4ce9dc02 374 unselect();
br549 0:db6e4ce9dc02 375 }
br549 0:db6e4ce9dc02 376
br549 0:db6e4ce9dc02 377 uint8_t RFM69::readTemperature(int8_t calFactor) // returns centigrade
br549 0:db6e4ce9dc02 378 {
br549 0:db6e4ce9dc02 379 uint8_t oldMode = _mode;
br549 0:db6e4ce9dc02 380
br549 0:db6e4ce9dc02 381 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 382 writeReg(REG_TEMP1, RF_TEMP1_MEAS_START);
br549 0:db6e4ce9dc02 383 while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING));
br549 0:db6e4ce9dc02 384 setMode(oldMode);
br549 0:db6e4ce9dc02 385
br549 0:db6e4ce9dc02 386 return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val
br549 0:db6e4ce9dc02 387 } // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction
br549 0:db6e4ce9dc02 388
br549 0:db6e4ce9dc02 389 void RFM69::rcCalibration()
br549 0:db6e4ce9dc02 390 {
br549 0:db6e4ce9dc02 391 writeReg(REG_OSC1, RF_OSC1_RCCAL_START);
br549 0:db6e4ce9dc02 392 while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
br549 0:db6e4ce9dc02 393 }
br549 0:db6e4ce9dc02 394 // C++ level interrupt handler for this instance
br549 0:db6e4ce9dc02 395 void RFM69::interruptHandler() {
br549 0:db6e4ce9dc02 396
br549 0:db6e4ce9dc02 397 if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY))
br549 0:db6e4ce9dc02 398 {
br549 0:db6e4ce9dc02 399 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 400 select();
br549 0:db6e4ce9dc02 401
br549 0:db6e4ce9dc02 402 _spi.write(REG_FIFO & 0x7F);
br549 0:db6e4ce9dc02 403 PAYLOADLEN = _spi.write(0);
br549 0:db6e4ce9dc02 404 PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution
br549 0:db6e4ce9dc02 405 TARGETID = _spi.write(0);
br549 0:db6e4ce9dc02 406 if(!(_promiscuousMode || TARGETID == _address || TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode
br549 0:db6e4ce9dc02 407 || PAYLOADLEN < 3) // address situation could receive packets that are malformed and don't fit this libraries extra fields
br549 0:db6e4ce9dc02 408 {
br549 0:db6e4ce9dc02 409 PAYLOADLEN = 0;
br549 0:db6e4ce9dc02 410 unselect();
br549 0:db6e4ce9dc02 411 receiveBegin();
br549 0:db6e4ce9dc02 412 return;
br549 0:db6e4ce9dc02 413 }
br549 0:db6e4ce9dc02 414
br549 0:db6e4ce9dc02 415 DATALEN = PAYLOADLEN - 3;
br549 0:db6e4ce9dc02 416 SENDERID = _spi.write(0);
br549 0:db6e4ce9dc02 417 uint8_t CTLbyte = _spi.write(0);
br549 0:db6e4ce9dc02 418
br549 0:db6e4ce9dc02 419 ACK_RECEIVED = CTLbyte & 0x80; // extract ACK-received flag
br549 0:db6e4ce9dc02 420 ACK_REQUESTED = CTLbyte & 0x40; // extract ACK-requested flag
br549 0:db6e4ce9dc02 421
br549 0:db6e4ce9dc02 422 for (uint8_t i = 0; i < DATALEN; i++)
br549 0:db6e4ce9dc02 423 {
br549 0:db6e4ce9dc02 424 DATA[i] = _spi.write(0);
br549 0:db6e4ce9dc02 425 }
br549 0:db6e4ce9dc02 426 if (DATALEN < RF69_MAX_DATA_LEN) DATA[DATALEN] = 0; // add null at end of string
br549 0:db6e4ce9dc02 427 unselect();
br549 0:db6e4ce9dc02 428 setMode(RF69_MODE_RX);
br549 0:db6e4ce9dc02 429 }
br549 0:db6e4ce9dc02 430 RSSI = readRSSI();
br549 0:db6e4ce9dc02 431 }
br549 0:db6e4ce9dc02 432
br549 0:db6e4ce9dc02 433
br549 0:db6e4ce9dc02 434 // These are low level functions that call the interrupt handler for the correct instance of RFM69.
br549 0:db6e4ce9dc02 435 void RFM69::isr0()
br549 0:db6e4ce9dc02 436 {
br549 0:db6e4ce9dc02 437 interruptHandler();
br549 0:db6e4ce9dc02 438 }
br549 0:db6e4ce9dc02 439 void RFM69::receiveBegin() {
br549 0:db6e4ce9dc02 440 DATALEN = 0;
br549 0:db6e4ce9dc02 441 SENDERID = 0;
br549 0:db6e4ce9dc02 442 TARGETID = 0;
br549 0:db6e4ce9dc02 443 PAYLOADLEN = 0;
br549 0:db6e4ce9dc02 444 ACK_REQUESTED = 0;
br549 0:db6e4ce9dc02 445 ACK_RECEIVED = 0;
br549 0:db6e4ce9dc02 446 RSSI = 0;
br549 0:db6e4ce9dc02 447 if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)
br549 0:db6e4ce9dc02 448 writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks
br549 0:db6e4ce9dc02 449 writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode
br549 0:db6e4ce9dc02 450 setMode(RF69_MODE_RX);
br549 0:db6e4ce9dc02 451 _interrupt.enable_irq();
br549 0:db6e4ce9dc02 452 }
br549 0:db6e4ce9dc02 453
br549 0:db6e4ce9dc02 454 bool RFM69::receiveDone() {
geekylou 1:cedfa200eaeb 455 if (_interrupt.read()) interruptHandler(); // As we are using edge triggered interrupts we need to handle the case of the interrupt being high already and not triggering an edge.
geekylou 1:cedfa200eaeb 456 // This would be better handled with level triggered interrupts.
br549 0:db6e4ce9dc02 457 _interrupt.disable_irq(); // re-enabled in unselect() via setMode() or via receiveBegin()
br549 0:db6e4ce9dc02 458 if (_mode == RF69_MODE_RX && PAYLOADLEN > 0)
br549 0:db6e4ce9dc02 459 {
br549 0:db6e4ce9dc02 460 setMode(RF69_MODE_STANDBY); // enables interrupts
br549 0:db6e4ce9dc02 461 return true;
br549 0:db6e4ce9dc02 462 }
br549 0:db6e4ce9dc02 463 else if (_mode == RF69_MODE_RX) // already in RX no payload yet
br549 0:db6e4ce9dc02 464 {
br549 0:db6e4ce9dc02 465 _interrupt.enable_irq(); // explicitly re-enable interrupts
br549 0:db6e4ce9dc02 466 return false;
br549 0:db6e4ce9dc02 467 }
br549 0:db6e4ce9dc02 468 receiveBegin();
br549 0:db6e4ce9dc02 469 return false;
br549 0:db6e4ce9dc02 470 }
br549 0:db6e4ce9dc02 471
br549 0:db6e4ce9dc02 472 // To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP");
br549 0:db6e4ce9dc02 473 // To disable encryption: radio.encrypt(null) or radio.encrypt(0)
br549 0:db6e4ce9dc02 474 // KEY HAS TO BE 16 bytes !!!
br549 0:db6e4ce9dc02 475 void RFM69::encrypt(const char* key) {
br549 0:db6e4ce9dc02 476 setMode(RF69_MODE_STANDBY);
br549 0:db6e4ce9dc02 477 if (key != 0)
br549 0:db6e4ce9dc02 478 {
br549 0:db6e4ce9dc02 479 select();
br549 0:db6e4ce9dc02 480 _spi.write(REG_AESKEY1 | 0x80);
br549 0:db6e4ce9dc02 481 for (uint8_t i = 0; i < 16; i++)
br549 0:db6e4ce9dc02 482 _spi.write(key[i]);
br549 0:db6e4ce9dc02 483 unselect();
br549 0:db6e4ce9dc02 484 }
br549 0:db6e4ce9dc02 485 writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0));
br549 0:db6e4ce9dc02 486 }
br549 0:db6e4ce9dc02 487
br549 0:db6e4ce9dc02 488 int16_t RFM69::readRSSI(bool forceTrigger) {
br549 0:db6e4ce9dc02 489 int16_t rssi = 0;
br549 0:db6e4ce9dc02 490 if (forceTrigger)
br549 0:db6e4ce9dc02 491 {
br549 0:db6e4ce9dc02 492 // RSSI trigger not needed if DAGC is in continuous mode
br549 0:db6e4ce9dc02 493 writeReg(REG_RSSICONFIG, RF_RSSI_START);
br549 0:db6e4ce9dc02 494 while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // wait for RSSI_Ready
br549 0:db6e4ce9dc02 495 }
br549 0:db6e4ce9dc02 496 rssi = -readReg(REG_RSSIVALUE);
br549 0:db6e4ce9dc02 497 rssi >>= 1;
br549 0:db6e4ce9dc02 498 return rssi;
br549 0:db6e4ce9dc02 499 }
br549 0:db6e4ce9dc02 500
br549 0:db6e4ce9dc02 501 uint8_t RFM69::readReg(uint8_t addr)
br549 0:db6e4ce9dc02 502 {
br549 0:db6e4ce9dc02 503 select();
br549 0:db6e4ce9dc02 504 _spi.write(addr & 0x7F); // Send the address with the write mask off
br549 0:db6e4ce9dc02 505 uint8_t val = _spi.write(0); // The written value is ignored, reg value is read
br549 0:db6e4ce9dc02 506 unselect();
br549 0:db6e4ce9dc02 507 return val;
br549 0:db6e4ce9dc02 508 }
br549 0:db6e4ce9dc02 509
br549 0:db6e4ce9dc02 510 void RFM69::writeReg(uint8_t addr, uint8_t value)
br549 0:db6e4ce9dc02 511 {
br549 0:db6e4ce9dc02 512 select();
br549 0:db6e4ce9dc02 513 _spi.write(addr | 0x80); // Send the address with the write mask on
br549 0:db6e4ce9dc02 514 _spi.write(value); // New value follows
br549 0:db6e4ce9dc02 515 unselect();
br549 0:db6e4ce9dc02 516 }
br549 0:db6e4ce9dc02 517
br549 0:db6e4ce9dc02 518 // select the transceiver
br549 0:db6e4ce9dc02 519 void RFM69::select() {
br549 0:db6e4ce9dc02 520 _interrupt.disable_irq(); // Disable Interrupts
br549 0:db6e4ce9dc02 521 /* // set RFM69 SPI settings
br549 0:db6e4ce9dc02 522 SPI.setDataMode(SPI_MODE0);
br549 0:db6e4ce9dc02 523 SPI.setBitOrder(MSBFIRST);
br549 0:db6e4ce9dc02 524 SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present */
br549 0:db6e4ce9dc02 525 _slaveSelectPin = 0;
br549 0:db6e4ce9dc02 526 }
br549 0:db6e4ce9dc02 527
br549 0:db6e4ce9dc02 528 // UNselect the transceiver chip
br549 0:db6e4ce9dc02 529 void RFM69::unselect() {
br549 0:db6e4ce9dc02 530 _slaveSelectPin = 1;
br549 0:db6e4ce9dc02 531 _interrupt.enable_irq(); // Enable Interrupts
br549 0:db6e4ce9dc02 532 }