Skip to content

Commit 266eb78

Browse files
committed
Implentation of CAD mode (SX1276 datasheet page 42) with working example using watchdog timer of the 328p for the sleep intervals.
1 parent 7edf89a commit 266eb78

File tree

3 files changed

+185
-4
lines changed

3 files changed

+185
-4
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#include <SPI.h>
2+
#include <LoRa.h>
3+
4+
#include <avr/sleep.h>
5+
#include <avr/power.h>
6+
#include <avr/wdt.h>
7+
8+
ISR(WDT_vect) {
9+
}
10+
11+
volatile bool dio0_rise;
12+
volatile bool dio1_rise;
13+
14+
byte dio0_pin = 2;
15+
byte dio1_pin = 3;
16+
17+
void setup() {
18+
Serial.begin(9600);
19+
while (!Serial);
20+
21+
Serial.println("LoRa Receiver");
22+
23+
pinMode(dio0_pin, INPUT);
24+
pinMode(dio1_pin, INPUT);
25+
26+
// Set sleep to full power down. Only external interrupts or
27+
// the watchdog timer can wake the CPU!
28+
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
29+
30+
// wdt sleep settings:
31+
// 10.8 Watchdog Timer
32+
WDTCSR |= 1<<WDCE | 1<<WDE;
33+
34+
// Table 10-3. Watchdog Timer Prescale Select
35+
//WDTCSR = WDTO_8S; // 1<<WDP3 | 1<<WDP0; // 8 seconds
36+
//WDTCSR = WDTO_4S; // 1<<WDP3; // 4 seconds
37+
//WDTCSR = WDTO_2S; // 1<<WDP2 | 1<<WDP1 | 1<<WDP0; // 2 seconds
38+
//WDTCSR = WDTO_1S; // 1<<WDP2 | 1<<WDP1; // 1 seconds
39+
//WDTCSR = WDTO_30MS;
40+
WDTCSR = WDTO_15MS;
41+
42+
WDTCSR |= 1<<WDIE;
43+
44+
// Setup external interrupt INT0 and INT1
45+
//
46+
//12.2 Register Description
47+
//12.2.1 EICRA – External Interrupt Control Register A
48+
EICRA = 0;
49+
//EICRA |= (1<<ISC10); // Any logical change on INT1 generates an interrupt request.
50+
//EICRA |= (1<<ISC00); // Any logical change on INT0 generates an interrupt request.
51+
EICRA |= 1<<ISC11 | 1<<ISC10; // The rising edge of INT1 generates an interrupt request.
52+
EICRA |= 1<<ISC01 | 1<<ISC00; // The rising edge of INT0 generates an interrupt request.
53+
54+
//12.2.2 EIMSK – External Interrupt Mask Register
55+
EIMSK = 0;
56+
EIMSK |= (1<<INT1); // Bit 1 – INT1: External Interrupt Request 1 Enable
57+
EIMSK |= (1<<INT0); // Bit 0 – INT0: External Interrupt Request 0 Enable
58+
59+
if (!LoRa.begin(915E6)) {
60+
Serial.println("Starting LoRa failed!");
61+
while (1);
62+
}
63+
64+
LoRa.setPreambleLength(30);
65+
66+
// initiates the first cadMode
67+
LoRa.cadMode();
68+
}
69+
70+
void go_to_sleep() {
71+
// reset wdt counter
72+
wdt_reset();
73+
74+
//sleep_mode: Put the device into sleep mode, taking care of setting the SE bit before, and clearing it afterwards.
75+
sleep_mode();
76+
}
77+
78+
ISR (INT0_vect){
79+
dio0_rise = true;
80+
}
81+
82+
ISR (INT1_vect){
83+
dio1_rise = true;
84+
}
85+
86+
void parse_packet(){
87+
// try to parse packet
88+
int packetSize = LoRa.parsePacket();
89+
if (packetSize) {
90+
// received a packet
91+
Serial.print("Received packet '");
92+
93+
// read packet
94+
while (LoRa.available()) {
95+
Serial.print((char)LoRa.read());
96+
}
97+
98+
// print RSSI of packet
99+
Serial.print("' with RSSI ");
100+
Serial.println(LoRa.packetRssi());
101+
}
102+
}
103+
104+
void loop() {
105+
if (LoRa.cadModeActive && dio0_rise){
106+
// dio0: CadDone
107+
// dio1: CadDetected
108+
109+
if (dio1_rise){
110+
dio0_rise = false;
111+
dio1_rise = false;
112+
// prepare radio to receive a single packet
113+
LoRa.setRxSingle();
114+
} else {
115+
116+
// nothing detected: wait before initiating the next cadMode
117+
// put both radio and microcontroller to sleep
118+
LoRa.sleep();
119+
go_to_sleep();
120+
121+
dio0_rise = false;
122+
dio1_rise = false;
123+
LoRa.cadMode();
124+
}
125+
} else if (LoRa.rxSingleMode){
126+
// dio0: RxDone
127+
// dio1: RxTimeout
128+
129+
// only take action if either of the pins went high
130+
if (dio0_rise || dio1_rise){
131+
if (dio0_rise){
132+
parse_packet();
133+
Serial.flush();
134+
}
135+
136+
dio0_rise = false;
137+
dio1_rise = false;
138+
LoRa.cadMode();
139+
}
140+
}
141+
142+
go_to_sleep();
143+
}

src/LoRa.cpp

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#define MODE_TX 0x03
4747
#define MODE_RX_CONTINUOUS 0x05
4848
#define MODE_RX_SINGLE 0x06
49+
#define MODE_CAD 0x07
4950

5051
// PA config
5152
#define PA_BOOST 0x80
@@ -358,9 +359,9 @@ void LoRaClass::onReceive(void(*callback)(int))
358359
#ifdef SPI_HAS_NOTUSINGINTERRUPT
359360
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
360361
#endif
361-
attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
362+
//attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
362363
} else {
363-
detachInterrupt(digitalPinToInterrupt(_dio0));
364+
//detachInterrupt(digitalPinToInterrupt(_dio0));
364365
#ifdef SPI_HAS_NOTUSINGINTERRUPT
365366
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
366367
#endif
@@ -376,9 +377,9 @@ void LoRaClass::onTxDone(void(*callback)())
376377
#ifdef SPI_HAS_NOTUSINGINTERRUPT
377378
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
378379
#endif
379-
attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
380+
//attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
380381
} else {
381-
detachInterrupt(digitalPinToInterrupt(_dio0));
382+
//detachInterrupt(digitalPinToInterrupt(_dio0));
382383
#ifdef SPI_HAS_NOTUSINGINTERRUPT
383384
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
384385
#endif
@@ -710,6 +711,39 @@ uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value)
710711
return response;
711712
}
712713

714+
void LoRaClass::cadMode(){
715+
cadModeActive = true;
716+
rxSingleMode = false;
717+
718+
// SX1276 datasheet page 105:
719+
// RegDioMapping1:
720+
// Mapping of pins DIO0 to DIO5
721+
// See Table 18 for mapping in LoRa mode
722+
//
723+
// Table 18 DIO Mapping LoRa® Mode (page 46):
724+
// dio0: CadDone : 10
725+
// dio1: CadDetected: 10
726+
writeRegister(REG_DIO_MAPPING_1, 0b10100000);
727+
728+
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_CAD);
729+
}
730+
731+
void LoRaClass::setRxSingle(){
732+
// prepare to receive a single packet
733+
cadModeActive = false;
734+
rxSingleMode = true;
735+
736+
// dio mapping for RxSingle:
737+
writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RxDone, DIO1 => RxTimeout
738+
739+
// same code as in parsePacket():
740+
// reset FIFO address
741+
writeRegister(REG_FIFO_ADDR_PTR, 0);
742+
743+
// put in single RX mode
744+
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
745+
}
746+
713747
ISR_PREFIX void LoRaClass::onDio0Rise()
714748
{
715749
LoRa.handleDio0Rise();

src/LoRa.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ class LoRaClass : public Stream {
8989
void setSPIFrequency(uint32_t frequency);
9090

9191
void dumpRegisters(Stream& out);
92+
void cadMode();
93+
void setRxSingle();
94+
bool cadModeActive = false;
95+
bool rxSingleMode = false;
9296

9397
private:
9498
void explicitHeaderMode();

0 commit comments

Comments
 (0)