<p>Last article we got <strong>LoRa</strong> (the long-range, low-bandwidth wireless network) running on <ahref="https://lupyuen.github.io/articles/nuttx"><strong>Apache NuttX OS</strong></a>…</p>
<p>We shall test LoRaWAN on NuttX with Bouffalo Lab’s <ahref="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><imgsrc="https://lupyuen.github.io/images/sx1262-library5.jpg"alt="Porting LoRaWAN to NuttX OS"/></p>
<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>
<p>LoRaWAN works <strong>slightly differently across the world regions</strong>, to comply with Local Wireless Regulations: Radio Frequency, Maximum Airtime (Duty Cycle), <ahref="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>
<p>Look for these lines in <ahref="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>
<p>Next find this in the same file <ahref="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>
<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>
<p>Instead they store the App Key in the <ahref="https://encyclopedia.kaspersky.com/glossary/secure-element/"><strong>Secure Element</strong></a> hardware.</p>
<p>Our LoRaWAN Library supports two kinds of Secure Elements: <ahref="https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/atecc608a-tnglora-se"><strong>Microchip ATECC608A</strong></a> and <ahref="https://github.com/lupyuen/LoRaMac-node-nuttx/tree/master/src/peripherals/lr1110-se"><strong>Semtech LR1110</strong></a></p>
<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 <ahref="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>
<p>Do the same for the LoRaMAC Handler: <ahref="https://github.com/lupyuen/LoRaMac-node-nuttx/blob/master/src/apps/LoRaMac/common/LmHandler/LmHandler.c#L41-L47"><strong>LmHandler.c</strong></a></p>
<p>Check that the <strong>Semtech SX1262 Pins</strong> are configured correctly in <ahref="https://github.com/lupyuen/incubator-nuttx/blob/lorawan/boards/risc-v/bl602/bl602evb/include/board.h#L36-L95"><strong>board.h</strong></a> or <ahref="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>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>
<p>Enable <strong>POSIX Timers and Message Queues</strong> (for NimBLE Porting Layer)…</p>
<p><ahref="https://lupyuen.github.io/articles/lorawan3#appendix-posix-timers-and-message-queues"><strong>“POSIX Timers and Message Queues”</strong></a></p>
<p>Enable <strong>Random Number Generator with Entropy Pool</strong> (for LoRaWAN Nonces)…</p>
<p><ahref="https://lupyuen.github.io/articles/lorawan3#appendix-random-number-generator-with-entropy-pool"><strong>“Random Number Generator with Entropy Pool”</strong></a></p>
<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>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>
<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>
<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>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><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. <ahref="https://lupyuen.github.io/articles/sx1262#notes">(But we shall minimise the changes)</a></p>
<p>Stay Tuned!</p>
<p>Many Thanks to my <ahref="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><ahref="https://github.com/sponsors/lupyuen">Sponsor me a coffee</a></p>
</li>
<li>
<p><ahref="https://lupyuen.github.io/articles/book">Read “The RISC-V BL602 / BL604 Book”</a></p>
</li>
<li>
<p><ahref="https://lupyuen.github.io">Check out my articles</a></p>
<p>This article is the expanded version of <ahref="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 <ahref="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><ahref="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 <ahref="https://github.com/lupyuen/incubator-nuttx-apps/tree/master/wireless/bluetooth/nimble"><strong>NimBLE for NuttX</strong></a>.</p>
<p>(The <ahref="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 <ahref="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 <ahref="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><ahref="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><ahref="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>
<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>
<h1id="appendix-random-number-generator-with-entropy-pool"class="section-header"><ahref="#appendix-random-number-generator-with-entropy-pool">20 Appendix: Random Number Generator with Entropy Pool</a></h1>
<h1id="appendix-build-flash-and-run-nuttx"class="section-header"><ahref="#appendix-build-flash-and-run-nuttx">21 Appendix: Build, Flash and Run NuttX</a></h1>
<p><strong>For ESP32:</strong><ahref="https://nuttx.apache.org/docs/latest/platforms/xtensa/esp32/index.html#flashing"><strong>See instructions here</strong></a><ahref="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>
<p><ahref="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><ahref="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><ahref="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>
<divclass="example-wrap"><preclass="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><ahref="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><ahref="https://github.com/apache/incubator-nuttx/issues/4336">(Flashing WiFi apps to BL602 / BL604? Remember to use <strong>bl_rfbin</strong>)</a></p>
<p><ahref="https://lupyuen.github.io/articles/flash#flash-the-firmware">(More details on flashing firmware)</a></p>
<p><ahref="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><ahref="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><ahref="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 macOS:</strong> Use CoolTerm (<ahref="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
<p><strong>For Windows:</strong> Use <code>putty</code> (<ahref="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
<p><strong>Alternatively:</strong> Use the Web Serial Terminal (<ahref="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>
<p><strong>macOS Tip:</strong> Here’s the script I use to build, flash and run NuttX on macOS, all in a single step: <ahref="https://gist.github.com/lupyuen/cc21385ecc66b5c02d15affd776a64af">run.sh</a></p>
<p><imgsrc="https://lupyuen.github.io/images/spi2-script.png"alt="Script to build, flash and run NuttX on macOS"/></p>
<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>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>