diff --git a/README.md b/README.md index 47cc97cd..817dbd2e 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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: diff --git a/src/hal/hal.cpp b/src/hal/hal.cpp index 53bf359d..c6c89ba3 100644 --- a/src/hal/hal.cpp +++ b/src/hal/hal.cpp @@ -16,12 +16,17 @@ // ----------------------------------------------------------------------------- // 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) @@ -29,11 +34,13 @@ static void hal_io_init () { 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 @@ -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 diff --git a/src/lmic/oslmic.h b/src/lmic/oslmic.h index 01564004..6be903a5 100644 --- a/src/lmic/oslmic.h +++ b/src/lmic/oslmic.h @@ -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); diff --git a/src/lmic/radio.c b/src/lmic/radio.c index d1bd48c9..2f9ea96d 100644 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -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 @@ -725,7 +728,9 @@ void radio_init () { opmode(OPMODE_SLEEP); +#ifndef ESP8266 hal_enableIRQs(); +#endif } // return next random byte derived from seed buffer @@ -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) {