2021-12-30 10:58:30 +08:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "generator" content = "rustdoc" >
< title > LoRaWAN on Apache NuttX OS< / title >
<!-- Begin scripts/articles/* - header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
< meta property = "og:title"
content="LoRaWAN on Apache NuttX OS"
data-rh="true">
< meta property = "og:description"
content="Porting Semtech's LoRaWAN Stack to Apache NuttX OS... And testing it on PineDio Stack BL604 RISC-V Board"
data-rh="true">
< meta property = "og:image"
content="https://lupyuen.github.io/images/lorawan3-title.jpg">
< meta property = "og:type"
content="article" data-rh="true">
<!-- End scripts/articles/* - header.html -->
<!-- Begin scripts/rustdoc - header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
< link rel = "alternate" type = "application/rss+xml" title = "RSS Feed for lupyuen" href = "/rss.xml" / >
< link rel = "stylesheet" type = "text/css" href = "../normalize.css" >
< link rel = "stylesheet" type = "text/css" href = "../rustdoc.css" id = "mainThemeStyle" >
< link rel = "stylesheet" type = "text/css" href = "../dark.css" >
< link rel = "stylesheet" type = "text/css" href = "../light.css" id = "themeStyle" >
< link rel = "stylesheet" type = "text/css" href = "../prism.css" >
< script src = "../storage.js" > < / script > < noscript >
< link rel = "stylesheet" href = "../noscript.css" > < / noscript >
< link rel = "shortcut icon" href = "../favicon.ico" >
< style type = "text/css" >
#crate-search {
background-image: url("../down-arrow.svg");
}
a {
color: #77d;
}
< / style >
<!-- End scripts/rustdoc - header.html -->
< / head >
< body class = "rustdoc" >
<!-- [if lte IE 8]>
< div class = "warning" >
This old browser is unsupported and will most likely display funky
things.
< / div >
<![endif]-->
<!-- Begin scripts/rustdoc - before.html: Pre - HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
<!-- Begin Theme Picker -->
< div class = "theme-picker" style = "left: 0" > < button id = "theme-picker" aria-label = "Pick another theme!" > < img src = "../brush.svg"
width="18" alt="Pick another theme!">< / button >
< div id = "theme-choices" > < / div >
< / div >
< script src = "../theme.js" > < / script >
< script src = "../prism.js" > < / script >
<!-- Theme Picker -->
<!-- End scripts/rustdoc - before.html -->
< h1 class = "title" > LoRaWAN on Apache NuttX OS< / h1 >
< nav id = "TOC" > < ul >
< li > < a href = "#small-steps" > 1 Small Steps< / a > < ul >
< li > < a href = "#lorawan-support" > 1.1 LoRaWAN Support< / a > < ul > < / ul > < / li >
2021-12-30 18:14:03 +08:00
< li > < a href = "#dependencies" > 1.2 Dependencies< / a > < ul > < / ul > < / li > < / ul > < / li >
2021-12-31 01:42:31 +08:00
< li > < a href = "#lorawan-objective" > 2 LoRaWAN Objective< / a > < ul > < / ul > < / li >
2021-12-31 09:48:18 +08:00
< li > < a href = "#download-source-code" > 3 Download Source Code< / a > < ul > < / ul > < / li >
2021-12-31 17:52:11 +08:00
< li > < a href = "#device-eui-join-eui-and-app-key" > 4 Device EUI, Join EUI and App Key< / a > < ul >
< li > < a href = "#secure-element" > 4.1 Secure Element< / a > < ul > < / ul > < / li > < / ul > < / li >
2021-12-31 16:24:13 +08:00
< li > < a href = "#lorawan-frequency" > 5 LoRaWAN Frequency< / a > < ul > < / ul > < / li >
2021-12-31 19:09:25 +08:00
< li > < a href = "#build-the-firmware" > 6 Build The Firmware< / a > < ul > < / ul > < / li >
< li > < a href = "#run-the-firmware" > 7 Run The Firmware< / a > < ul > < / ul > < / li >
2022-01-01 19:06:48 +08:00
< li > < a href = "#join-lorawan-network" > 8 Join LoRaWAN Network< / a > < ul >
2022-01-01 20:36:08 +08:00
< li > < a href = "#check-lorawan-gateway" > 8.1 Check LoRaWAN Gateway< / a > < ul > < / ul > < / li > < / ul > < / li >
2022-01-02 09:32:47 +08:00
< li > < a href = "#send-data-to-lorawan" > 9 Send Data To LoRaWAN< / a > < ul >
< li > < a href = "#message-size" > 9.1 Message Size< / a > < ul > < / ul > < / li >
< li > < a href = "#message-interval" > 9.2 Message Interval< / a > < ul > < / ul > < / li > < / ul > < / li >
2022-01-02 12:25:44 +08:00
< li > < a href = "#rerun-the-firmware" > 10 Rerun The Firmware< / a > < ul >
< li > < a href = "#check-lorawan-gateway-1" > 10.1 Check LoRaWAN Gateway< / a > < ul > < / ul > < / li > < / ul > < / li >
2022-01-02 09:32:47 +08:00
< li > < a href = "#lorawan-event-loop" > 11 LoRaWAN Event Loop< / a > < ul > < / ul > < / li >
< li > < a href = "#lorawan-nonce" > 12 LoRaWAN Nonce< / a > < ul > < / ul > < / li >
< li > < a href = "#nimble-porting-layer" > 13 NimBLE Porting Layer< / a > < ul > < / ul > < / li >
< li > < a href = "#gpio-interrupts" > 14 GPIO Interrupts< / a > < ul > < / ul > < / li >
< li > < a href = "#sx1262-busy" > 15 SX1262 Busy< / a > < ul > < / ul > < / li >
< li > < a href = "#troubleshoot-lorawan" > 16 Troubleshoot LoRaWAN< / a > < ul >
< li > < a href = "#logging" > 16.1 Logging< / a > < ul > < / ul > < / li >
< li > < a href = "#message-size-1" > 16.2 Message Size< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#spi-with-dma" > 17 SPI with DMA< / a > < ul > < / ul > < / li >
< li > < a href = "#whats-next" > 18 What’ s Next< / a > < ul > < / ul > < / li >
< li > < a href = "#notes" > 19 Notes< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-posix-timers-and-message-queues" > 20 Appendix: POSIX Timers and Message Queues< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-random-number-generator-with-entropy-pool" > 21 Appendix: Random Number Generator with Entropy Pool< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-build-flash-and-run-nuttx" > 22 Appendix: Build, Flash and Run NuttX< / a > < ul >
< li > < a href = "#build-nuttx" > 22.1 Build NuttX< / a > < ul > < / ul > < / li >
< li > < a href = "#flash-nuttx" > 22.2 Flash NuttX< / a > < ul > < / ul > < / li >
< li > < a href = "#run-nuttx" > 22.3 Run NuttX< / a > < ul > < / ul > < / li > < / ul > < / li >
< li > < a href = "#appendix-gpio-issue" > 23 Appendix: GPIO Issue< / a > < ul > < / ul > < / li >
< li > < a href = "#appendix-callout-issue" > 24 Appendix: Callout Issue< / a > < ul > < / ul > < / li > < / ul > < / nav > < p > 📝 < em > 7 Jan 2022< / em > < / p >
2021-12-30 11:49:59 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
< p > < em > PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)< / em > < / p >
< p > Last article we got < strong > LoRa< / strong > (the long-range, low-bandwidth wireless network) running on < a href = "https://lupyuen.github.io/articles/nuttx" > < strong > Apache NuttX OS< / strong > < / a > …< / p >
2021-12-30 10:58:30 +08:00
< ul >
2021-12-30 11:49:59 +08:00
< li > < a href = "https://lupyuen.github.io/articles/sx1262" > < strong > “LoRa SX1262 on Apache NuttX OS”< / strong > < / a > < / li >
2021-12-30 10:58:30 +08:00
< / ul >
2021-12-30 11:49:59 +08:00
< p > Today we shall run < strong > LoRaWAN< / strong > on NuttX OS!< / p >
2021-12-30 11:51:32 +08:00
< p > < em > Why would we need LoRaWAN?< / em > < / p >
2021-12-30 11:49:59 +08:00
< p > LoRa will work perfectly fine for unsecured < strong > Point-to-Point Wireless Communication< / strong > .< / p >
2021-12-30 10:58:30 +08:00
< p > But if we need to < strong > relay data packets< / strong > securely to a Local Area Network or to the internet, we need < strong > LoRaWAN< / strong > .< / p >
< p > < a href = "https://makezine.com/2021/05/24/go-long-with-lora-radio/" > (More about LoRaWAN)< / a > < / p >
2021-12-30 11:49:59 +08:00
< p > We shall test LoRaWAN on NuttX with Bouffalo Lab’ s < a href = "https://lupyuen.github.io/articles/pinecone" > < strong > BL602 and BL604 RISC-V SoCs< / strong > < / a > .< / p >
< p > (It will probably run on < strong > ESP32< / strong > , since we’ re calling standard NuttX Interfaces)< / p >
< p > < img src = "https://lupyuen.github.io/images/sx1262-library5.jpg" alt = "Porting LoRaWAN to NuttX OS" / > < / p >
2021-12-30 10:58:30 +08:00
< h1 id = "small-steps" class = "section-header" > < a href = "#small-steps" > 1 Small Steps< / a > < / h1 >
2021-12-30 18:14:03 +08:00
< p > In the last article we created a < strong > LoRa Library for NuttX< / strong > (top right) that works with < strong > Semtech SX1262 Transceiver< / strong > …< / p >
2021-12-30 16:35:12 +08:00
< ul >
2021-12-30 18:14:03 +08:00
< li > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > lupyuen/lora-sx1262 (lorawan branch)< / strong > < / a > < / li >
2021-12-30 16:35:12 +08:00
< / ul >
2021-12-30 18:14:03 +08:00
< p > Today we’ ll create a < strong > LoRaWAN Library for NuttX< / strong > (centre right)…< / p >
2021-12-30 10:58:30 +08:00
< ul >
2021-12-30 18:14:03 +08:00
< li > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > < strong > lupyuen/LoRaMac-node-nuttx< / strong > < / a > < / li >
< / ul >
< p > That’ s a near-identical fork of < strong > Semtech’ s LoRaWAN Stack< / strong > (dated 14 Dec 2021)…< / p >
< ul >
< li > < a href = "https://github.com/Lora-net/LoRaMac-node" > < strong > Lora-net/LoRaMac-node< / strong > < / a > < / li >
2021-12-30 10:58:30 +08:00
< / ul >
2021-12-30 18:29:00 +08:00
< p > We’ ll test with this < strong > LoRaWAN App< / strong > on NuttX…< / p >
< ul >
< li > < a href = "https://github.com/lupyuen/lorawan_test" > < strong > lupyuen/lorawan_test< / strong > < / a > < / li >
< / ul >
2021-12-30 10:58:30 +08:00
< h2 id = "lorawan-support" class = "section-header" > < a href = "#lorawan-support" > 1.1 LoRaWAN Support< / a > < / h2 >
2021-12-30 18:14:03 +08:00
< p > < em > Why did we fork Semtech’ s LoRaWAN Stack? Why not build it specifically for NuttX?< / em > < / p >
2021-12-30 10:58:30 +08:00
< p > LoRaWAN works < strong > slightly differently across the world regions< / strong > , to comply with Local Wireless Regulations: Radio Frequency, Maximum Airtime (Duty Cycle), < a href = "https://lupyuen.github.io/articles/lorawan#appendix-lora-carrier-sensing" > Listen Before Talk< / a > , …< / p >
< p > Thus we should port < strong > Semtech’ s LoRaWAN Stack< / strong > to NuttX with < strong > minimal changes< / strong > , in case of future updates. (Like for new regions)< / p >
2021-12-30 18:14:03 +08:00
< p > < em > How did we create the LoRaWAN Library?< / em > < / p >
< p > We followed the steps below to create < strong > “nuttx/libs/liblorawan”< / strong > by cloning a NuttX Library…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li > < a href = "https://lupyuen.github.io/articles/sx1262#appendix-create-a-nuttx-library" > < strong > “Create a NuttX Library”< / strong > < / a > < / li >
< / ul >
2021-12-30 18:14:03 +08:00
< p > Then we replaced the “liblorawan” folder by a < strong > Git Submodule< / strong > that contains our LoRaWAN code… < / p >
2021-12-30 10:58:30 +08:00
< div class = "example-wrap" > < pre class = "language-bash" > < code > cd nuttx/nuttx/libs
2021-12-30 18:14:03 +08:00
rm -r liblorawan
git rm -r liblorawan
git submodule add https://github.com/lupyuen/LoRaMac-node-nuttx liblorawan< / code > < / pre > < / div >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > (To add the LoRaWAN Library to your NuttX Project, see this)< / a > < / p >
< h2 id = "dependencies" class = "section-header" > < a href = "#dependencies" > 1.2 Dependencies< / a > < / h2 >
< p > Our LoRaWAN Library should work on < strong > any NuttX platform< / strong > (like ESP32), assuming that the following dependencies are installed…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li >
2021-12-30 18:14:03 +08:00
< p > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > lupyuen/lora-sx1262 (lorawan branch)< / strong > < / a > < / p >
< p > LoRa Library for Semtech SX1262 Transceiver< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262" > (See this)< / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/nimble-porting-nuttx" > < strong > lupyuen/nimble-porting-nuttx< / strong > < / a > < / p >
< p > NimBLE Porting Layer multithreading library< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262#multithreading-with-nimble-porting-layer" > (See this)< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
2021-12-30 18:14:03 +08:00
< p > < a href = "https://github.com/lupyuen/incubator-nuttx/tree/lorawan/drivers/rf" > < strong > spi_test_driver (/dev/spitest0)< / strong > < / a > < / p >
< p > SPI Test Driver< / p >
< p > < a href = "https://lupyuen.github.io/articles/spi2" > (See this)< / a > < / p >
2021-12-30 10:58:30 +08:00
< / li >
< / ul >
2021-12-30 18:14:03 +08:00
< p > Our LoRa SX1262 Library assumes that the following < strong > NuttX Devices< / strong > are configured…< / p >
2021-12-30 10:58:30 +08:00
< ul >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/gpio0< / strong > : GPIO Input for SX1262 Busy Pin< / p >
2021-12-30 10:58:30 +08:00
< / li >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/gpio1< / strong > : GPIO Output for SX1262 Chip Select< / p >
< / li >
< li >
< p > < strong > /dev/gpio2< / strong > : GPIO Interrupt for SX1262 DIO1 Pin< / p >
< / li >
< li >
2021-12-30 20:20:16 +08:00
< p > < strong > /dev/spi0< / strong > : SPI Bus for SX1262< / p >
< / li >
< li >
2021-12-30 18:14:03 +08:00
< p > < strong > /dev/spitest0< / strong > : SPI Test Driver (see above)< / p >
2021-12-30 10:58:30 +08:00
< / li >
< / ul >
2021-12-31 01:42:31 +08:00
< h1 id = "lorawan-objective" class = "section-header" > < a href = "#lorawan-objective" > 2 LoRaWAN Objective< / a > < / h1 >
< p > < em > What shall we accomplish with LoRaWAN today?< / em > < / p >
< p > We’ ll do the basic LoRaWAN use case on NuttX…< / p >
< ul >
< li >
2021-12-31 10:02:51 +08:00
< p > Join NuttX to the < strong > LoRaWAN Network< / strong > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > Send a < strong > Data Packet< / strong > from NuttX to LoRaWAN< / p >
< / li >
< / ul >
< p > Which works like this…< / p >
2021-12-31 09:48:18 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow.jpg" alt = "LoRaWAN Use Case" / > < / p >
2021-12-31 01:42:31 +08:00
< ol >
< li >
< p > NuttX sends a < strong > Join Network Request< / strong > to the LoRaWAN Gateway.< / p >
< p > Inside the Join Network Request are…< / p >
2021-12-31 10:02:51 +08:00
< p > < strong > Device EUI:< / strong > Unique ID that’ s assigned to our LoRaWAN Device< / p >
< p > < strong > Join EUI:< / strong > Identifies the LoRaWAN Network that we’ re joining< / p >
2021-12-31 10:24:15 +08:00
< p > < strong > Nonce:< / strong > Non-repeating number, to prevent < a href = "https://en.wikipedia.org/wiki/Replay_attack" > Replay Attacks< / a > < / p >
2022-01-01 09:56:22 +08:00
< p > < em > (EUI sounds like Durian on Century Egg… But it actually means Extended Unique Identifier)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > LoRaWAN Gateway returns a < strong > Join Network Response< / strong > < / p >
2021-12-31 14:41:03 +08:00
< p > < em > (Which contains the Device Address)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > NuttX sends a < strong > Data Packet< / strong > to the LoRaWAN Network< / p >
2021-12-31 14:41:03 +08:00
< p > < em > (Which has the Device Address and Payload “Hi NuttX”)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< li >
< p > NuttX uses an < strong > App Key< / strong > to sign the Join Network Request and the Data Packet< / p >
2021-12-31 14:41:03 +08:00
< p > < em > (App Key is stored inside NuttX, never exposed over the airwaves)< / em > < / p >
2021-12-31 01:42:31 +08:00
< / li >
< / ol >
2021-12-31 14:27:01 +08:00
< p > In a while we’ ll set the Device EUI, Join EUI and App Key in our code.< / p >
2021-12-31 09:48:18 +08:00
< h1 id = "download-source-code" class = "section-header" > < a href = "#download-source-code" > 3 Download Source Code< / a > < / h1 >
2021-12-31 14:27:01 +08:00
< p > To run LoRaWAN on NuttX, download the modified source code for < strong > NuttX OS and NuttX Apps< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > mkdir nuttx
cd nuttx
git clone --recursive --branch lorawan https://github.com/lupyuen/incubator-nuttx nuttx
git clone --recursive --branch lorawan https://github.com/lupyuen/incubator-nuttx-apps apps< / code > < / pre > < / div >
< p > Or if we prefer to < strong > add the LoRaWAN Library< / strong > to our NuttX Project, follow these instructions…< / p >
< ol >
< li >
< p > < a href = "https://github.com/lupyuen/incubator-nuttx/tree/lorawan/drivers/rf" > < strong > “Install SPI Test Driver”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/nimble-porting-nuttx" > < strong > “Install NimBLE Porting Layer”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/tree/lorawan" > < strong > “Install LoRa SX1262 Library”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > < strong > “Install LoRaWAN Library”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://github.com/lupyuen/lorawan_test" > < strong > “Install LoRaWAN Test App”< / strong > < / a > < / p >
< / li >
< / ol >
2021-12-31 16:24:13 +08:00
< p > Let’ s configure our LoRaWAN code.< / p >
2021-12-31 15:33:02 +08:00
< p > < img src = "https://lupyuen.github.io/images/wisgate-app2.png" alt = "Device EUI from ChirpStack" / > < / p >
2021-12-31 09:48:18 +08:00
< h1 id = "device-eui-join-eui-and-app-key" class = "section-header" > < a href = "#device-eui-join-eui-and-app-key" > 4 Device EUI, Join EUI and App Key< / a > < / h1 >
2021-12-31 14:27:01 +08:00
< p > < em > Where do we get the Device EUI, Join EUI and App Key?< / em > < / p >
2021-12-31 15:33:02 +08:00
< p > We get the LoRaWAN Settings from our < strong > LoRaWAN Gateway< / strong > , like ChirpStack (pic above)…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/wisgate#lorawan-application" > < strong > “LoRaWAN Application (ChirpStack)”< / strong > < / a > < / li >
< / ul >
< p > < em > How do we set the Device EUI, Join EUI and App Key in our code?< / em > < / p >
< p > Edit the file…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > nuttx/libs/liblorawan/src/peripherals/soft-se/se-identity.h< / code > < / pre > < / div >
2021-12-31 17:09:16 +08:00
< p > Look for these lines in < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/peripherals/soft-se/se-identity.h#L65-L79" > < strong > se-identity.h< / strong > < / a > < / p >
2021-12-31 15:33:02 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > /*!
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically set with a value provided by MCU platform
*/
#define STATIC_DEVICE_EUI 1
/*!
* end-device IEEE EUI (big endian)
*/
#define LORAWAN_DEVICE_EUI { 0x4b, 0xc1, 0x5e, 0xe7, 0x37, 0x7b, 0xb1, 0x5b }
/*!
* App/Join server IEEE EUI (big endian)
*/
#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }< / code > < / pre > < / div >
< ul >
< li >
< p > < strong > STATIC_DEVICE_EUI:< / strong > Must be < code > 1< / code > < / p >
< / li >
< li >
< p > < strong > LORAWAN_DEVICE_EUI:< / strong > Change this to our < strong > LoRaWAN Device EUI< / strong > .< / p >
2021-12-31 17:46:40 +08:00
< p > For ChirpStack: Copy from “Applications → app → Device EUI”< / p >
2021-12-31 15:33:02 +08:00
< / li >
< li >
< p > < strong > LORAWAN_JOIN_EUI:< / strong > Change this to our < strong > LoRaWAN Join EUI< / strong > .< / p >
2021-12-31 16:19:00 +08:00
< p > For ChirpStack: Join EUI is not needed, we leave it as zeroes< / p >
2021-12-31 15:33:02 +08:00
< / li >
< / ul >
2021-12-31 15:55:25 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-secure1.png" alt = "Device EUI and Join EUI" / > < / p >
2021-12-31 17:09:16 +08:00
< p > Next find this in the same file < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/peripherals/soft-se/se-identity.h#L98-L115" > < strong > se-identity.h< / strong > < / a > < / p >
2021-12-31 15:33:02 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > #define SOFT_SE_KEY_LIST \
{ \
{ \
/*! \
* Application root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \
*/ \
.KeyID = APP_KEY, \
.KeyValue = { 0xaa, 0xff, 0xad, 0x5c, 0x7e, 0x87, 0xf6, 0x4d, 0xe3, 0xf0, 0x87, 0x32, 0xfc, 0x1d, 0xd2, 0x5d }, \
}, \
{ \
/*! \
* Network root key \
* WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \
*/ \
.KeyID = NWK_KEY, \
.KeyValue = { 0xaa, 0xff, 0xad, 0x5c, 0x7e, 0x87, 0xf6, 0x4d, 0xe3, 0xf0, 0x87, 0x32, 0xfc, 0x1d, 0xd2, 0x5d }, \
}, \< / code > < / pre > < / div >
< ul >
< li >
< p > < strong > APP_KEY:< / strong > Change this to our < strong > LoRaWAN App Key< / strong > < / p >
2021-12-31 17:46:40 +08:00
< p > For ChirpStack: Copy from “Applications → app → Devices → device_otaa_class_a → Keys (OTAA) → Application Key”< / p >
2021-12-31 15:33:02 +08:00
< / li >
< li >
< p > < strong > NWK_KEY:< / strong > Change this to our < strong > LoRaWAN App Key< / strong > < / p >
< p > (Same as < strong > APP_KEY< / strong > )< / p >
< / li >
< / ul >
2021-12-31 15:55:25 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-secure2a.png" alt = "App Key" / > < / p >
2021-12-31 17:52:11 +08:00
< h2 id = "secure-element" class = "section-header" > < a href = "#secure-element" > 4.1 Secure Element< / a > < / h2 >
2021-12-31 15:55:25 +08:00
< p > < em > What’ s “soft-se”? Why are our LoRaWAN Settings there?< / em > < / p >
2021-12-31 18:21:35 +08:00
< p > For LoRaWAN Devices that are designed to be < strong > super secure< / strong > , they < strong > don’ t expose the LoRaWAN App Key< / strong > in the firmware code…< / p >
2021-12-31 16:19:00 +08:00
< p > Instead they store the App Key in the < a href = "https://encyclopedia.kaspersky.com/glossary/secure-element/" > < strong > Secure Element< / strong > < / a > hardware.< / p >
2021-12-31 17:46:40 +08:00
< p > Our LoRaWAN Library supports two kinds of Secure Elements: < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/atecc608a-tnglora-se" > < strong > Microchip ATECC608A< / strong > < / a > and < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/lr1110-se" > < strong > Semtech LR1110< / strong > < / a > < / p >
2021-12-31 16:19:00 +08:00
< p > < em > But our NuttX Device doesn’ t have a Secure Element right?< / em > < / p >
< p > That’ s why we define the App Key in the < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/soft-se" > < strong > “Software Secure Element (soft-se)”< / strong > < / a > that simulates a Hardware Secure Element… Minus the actual hardware security.< / p >
2021-12-31 18:21:35 +08:00
< p > Our App Key will be exposed if somebody dumps the firmware for our NuttX Device. But it’ s probably OK during development.< / p >
2021-12-31 16:24:13 +08:00
< h1 id = "lorawan-frequency" class = "section-header" > < a href = "#lorawan-frequency" > 5 LoRaWAN Frequency< / a > < / h1 >
2021-12-31 17:46:40 +08:00
< p > Let’ s set the LoRaWAN Frequency…< / p >
2021-12-31 17:09:16 +08:00
< ol >
< li >
< p > Find the < strong > LoRaWAN Frequency< / strong > for our region…< / p >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html" > < strong > “Frequency Plans by Country”< / strong > < / a > < / p >
< / li >
< li >
< p > Edit our < strong > LoRaWAN Test App< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > apps/examples/lorawan_test/lorawan_test_main.c< / code > < / pre > < / div > < / li >
< li >
< p > Find this in < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L34-L40" > < strong > lorawan_test_main.c< / strong > < / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > #ifndef ACTIVE_REGION
#warning " No active region defined, LORAMAC_REGION_AS923 will be used as default."
#define ACTIVE_REGION LORAMAC_REGION_AS923
#endif< / code > < / pre > < / div > < / li >
< li >
< p > Change < strong > AS923< / strong > (both occurrences) to our LoRaWAN Frequency…< / p >
< p > < strong > US915< / strong > , < strong > CN779< / strong > , < strong > EU433< / strong > , < strong > AU915< / strong > , < strong > AS923< / strong > , < strong > CN470< / strong > , < strong > KR920< / strong > , < strong > IN865< / strong > or < strong > RU864< / strong > < / p >
< / li >
< li >
2021-12-31 17:52:11 +08:00
< p > Do the same for the LoRaMAC Handler: < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/apps/LoRaMac/common/LmHandler/LmHandler.c#L41-L47" > < strong > LmHandler.c< / strong > < / a > < / p >
2021-12-31 17:09:16 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > nuttx/libs/liblorawan/src/apps/LoRaMac/common/LmHandler/LmHandler.c< / code > < / pre > < / div >
< p > (We ought to define this parameter in Kconfig instead)< / p >
< / li >
< / ol >
2021-12-31 19:09:25 +08:00
< h1 id = "build-the-firmware" class = "section-header" > < a href = "#build-the-firmware" > 6 Build The Firmware< / a > < / h1 >
< p > Let’ s build the NuttX Firmware that contains our < strong > LoRaWAN Library< / strong > …< / p >
< ol >
< li >
< p > Install the build prerequisites…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#install-prerequisites" > < strong > “Install Prerequisites”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 10:27:28 +08:00
< p > Assume that we have downloaded the < strong > NuttX Source Code< / strong > and configured the < strong > LoRaWAN Settings< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#download-source-code" > < strong > “Download Source Code”< / strong > < / a > < / p >
2022-01-01 10:27:28 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#device-eui-join-eui-and-app-key" > < strong > “Device EUI, Join EUI and App Key”< / strong > < / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#lorawan-frequency" > < strong > “LoRaWAN Frequency”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:14:14 +08:00
< p > Edit the < strong > Pin Definitions< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > # For BL602 and BL604:
nuttx/boards/risc-v/bl602/bl602evb/include/board.h
# For ESP32: Change " esp32-devkitc" to our ESP32 board
nuttx/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c< / code > < / pre > < / div >
< p > Check that the < strong > Semtech SX1262 Pins< / strong > are configured correctly in < a href = "https://github.com/lupyuen/incubator-nuttx/blob/lorawan/boards/risc-v/bl602/bl602evb/include/board.h#L36-L95" > < strong > board.h< / strong > < / a > or < a href = "https://github.com/lupyuen/incubator-nuttx/blob/lorawan/boards/xtensa/esp32/esp32-devkitc/src/esp32_gpio.c#L43-L67" > < strong > esp32_gpio.c< / strong > < / a > …< / p >
< p > < a href = "https://lupyuen.github.io/articles/sx1262#connect-sx1262-transceiver" > < strong > “Connect SX1262 Transceiver”< / strong > < / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > Configure the build…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > cd nuttx
# For BL602: Configure the build for BL602
./tools/configure.sh bl602evb:nsh
# For ESP32: Configure the build for ESP32.
# TODO: Change " esp32-devkitc" to our ESP32 board.
./tools/configure.sh esp32-devkitc:nsh
# Edit the Build Config
make menuconfig < / code > < / pre > < / div > < / li >
< li >
< p > Enable the < strong > GPIO Driver< / strong > in menuconfig…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#enable-gpio-driver" > < strong > “Enable GPIO Driver”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:16:40 +08:00
< p > Enable the < strong > SPI Peripheral< / strong > , < strong > SPI Character Driver< / strong > and < strong > SPI Test Driver< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/spi2#enable-spi" > < strong > “Enable SPI”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 12:16:40 +08:00
< p > Enable < strong > GPIO and SPI Logging< / strong > for easier troubleshooting, but uncheck < strong > “Enable Info Debug Output”< / strong > , < strong > “GPIO Info Output”< / strong > and < strong > “SPI Info Output”< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/spi2#enable-logging" > < strong > “Enable Logging”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 09:47:11 +08:00
< p > Enable < strong > Stack Backtrace< / strong > for easier troubleshooting…< / p >
< p > Check the box for < strong > “RTOS Features”< / strong > → < strong > “Stack Backtrace”< / strong > < / p >
< p > < a href = "https://lupyuen.github.io/images/lorawan3-config4.png" > (See this)< / a > < / p >
< / li >
< li >
2022-01-01 10:23:28 +08:00
< p > Enable < strong > POSIX Timers and Message Queues< / strong > (for NimBLE Porting Layer)…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-posix-timers-and-message-queues" > < strong > “POSIX Timers and Message Queues”< / strong > < / a > < / p >
2021-12-31 19:55:05 +08:00
< / li >
< li >
2022-01-01 10:23:28 +08:00
< p > Enable < strong > Random Number Generator with Entropy Pool< / strong > (for LoRaWAN Nonces)…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-random-number-generator-with-entropy-pool" > < strong > “Random Number Generator with Entropy Pool”< / strong > < / a > < / p >
< p > (We’ ll talk about this in a while)< / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > Click < strong > “Library Routines”< / strong > and enable the following libraries…< / p >
< p > < strong > “LoRaWAN Library”< / strong > < / p >
< p > < strong > “NimBLE Porting Layer”< / strong > < / p >
< p > < strong > “Semtech SX1262 Library”< / strong > < / p >
< / li >
< li >
< p > Enable our < strong > LoRaWAN Test App< / strong > …< / p >
< p > Check the box for < strong > “Application Configuration”< / strong > → < strong > “Examples”< / strong > → < strong > “LoRaWAN Test App”< / strong > < / p >
< / li >
< li >
< p > Save the configuration and exit menuconfig< / p >
2022-01-01 12:16:40 +08:00
< p > < a href = "https://gist.github.com/lupyuen/d0487cda965f72ed99631d168ea4f5c8" > (See the .config for BL602 and BL604)< / a > < / p >
2021-12-31 19:09:25 +08:00
< / li >
< li >
< p > < strong > For ESP32:< / strong > Edit < a href = "https://github.com/lupyuen/incubator-nuttx/blob/spi_test/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c#L118-L426" > < strong > esp32_bringup.c< / strong > < / a > to register our SPI Test Driver < a href = "https://lupyuen.github.io/articles/spi2#register-device-driver" > (See this)< / a > < / p >
< / li >
< li >
< p > Build, flash and run the NuttX Firmware on BL602 or ESP32…< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#appendix-build-flash-and-run-nuttx" > < strong > “Build, Flash and Run NuttX”< / strong > < / a > < / p >
< / li >
< / ol >
2022-01-01 13:38:19 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx3.png" alt = "Our NuttX Device successfully joins the LoRaWAN Network" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (Source)< / a > < / p >
2021-12-31 19:09:25 +08:00
< h1 id = "run-the-firmware" class = "section-header" > < a href = "#run-the-firmware" > 7 Run The Firmware< / a > < / h1 >
2022-01-01 13:38:19 +08:00
< p > We’ re ready to run the NuttX Firmware and test our < strong > LoRaWAN Library< / strong > !< / p >
2021-12-31 19:09:25 +08:00
< ol >
< li >
2022-01-01 13:38:19 +08:00
< p > In the NuttX Shell, list the < strong > NuttX Devices< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > ls /dev< / code > < / pre > < / div > < / li >
2021-12-31 19:55:05 +08:00
< li >
< p > We should see…< / p >
2022-01-01 13:38:19 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > /dev:
gpio0
gpio1
gpio2
spi0
spitest0
urandom
...< / code > < / pre > < / div >
< p > Our SPI Test Driver appears as < strong > “/dev/spitest0”< / strong > < / p >
< p > The SX1262 Pins for Busy, Chip Select and DIO1 should appear as < strong > “/dev/gpio0”< / strong > (GPIO Input), < strong > “gpio1”< / strong > (GPIO Output) and < strong > “gpio2”< / strong > (GPIO Interrupt) respectively.< / p >
< p > The Random Number Generator (with Entropy Pool) appears as < strong > “/dev/urandom”< / strong > < / p >
< / li >
< li >
< p > In the NuttX Shell, run our < strong > LoRaWAN Test App< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > lorawan_test< / code > < / pre > < / div >
< p > Our app sends a < strong > Join Network Request< / strong > to the LoRaWAN Gateway…< / p >
2022-01-01 20:36:08 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > RadioSetPublicNetwork: public syncword=3444
DevEui : 4B-C1-5E-E7-37-7B-B1-5B
JoinEui : 00-00-00-00-00-00-00-00
Pin : 00-00-00-00
## =========== MLME-Request ============ ##
2022-01-01 13:38:19 +08:00
## MLME_JOIN ##
## ===================================== ##
2022-01-01 20:36:08 +08:00
STATUS : OK< / code > < / pre > < / div >
< p > (Which contains the Device EUI and Join EUI that we have configured earlier)< / p >
< / li >
2022-01-01 13:38:19 +08:00
< li >
< p > A few seconds later we should see the < strong > Join Network Response< / strong > from the LoRaWAN Gateway…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > ## =========== MLME-Confirm ============ ##
STATUS : OK
## =========== JOINED ============ ##
OTAA
DevAddr : 01DA9790
DATA RATE : DR_2< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< p > Congratulations our NuttX Device has successfully joined the LoRaWAN Network!< / p >
< / li >
< li >
< p > If we see this instead…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > ## =========== MLME-Confirm ============ ##
STATUS : Rx 1 timeout< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/007788b9ea3974b127f6260bf57f5d8b" > (See the Output Log)< / a > < / p >
< p > Our Join Network Request has failed.< / p >
< p > Check the next section for troubleshooting tips.< / p >
< / li >
< li >
2022-01-01 19:06:48 +08:00
< p > Our LoRaWAN Test App continues to < strong > transmit Data Packets< / strong > . But we’ ll cover this later…< / p >
2022-01-01 13:38:19 +08:00
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
PrepareTxFrame: status=0, maxSize=11, currentSize=11
## =========== MCPS-Request ============ ##
## MCPS_UNCONFIRMED ##
## ===================================== ##
STATUS : OK
PrepareTxFrame: Transmit OK< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
2022-01-01 19:06:48 +08:00
< p > Let’ s find out how our LoRaWAN Test App joins the LoRaWAN Network.< / p >
2021-12-31 19:09:25 +08:00
< / li >
< / ol >
2022-01-01 19:06:48 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow2.jpg" alt = "Join LoRaWAN Network" / > < / p >
2021-12-31 19:55:05 +08:00
< h1 id = "join-lorawan-network" class = "section-header" > < a href = "#join-lorawan-network" > 8 Join LoRaWAN Network< / a > < / h1 >
2022-01-01 14:17:40 +08:00
< p > < em > How do we join the LoRaWAN Network in our NuttX App?< / em > < / p >
2022-01-01 19:06:48 +08:00
< p > Let’ s dive into the code for our < strong > LoRaWAN Test App< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L260-L303" > lorawan_test_main.c< / a > < / p >
2022-01-01 14:17:40 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > int main(int argc, FAR char *argv[]) {
2022-01-01 14:22:19 +08:00
// Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > Our app begins by computing the < strong > Time Interval Between Transmissions< / strong > of our Data Packets.< / p >
< p > (More about this later)< / p >
< p > Next it calls < strong > LmHandlerInit< / strong > to initialise the LoRaWAN Library…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Init LoRaWAN
2022-01-02 12:25:44 +08:00
if ( LmHandlerInit(
& LmHandlerCallbacks, // Callback Functions
& LmHandlerParams // LoRaWAN Parameters
) != LORAMAC_HANDLER_SUCCESS ) {
2022-01-01 14:22:19 +08:00
printf( " LoRaMac wasn' t properly initialized\n" );
while ( 1 ) {} // Fatal error, endless loop.
}< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > (Functions named < strong > “Lm…”< / strong > come from our LoRaWAN Library)< / p >
2022-01-01 19:06:48 +08:00
< p > We set load the < strong > LoRa Alliance Compliance Protocol Packages< / strong > …< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Set system maximum tolerated rx error in milliseconds
LmHandlerSetSystemMaxRxError( 20 );
2022-01-01 14:17:40 +08:00
2022-01-01 14:22:19 +08:00
// LoRa-Alliance Compliance protocol package should always be initialized and activated.
LmHandlerPackageRegister( PACKAGE_ID_COMPLIANCE, & LmhpComplianceParams );
LmHandlerPackageRegister( PACKAGE_ID_CLOCK_SYNC, NULL );
LmHandlerPackageRegister( PACKAGE_ID_REMOTE_MCAST_SETUP, NULL );
LmHandlerPackageRegister( PACKAGE_ID_FRAGMENTATION, & FragmentationParams );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > Below is the code that sends the < strong > Join Network Request< / strong > to the LoRaWAN Gateway: < strong > LmHandlerJoin< / strong > …< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Join the LoRaWAN Network
LmHandlerJoin( );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > We start the < strong > Transmit Timer< / strong > that will schedule the transmission of Data Packets (right after we have joined the LoRaWAN Network)…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Set the Transmit Timer
StartTxProcess( LORAMAC_HANDLER_TX_ON_TIMER );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > At this point we haven’ t actually joined the LoRaWAN Network yet.< / p >
< p > This happens in the < strong > LoRaWAN Event Loop< / strong > that will handle the < strong > Join Network Response< / strong > received from the LoRaWAN Gateway…< / p >
2022-01-01 14:22:19 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Handle LoRaWAN Events
handle_event_queue( NULL ); // Never returns
return 0;
2022-01-01 14:17:40 +08:00
}< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > (We’ ll talk about the LoRaWAN Event Loop later)< / p >
< p > Let’ s check the logs on our LoRaWAN Gateway. (RAKwireless WisGate, the black box below)< / p >
2021-12-31 18:21:35 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
2022-01-01 20:36:08 +08:00
< h2 id = "check-lorawan-gateway" class = "section-header" > < a href = "#check-lorawan-gateway" > 8.1 Check LoRaWAN Gateway< / a > < / h2 >
< p > To inspect the Join Network Request on our < strong > LoRaWAN Gateway< / strong > (ChirpStack), click…< / p >
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > LoRaWAN Frames< / strong > < / p >
< p > Restart our NuttX Device and the LoRaWAN Test App…< / p >
< ul >
< li > < a href = "https://lupyuen.github.io/articles/lorawan3#run-the-firmware" > < strong > “Run The Firmware”< / strong > < / a > < / li >
< / ul >
< p > The < strong > Join Network Request< / strong > appears in ChirpStack…< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack.png" alt = "Join Network Request" / > < / p >
< p > (Yep that’ s the Device EUI and Join EUI that we have configured earlier)< / p >
< p > Followed by the < strong > Join Accept Response< / strong > …< / p >
2022-01-02 08:00:58 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack7.png" alt = "Join Accept Response" / > < / p >
2022-01-01 20:36:08 +08:00
< p > The Join Network Request / Response also appears in ChirpStack at…< / p >
< p > < strong > Applications< / strong > → < strong > app< / strong > → < strong > device_otaa_class_a< / strong > → < strong > Device Data< / strong > < / p >
< p > Like so…< / p >
2022-01-02 08:00:58 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack10.png" alt = "Join Accept Response" / > < / p >
2022-01-01 20:36:08 +08:00
< p > < em > What if we don’ t see the Join Network Request or the Join Accept Response?< / em > < / p >
< p > Check the < strong > “Troubleshoot LoRaWAN”< / strong > section below for troubleshooting tips.< / p >
2021-12-31 19:55:05 +08:00
< h1 id = "send-data-to-lorawan" class = "section-header" > < a href = "#send-data-to-lorawan" > 9 Send Data To LoRaWAN< / a > < / h1 >
2022-01-02 12:25:44 +08:00
< p > Now that we’ ve joined the LoRaWAN Network, we’ re ready to < strong > send Data Packets< / strong > to LoRaWAN!< / p >
< p > < strong > PrepareTxFrame< / strong > is called by our LoRaWAN Event Loop to send a Data Packet when the < strong > Transmit Timer< / strong > expires: < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L305-L336" > lorawan_test_main.c< / a > < / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Prepare the payload of a Data Packet transmit it
static void PrepareTxFrame( void ) {
2022-01-02 12:25:44 +08:00
2022-01-02 09:32:47 +08:00
// If we haven' t joined the LoRaWAN Network, try again later
if (LmHandlerIsBusy()) { puts(" PrepareTxFrame: Busy" ); return; }< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > If we haven’ t joined a LoRaWAN Network yet, this function will return. (And we’ ll try again later)< / p >
< p > Assuming all is hunky dory, we proceed to transmit a < strong > 9-byte message< / strong > (including terminating null)…< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Send a message to LoRaWAN
const char msg[] = " Hi NuttX" ;
printf(" PrepareTxFrame: Transmit to LoRaWAN: %s (%d bytes)\n" , msg, sizeof(msg));< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > We copy the message to the < strong > Transmit Buffer< / strong > (max 242 bytes) and create a < strong > Transmit Request< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Compose the transmit request
2022-01-02 12:25:44 +08:00
assert(sizeof(msg) < = sizeof(AppDataBuffer));
2022-01-02 09:32:47 +08:00
memcpy(AppDataBuffer, msg, sizeof(msg));
2022-01-02 12:25:44 +08:00
LmHandlerAppData_t appData = { // Transmit Request contains...
.Buffer = AppDataBuffer, // Transmit Buffer
.BufferSize = sizeof(msg), // Size of Transmit Buffer
.Port = 1, // Port Number: 1 to 223
2022-01-02 09:32:47 +08:00
};< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > Next we < strong > validate the Message Size< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Validate the message size and check if it can be transmitted
LoRaMacTxInfo_t txInfo;
2022-01-02 12:25:44 +08:00
LoRaMacStatus_t status = LoRaMacQueryTxPossible(
appData.BufferSize, // Message size
& txInfo // Returns max message size
);
2022-01-02 09:32:47 +08:00
printf(" PrepareTxFrame: status=%d, maxSize=%d, currentSize=%d\n" , status, txInfo.MaxPossibleApplicationDataSize, txInfo.CurrentPossiblePayloadSize);
assert(status == LORAMAC_STATUS_OK);< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > (What’ s the Maximum Message Size? We’ ll discuss in a while)< / p >
< p > Finally we < strong > transmit the message< / strong > …< / p >
2022-01-02 09:32:47 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Transmit the message
2022-01-02 12:25:44 +08:00
LmHandlerErrorStatus_t sendStatus = LmHandlerSend(
& appData, // Transmit Request
LmHandlerParams.IsTxConfirmed // 0 for Unconfirmed
);
2022-01-02 09:32:47 +08:00
assert(sendStatus == LORAMAC_HANDLER_SUCCESS);
puts(" PrepareTxFrame: Transmit OK" );
2022-01-01 20:36:08 +08:00
}< / code > < / pre > < / div >
2022-01-02 12:25:44 +08:00
< p > < em > Why is our Data Packet marked Unconfirmed?< / em > < / p >
< p > Our Data Packet is marked Unconfirmed because we < strong > don’ t expect an acknowledgement< / strong > from the LoRaWAN Gateway.< / p >
< p > This is the typical mode for < strong > IoT Sensor Devices< / strong > , which don’ t handle acknowledgements to conserve battery power. < / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx6.png" alt = "Sending a LoRaWAN Data Packet" / > < / p >
2022-01-02 09:32:47 +08:00
< h2 id = "message-size" class = "section-header" > < a href = "#message-size" > 9.1 Message Size< / a > < / h2 >
2022-01-02 13:56:23 +08:00
< p > < em > What’ s the Maximum Message Size?< / em > < / p >
2022-01-02 13:37:59 +08:00
< p > The < strong > Maximum Message (Payload) Size< / strong > depends on…< / p >
< ul >
< li >
< p > < strong > LoRaWAN Data Rate< / strong > (like Data Rate 2 or 3)< / p >
< / li >
< li >
< p > < strong > LoRaWAN Region< / strong > (AS923 for Asia, AU915 for Australia / Brazil / New Zealand, EU868 for Europe, US915 for US, …)< / p >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html" > (See this)< / a > < / p >
< / li >
< / ul >
< p > Our LoRaWAN Test App uses < strong > Data Rate 3< / strong > : < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L58-L70" > lorawan_test_main.c< / a > < / p >
< div class = "example-wrap" > < pre class = "language-c" > < code > // LoRaWAN Adaptive Data Rate
// Please note that when ADR is enabled the end-device should be static
#define LORAWAN_ADR_STATE LORAMAC_HANDLER_ADR_OFF
2022-01-02 12:25:44 +08:00
2022-01-02 13:37:59 +08:00
// Default Data Rate
// Please note that LORAWAN_DEFAULT_DATARATE is used only when ADR is disabled
#define LORAWAN_DEFAULT_DATARATE DR_3< / code > < / pre > < / div >
< p > But there’ s a catch: The < strong > First Message Transmitted< / strong > (after joining LoRaWAN) will have < strong > Data Rate 2< / strong > (instead of Data Rate 3)!< / p >
< p > (We’ ll see this in the upcoming demo)< / p >
< p > For Data Rates 2 and 3, the < strong > Maximum Message (Payload) Sizes< / strong > are…< / p >
< div > < table > < thead > < tr > < th align = "center" > Region< / th > < th align = "center" > Data Rate< / th > < th align = "center" > Max Payload Size< / th > < / tr > < / thead > < tbody >
< tr > < td align = "center" > < strong > AS923< / strong > < / td > < td align = "center" > DR 2 < br > DR 3< / td > < td align = "center" > 11 bytes < br > 53 bytes< / td > < / tr >
< tr > < td align = "center" > < strong > AU915< / strong > < / td > < td align = "center" > DR 2 < br > DR 3< / td > < td align = "center" > 11 bytes < br > 53 bytes< / td > < / tr >
< tr > < td align = "center" > < strong > EU868< / strong > < / td > < td align = "center" > DR 2 < br > DR 3< / td > < td align = "center" > 51 bytes < br > 115 bytes< / td > < / tr >
< tr > < td align = "center" > < strong > US915< / strong > < / td > < td align = "center" > DR 2 < br > DR 3< / td > < td align = "center" > 125 bytes < br > 222 bytes< / td > < / tr >
< / tbody > < / table >
< / div >
< p > < a href = "https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/" > (Based on LoRaWAN Regional Parameters)< / a > < / p >
< p > Our LoRaWAN Test App sends a Message Payload of < strong > 9 bytes< / strong > , so it should work fine for Data Rates 2 and 3 across all LoRaWAN Regions.< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx5a.png" alt = "Setting LoRaWAN Data Rate to 3" / > < / p >
< h2 id = "message-interval" class = "section-header" > < a href = "#message-interval" > 9.2 Message Interval< / a > < / h2 >
< p > < em > How often can we send data to the LoRaWAN Network?< / em > < / p >
2022-01-01 19:06:48 +08:00
< p > TODO< / p >
2022-01-02 12:25:44 +08:00
< p > From < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L47-L56" > lorawan_test_main.c< / a > < / p >
2022-01-02 13:37:59 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Defines the application data transmission duty cycle.
// 40s, value in [ms].
#define APP_TX_DUTYCYCLE 40000
2022-01-02 12:25:44 +08:00
2022-01-02 13:37:59 +08:00
// Defines a random delay for application data transmission duty cycle.
// 5s, value in [ms].
#define APP_TX_DUTYCYCLE_RND 5000< / code > < / pre > < / div >
2022-01-01 20:36:08 +08:00
< p > From < a href = "https://github.com/lupyuen/lorawan_test/blob/main/lorawan_test_main.c#L260-L303" > lorawan_test_main.c< / a > < / p >
2022-01-02 13:37:59 +08:00
< div class = "example-wrap" > < pre class = "language-c" > < code > // Compute the interval between transmissions based on Duty Cycle
TxPeriodicity = APP_TX_DUTYCYCLE +
randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );< / code > < / pre > < / div >
2022-01-01 19:06:48 +08:00
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/boards/mcu/utilities.c#L48-L51" > (< strong > randr< / strong > is defined here)< / a > < / p >
2022-01-02 13:37:59 +08:00
< p > TODO< / p >
2022-01-02 09:32:47 +08:00
< h1 id = "rerun-the-firmware" class = "section-header" > < a href = "#rerun-the-firmware" > 10 Rerun The Firmware< / a > < / h1 >
< p > TODO< / p >
2022-01-02 13:37:59 +08:00
< ol >
< li >
< p > In the NuttX Shell, run our < strong > LoRaWAN Test App< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > lorawan_test< / code > < / pre > < / div >
< p > Our app sends a < strong > Join Network Request< / strong > to the LoRaWAN Gateway…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > RadioSetPublicNetwork: public syncword=3444
DevEui : 4B-C1-5E-E7-37-7B-B1-5B
JoinEui : 00-00-00-00-00-00-00-00
Pin : 00-00-00-00
## =========== MLME-Request ============ ##
## MLME_JOIN ##
## ===================================== ##
STATUS : OK< / code > < / pre > < / div >
< p > (Which contains the Device EUI and Join EUI that we have configured earlier)< / p >
< / li >
< li >
< p > A few seconds later we should see the < strong > Join Network Response< / strong > from the LoRaWAN Gateway…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > ## =========== MLME-Confirm ============ ##
STATUS : OK
## =========== JOINED ============ ##
OTAA
DevAddr : 01DA9790
DATA RATE : DR_2< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< p > Congratulations our NuttX Device has successfully joined the LoRaWAN Network!< / p >
< / li >
< li >
< p > If we see this instead…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > ## =========== MLME-Confirm ============ ##
STATUS : Rx 1 timeout< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/007788b9ea3974b127f6260bf57f5d8b" > (See the Output Log)< / a > < / p >
< p > Our Join Network Request has failed.< / p >
< p > Check the next section for troubleshooting tips.< / p >
< / li >
< li >
< p > Our LoRaWAN Test App continues to < strong > transmit Data Packets< / strong > . But we’ ll cover this later…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
PrepareTxFrame: status=0, maxSize=11, currentSize=11
## =========== MCPS-Request ============ ##
## MCPS_UNCONFIRMED ##
## ===================================== ##
STATUS : OK
PrepareTxFrame: Transmit OK
...
## =========== MCPS-Confirm ============ ##
STATUS : OK
## ===== UPLINK FRAME 1 ===== ##
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
CHANNEL MASK: 0003
...
PrepareTxFrame: Transmit to LoRaWAN: Hi NuttX (9 bytes)
PrepareTxFrame: status=0, maxSize=53, currentSize=53
## =========== MCPS-Request ============ ##
## MCPS_UNCONFIRMED ##
## ===================================== ##
STATUS : OK
PrepareTxFrame: Transmit OK
...
## =========== MCPS-Confirm ============ ##
STATUS : OK
## ===== UPLINK FRAME 1 ===== ##
CLASS : A
TX PORT : 1
TX DATA : UNCONFIRMED
48 69 20 4E 75 74 74 58 00
DATA RATE : DR_3
U/L FREQ : 923400000
TX POWER : 0
CHANNEL MASK: 0003< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (See the Output Log)< / a > < / p >
< / li >
< / ol >
2022-01-02 12:25:44 +08:00
< h2 id = "check-lorawan-gateway-1" class = "section-header" > < a href = "#check-lorawan-gateway-1" > 10.1 Check LoRaWAN Gateway< / a > < / h2 >
< p > TODO< / p >
2022-01-02 09:32:47 +08:00
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack8.png" alt = "Send Data" / > < / p >
< p > TODO2< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack11.png" alt = "Send Data" / > < / p >
< h1 id = "lorawan-event-loop" class = "section-header" > < a href = "#lorawan-event-loop" > 11 LoRaWAN Event Loop< / a > < / h1 >
2021-12-31 18:21:35 +08:00
< p > TODO< / p >
< p > Here’ s our #LoRaWAN Event Loop for #NuttX OS … Implemented with NimBLE Porting Library … No more polling!< / p >
< p > TODO54< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-npl1.png" alt = "" / > < / p >
< p > TODO58< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run5a.png" alt = "" / > < / p >
2022-01-01 19:13:46 +08:00
< p > TODO< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-flow2.jpg" alt = "Join LoRaWAN Network" / > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "lorawan-nonce" class = "section-header" > < a href = "#lorawan-nonce" > 12 LoRaWAN Nonce< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-31 16:19:00 +08:00
< p > Our #NuttX App resends the same Nonce to the #LoRaWAN Gateway … Which (silently) rejects the Join Request due to Duplicate Nonce … Let’ s fix our Random Number Generator< / p >
< p > TODO34< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack2a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/b38434c3d27500444382bb4a066691e5" > (Log)< / a > < / p >
< p > #LoRaWAN gets the Nonce from the Secure Element’ s Random Number Generator … Let’ s simulate the Secure Element on Apache #NuttX OS< / p >
< p > TODO51< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce2a.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/mac/LoRaMacCrypto.c#L980-L996" > (Source)< / a > < / p >
< p > Here’ s how we generate #LoRaWAN Nonces on #NuttX OS … With Strong Random Numbers thanks to Entropy Pool< / p >
< p > TODO53< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce6.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/nuttx.c#L136-L153" > (Source)< / a > < / p >
< p > Our #NuttX App now sends Random #LoRaWAN Nonces to the LoRaWAN Gateway … And are happily accepted by the gateway! 🎉< / p >
< p > TODO36< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce7a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/8f012856b9eb6b9a762160afd83df7f8" > (Log)< / a > < / p >
2021-12-31 09:48:18 +08:00
< p > < img src = "https://lupyuen.github.io/images/spi2-pinedio1.jpg" alt = "Inside PineDio Stack BL604" / > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "nimble-porting-layer" class = "section-header" > < a href = "#nimble-porting-layer" > 13 NimBLE Porting Layer< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > Our #NuttX App was waiting for the #LoRaWAN Join Request to be transmitted before receiving the Join Response … But because we’ re polling SX1262, we missed the Join Response … Let’ s fix this with the multithreading functions from NimBLE Porting Layer< / p >
< ul >
< li > < a href = "https://github.com/lupyuen/nimble-porting-nuttx" > < strong > nimble-porting-nuttx< / strong > < / a > < / li >
< / ul >
< p > TODO57< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run4a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/d3d9db37a40d7560fc211408db04a81b" > (Log)< / a > < / p >
< p > NimBLE Porting Layer is a portable library of Multithreading Functions … We’ ve used it for #LoRa on Linux and FreeRTOS … Now we call it from Apache #NuttX OS< / p >
2022-01-02 09:32:47 +08:00
< h1 id = "gpio-interrupts" class = "section-header" > < a href = "#gpio-interrupts" > 14 GPIO Interrupts< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > SX1262 will trigger a GPIO Interrupt on #NuttX OS when it receives a #LoRa Packet … We wait for the GPIO Interrupt to be Signalled in a Background Thread< / p >
< p > TODO46< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-gpio2.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/blob/lorawan/src/sx126x-nuttx.c#L742-L778" > (Source)< / a > < / p >
< p > We handle GPIO Interrupts (SX1262 DIO1) in a #NuttX Background Thread … Awaiting the Signal for GPIO Interrupt< / p >
< p > TODO47< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-gpio3.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/blob/lorawan/src/sx126x-nuttx.c#L835-L861" > (Source)< / a > < / p >
< p > Our #NuttX Background Thread handles the GPIO Interrupts (SX1262 DIO1) … By adding to the #LoRaWAN Event Queue< / p >
< p > TODO48< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-gpio4a.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/blob/lorawan/src/sx126x-nuttx.c#L863-L892" > (Source)< / a > < / p >
< p > #LoRaWAN runs neater on Apache #NuttX OS … After implementing Timers and Multithreading with NimBLE Porting Layer … No more sleep()!< / p >
< p > < a href = "https://gist.github.com/lupyuen/cad58115be4cabe8a8a49c0e498f1c95" > (Log)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "sx1262-busy" class = "section-header" > < a href = "#sx1262-busy" > 15 SX1262 Busy< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > Here’ s how we check the SX1262 Busy Pin on #NuttX OS … By reading the GPIO Input< / p >
< p > TODO49< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-gpio1.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/lora-sx1262/blob/lorawan/src/sx126x-nuttx.c#L184-L199" > (Source)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "troubleshoot-lorawan" class = "section-header" > < a href = "#troubleshoot-lorawan" > 16 Troubleshoot LoRaWAN< / a > < / h1 >
2021-12-31 19:55:05 +08:00
< p > TODO< / p >
2022-01-01 20:36:08 +08:00
< ul >
< li > < a href = "https://lupyuen.github.io/articles/wisgate#troubleshoot-lorawan" > < strong > “Troubleshoot LoRaWAN”< / strong > < / a > < / li >
< / ul >
2021-12-31 19:55:05 +08:00
< p > Check the LoRa Frequency, Sync Word, Device EUI and Join EUI< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run2a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/b91c1f88645eedb813cfffa2bdf7d7a0" > (Run Log)< / a > < / p >
2022-01-01 19:13:46 +08:00
< p > #NuttX OS doesn’ t handle the Join Response from #LoRaWAN Gateway … Let’ s fix this< / p >
< p > TODO56< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-run3.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/a8e834e7b4267345f01b6629fb7f5e33" > (Run Log)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h2 id = "logging" class = "section-header" > < a href = "#logging" > 16.1 Logging< / a > < / h2 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > Our #NuttX App was too busy to receive the #LoRaWAN Join Response … Let’ s disable the logging< / p >
< p > TODO62< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/8f012856b9eb6b9a762160afd83df7f8" > (Log)< / a > < / p >
< p > After disabling logging, our #NuttX App successfully joins the #LoRaWAN Network! 🎉 Now we transmit some Data Packets over LoRaWAN< / p >
< p > TODO63< / p >
< p > Our #LoRaWAN Gateway receives Data Packets from #NuttX OS! 🎉 The Message Payload is empty … Let’ s figure out why 🤔< / p >
< p > TODO44< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack5.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/0d301216bbf937147778bb57ab0ccf89" > (Log)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h2 id = "message-size-1" class = "section-header" > < a href = "#message-size-1" > 16.2 Message Size< / a > < / h2 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > Our #NuttX App sent an empty #LoRaWAN Message because our message is too long for LoRaWAN Data Rate 2 (max 11 bytes) … Let’ s increase the Data Rate to 3< / p >
< p > TODO65< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx4a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/5fc07695a6c4bb48b5e4d10eb05ca9bf" > (Log)< / a > < / p >
< p > #LoRaWAN Data Rate has been increased to 3 … Max Message Size is now 53 bytes for our #NuttX App< / p >
< p > TODO37< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-tx7a.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (Log)< / a > < / p >
< p > #LoRaWAN Gateway now receives the correct Data Packet from our #NuttX App! 🎉< / p >
< p > TODO45< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-chirpstack6.png" alt = "" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/83be5da091273bb39bad6e77cc91b68d" > (Log)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "spi-with-dma" class = "section-header" > < a href = "#spi-with-dma" > 17 SPI with DMA< / a > < / h1 >
2021-12-31 15:55:25 +08:00
< p > TODO< / p >
2022-01-02 09:32:47 +08:00
< h1 id = "whats-next" class = "section-header" > < a href = "#whats-next" > 18 What’ s Next< / a > < / h1 >
2021-12-31 01:49:00 +08:00
< p > TODO< / p >
< p > CBOR, TTN, Temperature Sensor< / p >
2021-12-30 10:58:30 +08:00
< p > In our next article we’ ll move on to < strong > LoRaWAN!< / strong > < / p >
< p > (Which will be super interesting because of multithreading)< / p >
< p > We’ ll port Semtech’ s < strong > Reference LoRaWAN Stack< / strong > to NuttX…< / p >
< ul >
< li > < a href = "https://github.com/lupyuen/LoRaMac-node-nuttx" > < strong > lupyuen/LoRaMac-node-nuttx< / strong > < / a > < / li >
< / ul >
< p > < em > We’ re porting plenty of code to NuttX: LoRa, LoRaWAN and NimBLE Porting Layer. Do we expect any problems?< / em > < / p >
< p > Yep we might have issues keeping our LoRaWAN Stack in sync with Semtech’ s version. < a href = "https://lupyuen.github.io/articles/sx1262#notes" > (But we shall minimise the changes)< / a > < / p >
< p > Stay Tuned!< / p >
< p > Many Thanks to my < a href = "https://github.com/sponsors/lupyuen" > < strong > GitHub Sponsors< / strong > < / a > for supporting my work! This article wouldn’ t have been possible without your support.< / p >
< ul >
< li >
< p > < a href = "https://github.com/sponsors/lupyuen" > Sponsor me a coffee< / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/articles/book" > Read “The RISC-V BL602 / BL604 Book”< / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io" > Check out my articles< / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/rss.xml" > RSS Feed< / a > < / p >
< / li >
< / ul >
< p > < em > Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…< / em > < / p >
< p > < a href = "https://github.com/lupyuen/lupyuen.github.io/blob/master/src/lorawan3.md" > < code > lupyuen.github.io/src/lorawan3.md< / code > < / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "notes" class = "section-header" > < a href = "#notes" > 19 Notes< / a > < / h1 >
2021-12-30 10:58:30 +08:00
< ol >
< li >
< p > This article is the expanded version of < a href = "https://twitter.com/MisterTechBlog/status/1473593455699841027" > this Twitter Thread< / a > < / p >
< / li >
< li >
< p > We’ re < strong > porting plenty of code< / strong > to NuttX: LoRa, LoRaWAN and NimBLE Porting Layer. Do we expect any problems?< / p >
< ul >
< li >
< p > If we implement LoRa and LoRaWAN as < strong > NuttX Drivers< / strong > , we’ ll have to scrub the code to comply with the < a href = "https://nuttx.apache.org/docs/latest/contributing/coding_style.html" > < strong > NuttX Coding Conventions< / strong > < / a > .< / p >
< p > This makes it < strong > harder to update< / strong > the LoRaWAN Driver when there are changes in the LoRaWAN Spec. (Like for a new LoRaWAN Region)< / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan#appendix-lora-carrier-sensing" > (Here’ s an example)< / a > < / p >
< / li >
< li >
< p > Alternatively we may implement LoRa and LoRaWAN as < strong > External Libraries< / strong > , similar to < a href = "https://github.com/lupyuen/incubator-nuttx-apps/tree/master/wireless/bluetooth/nimble" > < strong > NimBLE for NuttX< / strong > < / a > .< / p >
< p > (The < a href = "https://github.com/lupyuen/incubator-nuttx-apps/blob/master/wireless/bluetooth/nimble/Makefile#L33" > < strong > Makefile< / strong > < / a > downloads the External Library during build)< / p >
< p > But then we won’ t get a proper NuttX Driver that exposes the ioctl() interface to NuttX Apps.< / p >
< / li >
< / ul >
< p > Conundrum. Lemme know your thoughts!< / p >
< / li >
< li >
< p > How do other Embedded Operating Systems implement LoRaWAN?< / p >
< ul >
< li >
< p > < strong > Mynewt< / strong > embeds a < a href = "https://github.com/apache/mynewt-core/tree/master/net/lora/node" > < strong > Partial Copy< / strong > < / a > of Semtech’ s LoRaWAN Stack into its source tree.< / p >
< / li >
< li >
< p > < strong > Zephyr< / strong > maintains a < a href = "https://github.com/zephyrproject-rtos/loramac-node" > < strong > Complete Fork< / strong > < / a > of the entire LoRaWAN Repo by Semtech. Which gets embedded during the Zephyr build.< / p >
< / li >
< / ul >
< p > The Zephyr approach is probably the best way to < strong > keep our LoRaWAN Stack in sync< / strong > with Semtech’ s.< / p >
< / li >
< li >
< p > We have already ported LoRaWAN to < strong > BL602 IoT SDK< / strong > < a href = "https://lupyuen.github.io/articles/lorawan" > (see this)< / a > , why are we porting again to NuttX?< / p >
< p > Regrettably BL602 IoT SDK has been revamped (without warning) to the < strong > new “hosal” HAL< / strong > < a href = "https://twitter.com/MisterTechBlog/status/1456259223323508748" > (see this)< / a > , and the LoRaWAN Stack will < strong > no longer work< / strong > on the revamped BL602 IoT SDK.< / p >
< p > For easier maintenance, we shall < strong > code our BL602 and BL604 projects with Apache NuttX OS< / strong > instead.< / p >
< p > (Which won’ t get revamped overnight!)< / p >
< / li >
< li >
< p > Will NuttX become the official OS for PineDio Stack BL604 when it goes on sale?< / p >
< p > It might! But first let’ s get LoRaWAN (and ST7789) running on PineDio Stack.< / p >
< / li >
< / ol >
2022-01-02 09:32:47 +08:00
< h1 id = "appendix-posix-timers-and-message-queues" class = "section-header" > < a href = "#appendix-posix-timers-and-message-queues" > 20 Appendix: POSIX Timers and Message Queues< / a > < / h1 >
2022-01-01 09:47:11 +08:00
< p > NimBLE Porting Layer needs < strong > POSIX Timers and Message Queues< / strong > (plus more) to work. Follow the steps below to enable the features in < strong > menuconfig< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Disable NuttX Interfaces”< / strong > < / p >
< p > Uncheck < strong > “Disable POSIX Timers”< / strong > < / p >
< p > Uncheck < strong > “Disable POSIX Message Queue Support”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Clocks and Timers”< / strong > < / p >
< p > Check < strong > “Support CLOCK_MONOTONIC”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Work Queue Support”< / strong > < / p >
< p > Check < strong > “High Priority (Kernel) Worker Thread”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “RTOS Features”< / strong > → < strong > “Signal Configuration”< / strong > < / p >
< p > Check < strong > “Support SIGEV_THHREAD”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-config1.png" alt = "Enable POSIX Timers and Message Queues in menuconfig" / > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "appendix-random-number-generator-with-entropy-pool" class = "section-header" > < a href = "#appendix-random-number-generator-with-entropy-pool" > 21 Appendix: Random Number Generator with Entropy Pool< / a > < / h1 >
2022-01-01 09:47:11 +08:00
< p > Our LoRaWAN Library generates Nonces by calling a < strong > Random Number Generator with Entropy Pool< / strong > . < / p >
< p > Follow these steps to enable the < strong > Entropy Pool< / strong > in < strong > menuconfig< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “Crypto API”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Crypto API Support”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Entropy Pool and Strong Random Number Generator”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce3a.png" alt = "Enable Entropy Pool in menuconfig" / > < / p >
< p > Then we enable the < strong > Random Number Generator< / strong > …< / p >
< ol >
< li >
< p > Select < strong > “Device Drivers”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Enable /dev/urandom”< / strong > < / p >
< / li >
< li >
< p > Select < strong > “/dev/urandom algorithm”< / strong > < / p >
< / li >
< li >
< p > Check < strong > “Entropy Pool”< / strong > < / p >
< / li >
< li >
< p > Hit < strong > “Exit”< / strong > until the Top Menu appears. (“NuttX/x64_64 Configuration”)< / p >
< / li >
< / ol >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-nonce4a.png" alt = "Select Entropy Pool in menuconfig" / > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "appendix-build-flash-and-run-nuttx" class = "section-header" > < a href = "#appendix-build-flash-and-run-nuttx" > 22 Appendix: Build, Flash and Run NuttX< / a > < / h1 >
2021-12-31 19:09:25 +08:00
< p > < em > (For BL602 and ESP32)< / em > < / p >
< p > Below are the steps to build, flash and run NuttX on BL602 and ESP32.< / p >
< p > The instructions below will work on < strong > Linux (Ubuntu)< / strong > , < strong > WSL (Ubuntu)< / strong > and < strong > macOS< / strong > .< / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/quickstart/install.html" > (Instructions for other platforms)< / a > < / p >
< p > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (See this for Arch Linux)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h2 id = "build-nuttx" class = "section-header" > < a href = "#build-nuttx" > 22.1 Build NuttX< / a > < / h2 >
2021-12-31 19:09:25 +08:00
< p > Follow these steps to build NuttX for BL602 or ESP32…< / p >
< ol >
< li >
< p > Install the build prerequisites…< / p >
< p > < a href = "https://lupyuen.github.io/articles/nuttx#install-prerequisites" > < strong > “Install Prerequisites”< / strong > < / a > < / p >
< / li >
< li >
2022-01-01 10:27:28 +08:00
< p > Assume that we have downloaded the < strong > NuttX Source Code< / strong > and configured the < strong > LoRaWAN Settings< / strong > …< / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#download-source-code" > < strong > “Download Source Code”< / strong > < / a > < / p >
2022-01-01 10:27:28 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#device-eui-join-eui-and-app-key" > < strong > “Device EUI, Join EUI and App Key”< / strong > < / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#lorawan-frequency" > < strong > “LoRaWAN Frequency”< / strong > < / a > < / p >
2021-12-31 19:09:25 +08:00
< p > < a href = "https://lupyuen.github.io/articles/lorawan3#build-the-firmware" > < strong > “Build the Firmware”< / strong > < / a > < / p >
< / li >
< li >
< p > To build NuttX, enter this command…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > make< / code > < / pre > < / div > < / li >
< li >
< p > We should see…< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > LD: nuttx
CP: nuttx.hex
CP: nuttx.bin< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/8f725c278c25e209c1654469a2855746" > (See the complete log for BL602)< / a > < / p >
< / li >
< li >
< p > < strong > For BL602:< / strong > Copy the < strong > NuttX Firmware< / strong > to the < strong > blflash< / strong > directory…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > # For Linux and macOS:
# TODO: Change $HOME/blflash to the full path of blflash
cp nuttx.bin $HOME/blflash
# For WSL:
# TODO: Change /mnt/c/blflash to the full path of blflash in Windows
# /mnt/c/blflash refers to c:\blflash
cp nuttx.bin /mnt/c/blflash< / code > < / pre > < / div >
< p > (We’ ll cover < strong > blflash< / strong > in the next section)< / p >
< p > For WSL we need to run < strong > blflash< / strong > under plain old Windows CMD (not WSL) because it needs to access the COM port.< / p >
< / li >
< li >
< p > In case of problems, refer to the < strong > NuttX Docs< / strong > …< / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/platforms/risc-v/bl602/index.html" > < strong > “BL602 NuttX”< / strong > < / a > < / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/platforms/xtensa/esp32/index.html" > < strong > “ESP32 NuttX”< / strong > < / a > < / p >
< p > < a href = "https://nuttx.apache.org/docs/latest/quickstart/install.html" > < strong > “Installing NuttX”< / strong > < / a > < / p >
< / li >
< / ol >
< blockquote >
< p > < img src = "https://lupyuen.github.io/images/nuttx-build2.png" alt = "Building NuttX" / > < / p >
< / blockquote >
2022-01-02 09:32:47 +08:00
< h2 id = "flash-nuttx" class = "section-header" > < a href = "#flash-nuttx" > 22.2 Flash NuttX< / a > < / h2 >
2021-12-31 19:09:25 +08:00
< p > < strong > For ESP32:< / strong > < a href = "https://nuttx.apache.org/docs/latest/platforms/xtensa/esp32/index.html#flashing" > < strong > See instructions here< / strong > < / a > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (Also check out this article)< / a > < / p >
< p > < strong > For BL602:< / strong > Follow these steps to install < strong > blflash< / strong > …< / p >
< ol >
< li >
< p > < a href = "https://lupyuen.github.io/articles/flash#install-rustup" > < strong > “Install rustup”< / strong > < / a > < / p >
< / li >
< li >
< p > < a href = "https://lupyuen.github.io/articles/flash#download-and-build-blflash" > < strong > “Download and build blflash”< / strong > < / a > < / p >
< / li >
< / ol >
< p > We assume that our Firmware Binary File < strong > nuttx.bin< / strong > has been copied to the < strong > blflash< / strong > folder.< / p >
< p > Set BL602 / BL604 to < strong > Flashing Mode< / strong > and restart the board…< / p >
< p > < strong > For PineDio Stack BL604:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > GPIO 8 Jumper< / strong > to < strong > High< / strong > < a href = "https://lupyuen.github.io/images/pinedio-high.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For PineCone BL602:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > PineCone Jumper (IO 8)< / strong > to the < strong > < code > H< / code > Position< / strong > < a href = "https://lupyuen.github.io/images/pinecone-jumperh.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For BL10:< / strong > < / p >
< ol >
< li >
< p > Connect BL10 to the USB port< / p >
< / li >
< li >
< p > Press and hold the < strong > D8 Button (GPIO 8)< / strong > < / p >
< / li >
< li >
< p > Press and release the < strong > EN Button (Reset)< / strong > < / p >
< / li >
< li >
< p > Release the D8 Button< / p >
< / li >
< / ol >
< p > < strong > For Pinenut and MagicHome BL602:< / strong > < / p >
< ol >
< li >
< p > Disconnect the board from the USB Port< / p >
< / li >
< li >
< p > Connect < strong > GPIO 8< / strong > to < strong > 3.3V< / strong > < / p >
< / li >
< li >
< p > Reconnect the board to the USB port< / p >
< / li >
< / ol >
< p > Enter these commands to flash < strong > nuttx.bin< / strong > to BL602 / BL604 over UART…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > # TODO: Change ~/blflash to the full path of blflash
cd ~/blflash
# For Linux:
sudo cargo run flash nuttx.bin \
--port /dev/ttyUSB0
# For macOS:
cargo run flash nuttx.bin \
--port /dev/tty.usbserial-1420 \
--initial-baud-rate 230400 \
--baud-rate 230400
# For Windows: Change COM5 to the BL602 / BL604 Serial Port
cargo run flash nuttx.bin --port COM5< / code > < / pre > < / div >
< p > < a href = "https://gist.github.com/lupyuen/9c0dbd75bb6b8e810939a36ffb5c399f" > (See the Output Log)< / a > < / p >
< p > For WSL: Do this under plain old Windows CMD (not WSL) because < strong > blflash< / strong > needs to access the COM port.< / p >
< p > < a href = "https://github.com/apache/incubator-nuttx/issues/4336" > (Flashing WiFi apps to BL602 / BL604? Remember to use < strong > bl_rfbin< / strong > )< / a > < / p >
< p > < a href = "https://lupyuen.github.io/articles/flash#flash-the-firmware" > (More details on flashing firmware)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/nuttx-flash2.png" alt = "Flashing NuttX" / > < / p >
2022-01-02 09:32:47 +08:00
< h2 id = "run-nuttx" class = "section-header" > < a href = "#run-nuttx" > 22.3 Run NuttX< / a > < / h2 >
2021-12-31 19:09:25 +08:00
< p > < strong > For ESP32:< / strong > Use Picocom to connect to ESP32 over UART…< / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > picocom -b 115200 /dev/ttyUSB0< / code > < / pre > < / div >
< p > < a href = "https://popolon.org/gblog3/?p=1977&lang=en" > (More about this)< / a > < / p >
< p > < strong > For BL602:< / strong > Set BL602 / BL604 to < strong > Normal Mode< / strong > (Non-Flashing) and restart the board…< / p >
< p > < strong > For PineDio Stack BL604:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > GPIO 8 Jumper< / strong > to < strong > Low< / strong > < a href = "https://lupyuen.github.io/images/pinedio-low.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For PineCone BL602:< / strong > < / p >
< ol >
< li >
< p > Set the < strong > PineCone Jumper (IO 8)< / strong > to the < strong > < code > L< / code > Position< / strong > < a href = "https://lupyuen.github.io/images/pinecone-jumperl.jpg" > (Like this)< / a > < / p >
< / li >
< li >
< p > Press the Reset Button< / p >
< / li >
< / ol >
< p > < strong > For BL10:< / strong > < / p >
< ol >
< li > Press and release the < strong > EN Button (Reset)< / strong > < / li >
< / ol >
< p > < strong > For Pinenut and MagicHome BL602:< / strong > < / p >
< ol >
< li >
< p > Disconnect the board from the USB Port< / p >
< / li >
< li >
< p > Connect < strong > GPIO 8< / strong > to < strong > GND< / strong > < / p >
< / li >
< li >
< p > Reconnect the board to the USB port< / p >
< / li >
< / ol >
< p > After restarting, connect to BL602 / BL604’ s UART Port at 2 Mbps like so…< / p >
< p > < strong > For Linux:< / strong > < / p >
< div class = "example-wrap" > < pre class = "language-bash" > < code > sudo screen /dev/ttyUSB0 2000000< / code > < / pre > < / div >
< p > < strong > For macOS:< / strong > Use CoolTerm (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > < strong > For Windows:< / strong > Use < code > putty< / code > (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > < strong > Alternatively:< / strong > Use the Web Serial Terminal (< a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > See this< / a > )< / p >
< p > Press Enter to reveal the < strong > NuttX Shell< / strong > …< / p >
< div class = "example-wrap" > < pre class = "language-text" > < code > NuttShell (NSH) NuttX-10.2.0-RC0
nsh> < / code > < / pre > < / div >
< p > Congratulations NuttX is now running on BL602 / BL604!< / p >
< p > < a href = "https://lupyuen.github.io/articles/flash#watch-the-firmware-run" > (More details on connecting to BL602 / BL604)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/nuttx-boot2.png" alt = "Running NuttX" / > < / p >
< p > < strong > macOS Tip:< / strong > Here’ s the script I use to build, flash and run NuttX on macOS, all in a single step: < a href = "https://gist.github.com/lupyuen/cc21385ecc66b5c02d15affd776a64af" > run.sh< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/spi2-script.png" alt = "Script to build, flash and run NuttX on macOS" / > < / p >
< p > < a href = "https://gist.github.com/lupyuen/cc21385ecc66b5c02d15affd776a64af" > (Source)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "appendix-gpio-issue" class = "section-header" > < a href = "#appendix-gpio-issue" > 23 Appendix: GPIO Issue< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 14:32:20 +08:00
< p > Switching a #NuttX GPIO Interrupt Pin to Trigger On Rising Edge … Crashes with an Assertion Failure … I’ ll submit a NuttX Issue, meanwhile I have disabled the assertion< / p >
< p > TODO50< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-int.png" alt = "" / > < / p >
2021-12-30 16:35:12 +08:00
< p > < a href = "https://github.com/lupyuen/incubator-nuttx/blob/lorawan/drivers/ioexpander/gpio.c#L544-L547" > (Source)< / a > < / p >
2022-01-02 09:32:47 +08:00
< h1 id = "appendix-callout-issue" class = "section-header" > < a href = "#appendix-callout-issue" > 24 Appendix: Callout Issue< / a > < / h1 >
2021-12-30 16:53:54 +08:00
< p > TODO< / p >
2021-12-30 16:35:12 +08:00
< p > NimBLE Porting Layer doesn’ t work for multiple Callout Timers on #NuttX OS, unless we loop the thread … Will submit a Pull Request to Apache NimBLE 👍< / p >
< p > TODO42< / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-callout.png" alt = "" / > < / p >
< p > < a href = "https://github.com/lupyuen/nimble-porting-nuttx/blob/master/porting/npl/nuttx/src/os_callout.c#L35-L70" > (Source)< / a > < / p >
< p > < img src = "https://lupyuen.github.io/images/lorawan3-title2.jpg" alt = "PineDio Stack BL604 RISC-V Board (left) talking LoRaWAN to RAKwireless WisGate LoRaWAN Gateway (right)" / > < / p >
2021-12-30 10:58:30 +08:00
< / body >
< / html >