Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ library what pin you used through the pin mapping (see below).
[SPI]: https://www.arduino.cc/en/Reference/SPI

### DIO pins

Since now, a software feature has been added to remove needing DIO connections.
Of course, you can continue to use DIO mapping has follow, but in case you're
restricted in GPIO available, you can avoid using any GPIO connection ;-)
to activate this feature, you just need to declare 3 .dio to LMIC_UNUSED_PIN,
in your sketch as detailled in Pin mapping section.

If you want to use hardware IRQ but not having 3 IO pins, another trick is
to OR DIO0/DOI1/DIO2 into one. This is possible because the stack check
all IRQs, even if only one is triggered. Doing this is quite easy, just add 3
1N4148 diodes to each output and a pulldown resistor, see schematic example
on [WeMos Lora shield](https://github.com/hallard/WeMos-Lora).

If you still have DIO connection, following is explaining how they work.
The DIO (digitial I/O) pins on the transceiver board can be configured
for various functions. The LMIC library uses them to get instant status
information from the transceiver. For example, when a LoRa transmission
Expand Down Expand Up @@ -219,13 +233,41 @@ The names refer to the pins on the transceiver side, the numbers refer
to the Arduino pin numbers (to use the analog pins, use constants like
`A0`). For the DIO pins, the three numbers refer to DIO0, DIO1 and DIO2
respectively. Any pins that are not needed should be specified as
`LMIC_UNUSED_PIN`. The nss and dio0 pin is required, the others can
potentially left out (depending on the environments and requirements,
see the notes above for when a pin can or cannot be left out).
`LMIC_UNUSED_PIN`. The nss is required the others can potentially left out
(depending on the environments and requirements, see the notes above for when
a pin can or cannot be left out).

The name of this struct must always be `lmic_pins`, which is a special name
recognized by the library.

If you don't have any DIO pins connected to GPIO (new software feature)
you just need to declare 3 .dio to LMIC_UNUSED_PIN, in your sketch
That's all, stack will do the job for you.

#### [WeMos Lora Shield](https://github.com/hallard/WeMos-Lora)
```arduino
// Example with NO DIO pin connected
const lmic_pinmap lmic_pins = {
.nss = 16,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN},
};
```

If you used 3 diodes OR hardware trick like in this [schematic](https://github.com/hallard/WeMos-Lora),
just indicate which GPIO is used on DIO0 definition as follow:

```arduino
// Example with 3 DIO OR'ed on one pin connected to GPIO14
const lmic_pinmap lmic_pins = {
.nss = 16,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {15, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN},
};
```

#### LoRa Nexus by Ideetron
This board uses the following pin mapping:

Expand Down
47 changes: 29 additions & 18 deletions src/hal/hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,31 @@

// -----------------------------------------------------------------------------
// I/O
// default we do not use IRQ line and DIO output
static bool check_dio = 0;

static void hal_io_init () {
// NSS and DIO0 are required, DIO1 is required for LoRa, DIO2 for FSK
// NSS is required
ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
ASSERT(lmic_pins.dio[0] != LMIC_UNUSED_PIN);
ASSERT(lmic_pins.dio[1] != LMIC_UNUSED_PIN || lmic_pins.dio[2] != LMIC_UNUSED_PIN);

// No more needed, if dio pins are declared as unused, then LIMC will check
// interrputs directly into Lora module register, avoiding needed GPIO line to IRQ
//ASSERT(lmic_pins.dio[0] != LMIC_UNUSED_PIN);
//ASSERT(lmic_pins.dio[1] != LMIC_UNUSED_PIN || lmic_pins.dio[2] != LMIC_UNUSED_PIN);

pinMode(lmic_pins.nss, OUTPUT);
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
pinMode(lmic_pins.rxtx, OUTPUT);
if (lmic_pins.rst != LMIC_UNUSED_PIN)
pinMode(lmic_pins.rst, OUTPUT);

pinMode(lmic_pins.dio[0], INPUT);
if (lmic_pins.dio[1] != LMIC_UNUSED_PIN)
pinMode(lmic_pins.dio[1], INPUT);
if (lmic_pins.dio[2] != LMIC_UNUSED_PIN)
pinMode(lmic_pins.dio[2], INPUT);
// if using DIO lines, DIO0 is always required, DIO1 is required for LoRa, DIO2 for FSK
for (uint8_t i = 0; i < NUM_DIO; ++i) {
if (lmic_pins.dio[i] != LMIC_UNUSED_PIN) {
check_dio = 1; // we need to use DIO line check
pinMode(lmic_pins.dio[i], INPUT);
}
}
}

// val == 1 => tx 1
Expand All @@ -58,19 +65,23 @@ void hal_pin_rst (u1_t val) {
static bool dio_states[NUM_DIO] = {0};

static void hal_io_check() {
uint8_t i;
for (i = 0; i < NUM_DIO; ++i) {
if (lmic_pins.dio[i] == LMIC_UNUSED_PIN)
continue;

if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
dio_states[i] = !dio_states[i];
if (dio_states[i])
radio_irq_handler(i);
// We have DIO line connected?
if (check_dio == 1) {
uint8_t i;
for (i = 0; i < NUM_DIO; ++i) {
if (dio_states[i] != digitalRead(lmic_pins.dio[i])) {
dio_states[i] = !dio_states[i];
if (dio_states[i]) {
radio_irq_handler(i);
}
}
}
} else {
// Check IRQ flags in radio module
if ( radio_has_irq() )
radio_irq_handler(0);
}
}

// -----------------------------------------------------------------------------
// SPI

Expand Down
1 change: 1 addition & 0 deletions src/lmic/oslmic.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ u1_t radio_rand1 (void);
#define DECLARE_LMIC extern struct lmic_t LMIC

void radio_init (void);
u1_t radio_has_irq (void);
void radio_irq_handler (u1_t dio);
void os_init (void);
void os_runloop (void);
Expand Down
27 changes: 27 additions & 0 deletions src/lmic/radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,10 @@ static void startrx (u1_t rxmode) {

// get random seed from wideband noise rssi
void radio_init () {

#ifndef ESP8266
hal_disableIRQs();
#endif

// manually reset radio
#ifdef CFG_sx1276_radio
Expand Down Expand Up @@ -725,7 +728,9 @@ void radio_init () {

opmode(OPMODE_SLEEP);

#ifndef ESP8266
hal_enableIRQs();
#endif
}

// return next random byte derived from seed buffer
Expand Down Expand Up @@ -759,6 +764,28 @@ static CONST_TABLE(u2_t, LORA_RXDONE_FIXUP)[] = {
[SF12] = us2osticks(31189), // (1022 ticks)
};


// called by hal to check if we got one IRQ
// This trick directly read the Lora module IRQ register
// and thus avoid any IRQ line used to controler
u1_t radio_has_irq (void) {
u1_t flags ;
if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
flags = readReg(LORARegIrqFlags);
if( flags & ( IRQ_LORA_TXDONE_MASK | IRQ_LORA_RXDONE_MASK | IRQ_LORA_RXTOUT_MASK ) )
return 1;
} else { // FSK modem
flags = readReg(FSKRegIrqFlags2);
if ( flags & ( IRQ_FSK2_PACKETSENT_MASK | IRQ_FSK2_PAYLOADREADY_MASK) )
return 1;
flags = readReg(FSKRegIrqFlags1);
if ( flags & IRQ_FSK1_TIMEOUT_MASK )
return 1;
}

return 0;
}

// called by hal ext IRQ handler
// (radio goes to stanby mode after tx/rx operations)
void radio_irq_handler (u1_t dio) {
Expand Down