diff --git a/Documentation/components/drivers/character/wireless/lpwan/index.rst b/Documentation/components/drivers/character/wireless/lpwan/index.rst index 1dff004ff43..eb1b8e60e84 100644 --- a/Documentation/components/drivers/character/wireless/lpwan/index.rst +++ b/Documentation/components/drivers/character/wireless/lpwan/index.rst @@ -7,4 +7,5 @@ LPWAN lora_gw.rst sx126x.rst + sx127x.rst diff --git a/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst b/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst new file mode 100644 index 00000000000..7ec0f3a3df5 --- /dev/null +++ b/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst @@ -0,0 +1,132 @@ +.. _sx127x: + +================= +SX127x LoRa radio +================= + +The SX127x family, which includes the SX1272 and the SX1276 found on most +modules and development boards, is a sub-GHz transceiver doing LoRa as well +as FSK and OOK. Unlike a concentrator it demodulates one channel at a time, +so frequency, spreading factor and bandwidth are settings of the radio and +not attributes of each packet. + +The driver is enabled with ``CONFIG_LPWAN_SX127X`` and registers a character +device, ``/dev/sx127x`` by convention. + +Userspace API +============= + +Reading and writing +------------------- + +``write`` transmits the given bytes with the parameters currently configured. +``read`` returns one received packet, blocking until one arrives; with +``CONFIG_LPWAN_SX127X_RXFIFO_LEN`` the driver keeps a small queue of them, so +a reader that falls behind loses the oldest rather than the newest. + +Each packet is preceded by a ``struct sx127x_read_hdr_s``, which carries the +payload length together with the received power and, in LoRa mode, the signal +to noise ratio of that packet. + +IOCTL commands +-------------- + +The basic radio parameters use the common commands of +``nuttx/wireless/ioctl.h``: ``WLIOC_SETRADIOFREQ`` and ``WLIOC_GETRADIOFREQ`` +for the frequency in Hz, ``WLIOC_SETTXPOWER`` and ``WLIOC_GETTXPOWER`` for +the output power in dBm. Both may be further limited by the board logic. + +The rest is in ``nuttx/wireless/lpwan/sx127x.h``: + +* ``SX127XIOC_MODULATIONSET`` and ``SX127XIOC_MODULATIONGET`` choose between + LoRa, FSK and OOK. + +* ``SX127XIOC_OPMODESET`` and ``SX127XIOC_OPMODEGET`` move the radio between + sleep, standby, transmit, receive and channel activity detection. + +* ``SX127XIOC_SYNCWORDSET`` and ``SX127XIOC_SYNCWORDGET`` change the sync + word, and ``SX127XIOC_PREAMBLESET`` and ``SX127XIOC_PREAMBLEGET`` the + preamble length. + +* ``SX127XIOC_RSSIGET`` reads the current RSSI, ``SX127XIOC_CHANSCAN`` scans + a channel and ``SX127XIOC_RANDOMGET`` returns a random number taken from + the noise of the receiver. + +Note that the spreading factor, the bandwidth and the coding rate have no +ioctl of their own yet: they come from the configuration below. + +Configuration +============= + +============================================ ================================== +Option Meaning +============================================ ================================== +``LPWAN_SX127X_RFFREQ_DEFAULT`` Frequency, in Hz, at registration +``LPWAN_SX127X_TXPOWER_DEFAULT`` Output power in dBm +``LPWAN_SX127X_MODULATION_DEFAULT`` 1 for FSK, 2 for OOK, 3 for LoRa +``LPWAN_SX127X_RXSUPPORT`` Build the receive path +``LPWAN_SX127X_TXSUPPORT`` Build the transmit path +``LPWAN_SX127X_LORA`` Build the LoRa modem +``LPWAN_SX127X_FSKOOK`` Build the FSK and OOK modem +``LPWAN_SX127X_LORA_SYNCWORD`` Sync word, see below +``LPWAN_SX127X_LORA_BW_DEFAULT`` Bandwidth, 7 selects 125 kHz +``LPWAN_SX127X_LORA_SF_DEFAULT`` Spreading factor, 6 to 12 +``LPWAN_SX127X_CRCON`` Append and check a CRC +``LPWAN_SX127X_RXFIFO_LEN`` Packets buffered by the driver +============================================ ================================== + +Talking to another radio +======================== + +Two settings decide whether two devices hear each other at all, and both are +silent failures when they disagree: + +* **Band.** The chip has separate low and high frequency front ends and the + modem has to be told which one is in use. The driver derives that from the + configured frequency, using the high band above 525 MHz. + +* **Sync word.** ``CONFIG_LPWAN_SX127X_LORA_SYNCWORD`` defaults to 0x12, the + private network value. A public LoRaWAN network uses 0x34, and a receiver + configured for the other value never even detects the frame. + +Beyond those, the spreading factor, the bandwidth and the coding rate have to +match on both sides. + +Two boards reach each other with the ``sx127x`` example of +``apps/examples/sx127x_demo``. Start the receiver first, since the example +gives up after the time given with ``-d``:: + + board A> sx127x -m 0 -f 917200000 -r -d 60 + board B> sx127x -m 0 -f 917200000 -t -p 0 -l 32 -d 30 + +The receiver prints the payload of every packet along with its signal to +noise ratio and its received power. Keep the boards a metre or so apart: at a +few centimetres a transmitter saturates the other receiver and the packets +arrive with a broken CRC. + +The same commands work against a gateway. A concentrator running the ``lora`` +command of ``apps/wireless/lora_pkt_fwd`` sends a packet with +``lora tx 917200000 7 hello``, which any board listening on that frequency +receives; and a board transmitting as above shows up on the gateway as an +ordinary uplink. See :ref:`lora_gw` for the gateway side. + +Board implementation +==================== + +The driver is registered with ``sx127x_register``, which takes an SPI bus and +a ``struct sx127x_lower_s``. That structure carries what the chip needs from +the board: attaching the DIO0 interrupt, which signals the end of a +transmission or a reception, a ``reset`` hook, and the optional +``opmode_change``, ``freq_select`` and ``pa_select`` hooks used by boards +whose antenna switch or power amplifier path depends on the operating mode, +the frequency or the requested power. See +``nuttx/wireless/lpwan/sx127x.h``. + +Boards +====== + +* :ref:`ST B-L072Z-LRWAN1 ` +* :ref:`Nucleo L073RZ ` +* :ref:`Nucleo F091RC ` +* :ref:`nRF52840-DK ` +* :ref:`Heltec WiFi LoRa 32 ` diff --git a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst index 6375fad4b06..43e93e1ab6a 100644 --- a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst +++ b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst @@ -1,3 +1,5 @@ +.. _nrf52840-dk: + =========== nRF52840-DK =========== diff --git a/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst b/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst index 8f5df380009..a308569c098 100644 --- a/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst +++ b/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst @@ -1,3 +1,5 @@ +.. _nucleo-f091rc: + ================= ST Nucleo F091RC ================= diff --git a/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst index 0370a975522..63da5013097 100644 --- a/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst +++ b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst @@ -1,3 +1,5 @@ +.. _b-l072z-lrwan1: + ================= ST B-L072Z-LRWAN1 ================= diff --git a/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst b/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst index 6e41b3cba97..3000df30ae2 100644 --- a/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst +++ b/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst @@ -1,3 +1,5 @@ +.. _nucleo-l073rz: + ================ ST Nucleo L073RZ ================ diff --git a/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst b/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst index b0d3501757f..48d156ac731 100644 --- a/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst +++ b/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst @@ -1,3 +1,5 @@ +.. _heltec_wifi_lora32: + ====================== Heltec WiFi LoRa 32 V2 ====================== diff --git a/drivers/wireless/lpwan/sx127x/Kconfig b/drivers/wireless/lpwan/sx127x/Kconfig index 2af745e6d42..51fe87af314 100644 --- a/drivers/wireless/lpwan/sx127x/Kconfig +++ b/drivers/wireless/lpwan/sx127x/Kconfig @@ -79,6 +79,29 @@ config LPWAN_SX127X_LORA_IMPHEADER range 0 1 default 0 +config LPWAN_SX127X_LORA_SYNCWORD + hex "SX127X LORA sync word" + default 0x12 + ---help--- + Sync word written to the modem: 0x12 for a private network, 0x34 + for the public LoRaWAN network. A gateway configured for the + public network does not even detect a frame sent with the private + sync word, so this has to match the other end. + +config LPWAN_SX127X_LORA_BW_DEFAULT + int "SX127X LORA default bandwidth" + default 0 + range 0 9 + ---help--- + Bandwidth used until it is changed: 0 = 7.8 kHz, 1 = 10.4 kHz, + 2 = 15.6 kHz, 3 = 20.8 kHz, 4 = 31.2 kHz, 5 = 41.4 kHz, + 6 = 62.5 kHz, 7 = 125 kHz, 9 = 250 kHz. LoRaWAN uses 125 kHz. + +config LPWAN_SX127X_LORA_SF_DEFAULT + int "SX127X LORA default spreading factor" + default 7 + range 6 12 + endif # LPWAN_SX127X_LORA config LPWAN_SX127X_FSKOOK diff --git a/drivers/wireless/lpwan/sx127x/sx127x.c b/drivers/wireless/lpwan/sx127x/sx127x.c index 8b3f334a60e..6aba75ddd81 100644 --- a/drivers/wireless/lpwan/sx127x/sx127x.c +++ b/drivers/wireless/lpwan/sx127x/sx127x.c @@ -130,11 +130,11 @@ /* Default LORA bandwidth */ -#define SX127X_LRM_BW_DEFAULT LORA_BANDWIDTH_7P8KHZ +#define SX127X_LRM_BW_DEFAULT CONFIG_LPWAN_SX127X_LORA_BW_DEFAULT /* Default SF for LORA */ -#define SX127X_LRM_SF_DEFAULT (7) +#define SX127X_LRM_SF_DEFAULT CONFIG_LPWAN_SX127X_LORA_SF_DEFAULT /* FSK/OOK RX/TX FIFO size (two separate FIFOs) */ @@ -1286,7 +1286,12 @@ errout: * ****************************************************************************/ +/* The stall watchdog is only wired into the FSK and OOK receive path, so a + * configuration with LoRa alone must not compile it. + */ + #if defined(CONFIG_LPWAN_SX127X_RXSUPPORT) && \ + defined(CONFIG_LPWAN_SX127X_FSKOOK) && \ CONFIG_LPWAN_SX127X_RX_TIMEOUT > 0 static void sx127x_rx_watchdog(FAR void *arg) { @@ -1321,7 +1326,7 @@ static void sx127x_rx_watchdog(FAR void *arg) sx127x_rx_watchdog, dev, MSEC2TICK(dev->rx_timeout)); } -#endif /* CONFIG_LPWAN_SX127X_RXSUPPORT && CONFIG_LPWAN_SX127X_RX_TIMEOUT > 0 */ +#endif /* RXSUPPORT && FSKOOK && RX_TIMEOUT > 0 */ /**************************************************************************** * Name: sx127x_lora_isr0_process @@ -3875,6 +3880,22 @@ static int sx127x_frequency_set(FAR struct sx127x_dev_s *dev, uint32_t freq) sx127x_writeregbyte(dev, SX127X_CMN_FRFLSB, SX127X_CMN_FRF_LSB(frf)); + /* Tell the modem which of the two front ends the frequency belongs to. + * The chip comes up in low frequency mode, and a board wired for the high + * band (868 or 915 MHz) then neither transmits nor receives anything. + */ + + if (freq > SX127X_HFBAND_THR) + { + sx127x_modregbyte(dev, SX127X_CMN_OPMODE, 0, + SX127X_CMN_OPMODE_LFMODEON); + } + else + { + sx127x_modregbyte(dev, SX127X_CMN_OPMODE, + SX127X_CMN_OPMODE_LFMODEON, 0); + } + /* Unlock SPI */ sx127x_unlock(dev->spi); diff --git a/drivers/wireless/lpwan/sx127x/sx127x.h b/drivers/wireless/lpwan/sx127x/sx127x.h index 7e2fb3d2ba6..ecde2a50010 100644 --- a/drivers/wireless/lpwan/sx127x/sx127x.h +++ b/drivers/wireless/lpwan/sx127x/sx127x.h @@ -181,7 +181,8 @@ /* FSK/OOK/LORA: RF carrier frequency */ #define SX127X_CMN_FRF_MAX (0xffffff) -#define SX127X_FRF_FROM_FREQ(freq) (freq/SX127X_FSTEP) +#define SX127X_FRF_FROM_FREQ(freq) \ + ((uint32_t)(((uint64_t)(freq) << SX127X_FSTEP_SHIFT) / SX127X_FXOSC)) #define SX127X_CMN_FRF_MSB(frf) ((frf >> 16) & 0xff) #define SX127X_CMN_FRF_MID(frf) ((frf >> 8) & 0xff) #define SX127X_CMN_FRF_LSB(frf) ((frf >> 0) & 0xff) @@ -337,7 +338,8 @@ #define SX127X_FOM_FDEV_MSB_MASK (0x3f) #define SX127X_FOM_FDEV_MAX (0x3fff) -#define SX127X_FDEV_FROM_FREQ(freq) (freq/SX127X_FSTEP) +#define SX127X_FDEV_FROM_FREQ(freq) \ + ((uint32_t)(((uint64_t)(freq) << SX127X_FSTEP_SHIFT) / SX127X_FXOSC)) #define SX127X_FOM_FDEV_MSB(v) ((v >> 8) & 0xff) #define SX127X_FOM_FDEV_LSB(v) ((v >> 0) & 0xff) @@ -790,7 +792,7 @@ /* LORA: LORA Sync Word */ -#define SX127X_LRM_SYNCWORD_DEFAULT (0x12) +#define SX127X_LRM_SYNCWORD_DEFAULT CONFIG_LPWAN_SX127X_LORA_SYNCWORD #define SX127X_LRM_SYNCWORD_LORAWAN (0x34) /* Lora data rate: @@ -810,9 +812,14 @@ #define SX127X_FXOSC (32000000) -/* FSTEP is FXOSC/(2**19) =~ 61 Hz */ +/* One step of the frequency synthesiser is FXOSC/(2**19), about 61.035 Hz. + * It is not an integer, so the conversions below multiply first and divide + * afterwards instead of dividing by a truncated step: rounding it down to + * 61 Hz places a 915 MHz channel more than 500 kHz away from the requested + * frequency, well outside the bandwidth of the channel. + */ -#define SX127X_FSTEP (SX127X_FXOSC/(2<<18)) +#define SX127X_FSTEP_SHIFT (19) /**************************************************************************** * Public Data Types