LoRaWAN on PineDio Stack BL604 RISC-V Board

Tiny tasty treat… PineDio Stack BL604 RISC-V Board

Tiny tasty treat… PineDio Stack BL604 RISC-V Board

📝 16 Sep 2021

Previously I wrote about testing the prototype PineDio Stack BL604 RISC-V Board…

Today we dive into the most exciting component on PineDio Stack: Semtech SX1262 Transceiver for LoRa and LoRaWAN Networking.

Why LoRa?

LoRa is a Low-Power, Long-Range, Low-Bandwidth wireless network.

LoRa is perfect for IoT Sensor Devices that run on Battery Power. (Or Solar Power)

Since PineDio Stack comes with a Solar Panel, it will work really well for Agriculture Sensors.

(And many other IoT gadgets out there in the sun)

Will LoRa support all kinds of messages?

Not quite. LoRa only supports Short Messages of up to 242 Bytes.

And because LoRa is a Low Power (best effort) network, messages may get dropped.

Which is probably OK for sensor devices that send data periodically.

(But not for texting your friends)

(More about LoRa)

Is LoRa secure?

LoRa messages are delivered securely when we join a LoRaWAN Network.

Though our Security Keys would also need to be stored securely on PineDio Stack.

(We’ll learn how in a while)

Which Pine64 devices will talk LoRa and LoRaWAN?

Once the drivers are implemented, these Pine64 devices will talk LoRa and LoRaWAN to PineDio Stack…

PineDio Gateway, PinePhone Backplate and USB Adapter

This article describes the (pre-production) PineDio Stack Prototype thus…

⚠️ Obligatory Disclaimer: Features included in The Prototype are not complete, and will most certainly undergo changes before becoming available for public consumption. (Burp) They are described here for testing, exploration, education and entertainment purposes only. The Prototype shall NOT be used in production gadgets. (Like toasters, microwave ovens, and most definitely not, pressure cookers)

LoRa SX1262 Transceiver on PineDio Stack BL604

CAUTION: Always connect the Antenna before Powering On… Or the LoRa Transceiver may get damaged! See this

§1 LoRa SX1262 Transceiver

According to the PineDio Stack Schematic…

Our LoRa SX1262 Transceiver is wired onboard like so…

LoRa SX1262 Transceiver wired to PineDio Stack BL604

Note that the above SPI Pins are shared with the SPI Flash and ST7789 Display

GPIO NumberSPI Pin
17Common SDO (MOSI)
0Common SDI (MISO)
11Common SCK
14CS for SPI Flash
20CS for ST7789
15CS for SX1262

(More about SDO and SDI)

We set the Chip Select Pin (CS) to Low to select the Active SPI Device: Either LoRa SX1262, SPI Flash or ST7789 Display…

SPI Bus on PineDio Stack

To test the LoRa SX1262 Transceiver, we define the GPIO Pin Numbers like so: lora-sx1262/sx126x-board.h

//  Below are the pin numbers for PineDio Stack BL604 with onboard SX1262.
#define SX126X_SPI_IDX           0  //  SPI Port 0
#define SX126X_SPI_SDI_PIN       0  //  SPI Serial Data In Pin  (formerly MISO)
#define SX126X_SPI_SDO_PIN      17  //  SPI Serial Data Out Pin (formerly MOSI)
#define SX126X_SPI_CLK_PIN      11  //  SPI Clock Pin
#define SX126X_SPI_CS_PIN       15  //  SPI Chip Select Pin
#define SX126X_SPI_CS_OLD        8  //  Unused SPI Chip Select Pin
#define SX126X_NRESET           18  //  Reset Pin
#define SX126X_DIO1             19  //  DIO1
#define SX126X_BUSY_PIN         10  //  Busy Pin
#define SX126X_DEBUG_CS_PIN      5  //  Debug Chip Select Pin, mirrors the High / Low State of SX1262 Chip Select Pin. Set to -1 if not needed.
#define SX126X_TCXO_WAKEUP_TIME  5  //  Time required for the TCXO to wakeup (milliseconds)
#define SX126X_SPI_BAUDRATE  (200 * 1000)  //  SPI Frequency (200 kHz)

(SX126X_DEBUG_CS_PIN should be set to -1 if we’re not debugging. More about the Debug CS Pin later)

We define the Chip Select Pins for SPI Flash and ST7789 Display as well: pinedio_lorawan/demo.c

/// GPIO for SPI Flash Chip Select Pin. We must set this to High to deselect SPI Flash.
#define FLASH_CS_PIN     14

/// GPIO for ST7789 SPI Chip Select Pin. We must set this to High to deselect ST7789 Display.
#define DISPLAY_CS_PIN   20

§2 LoRaWAN Firmware

To test LoRaWAN on PineDio Stack we shall run this LoRaWAN Firmware

Which calls the following LoRaWAN and SX1262 Drivers

The firmware and drivers were previously ported from Apache Mynewt operating system to BL602 and BL604…

Here are the changes we made for PineDio Stack.

§2.1 Deselect SPI Peripherals

While testing LoRaWAN (and LoRa SX1262), we need to deselect all other SPI Peripherals (SPI Flash and ST7789 Display).

From pinedio_lorawan/demo.c

/// Set Chip Select pins to High, to deselect SX1262, SPI Flash and ST7789
int deselect_spi(void) {
  //  Configure Chip Select pins as GPIO Output Pins (instead of GPIO Input)
  int rc;
  rc = bl_gpio_enable_output(FLASH_CS_PIN,      0, 0);  assert(rc == 0);
  rc = bl_gpio_enable_output(DISPLAY_CS_PIN,    0, 0);  assert(rc == 0);
  rc = bl_gpio_enable_output(SX126X_SPI_CS_PIN, 0, 0);  assert(rc == 0);
  if (SX126X_DEBUG_CS_PIN >= 0) {  //  Mirror SX126X_SPI_CS_PIN
    rc = bl_gpio_enable_output(SX126X_DEBUG_CS_PIN, 0, 0);  assert(rc == 0);
  }

First we configure the Chip Select Pins for GPIO Output.

Then we set the Chip Select Pins to High, to deselect the SPI Peripherals…

  //  Set Chip Select pins to High, to deselect SX1262, SPI Flash and ST7789
  rc = bl_gpio_output_set(FLASH_CS_PIN,      1);  assert(rc == 0);
  rc = bl_gpio_output_set(DISPLAY_CS_PIN,    1);  assert(rc == 0);
  rc = bl_gpio_output_set(SX126X_SPI_CS_PIN, 1);  assert(rc == 0);
  if (SX126X_DEBUG_CS_PIN >= 0) {  //  Mirror SX126X_SPI_CS_PIN
    rc = bl_gpio_output_set(SX126X_DEBUG_CS_PIN, 1);  assert(rc == 0);
  }
  return 0;
}

(More about SX126X_DEBUG_CS_PIN when we talk about the Logic Analyser)

This function is called by the init_lorawan Command, which we’ll run in a while…

Deselect SPI Peripherals

(Source)

§2.2 Swap SPI Pins

Due to a quirk in the SPI implementation on BL602 and BL604, we need to swap the SPI Pins for SDI (formerly MISO) and SDO (formerly MOSI).

We do this by calling GLB_Swap_SPI_0_MOSI_With_MISO in lora-sx1262/sx126x-board.c

/// Initialise GPIO Pins and SPI Port. Called by SX126xIoIrqInit.
void SX126xIoInit( void ) {
  //  Configure the pins for GPIO Input / Output
  GpioInitOutput( SX126X_SPI_CS_PIN, 1 );
  GpioInitInput( SX126X_BUSY_PIN, 0, 0 );
  GpioInitInput( SX126X_DIO1, 0, 0 );
  if (SX126X_DEBUG_CS_PIN >= 0) { GpioInitOutput( SX126X_DEBUG_CS_PIN, 1 ); }

  //  Note: We must swap SDI (MISO) and SDO (MOSI)
  //  to comply with the SPI Pin Definitions in 
  //  BL602 / BL604 Reference Manual
  int rc = GLB_Swap_SPI_0_MOSI_With_MISO(ENABLE);  assert(rc == 0);

(More about swapping SPI Pins)

After swapping the SPI Pins we may initialise the SPI Port

  //  Configure the SPI Port
  rc = spi_init(
    &spi_device,     //  SPI Device
    SX126X_SPI_IDX,  //  SPI Port
    0,               //  SPI Mode: 0 for Controller
    //  TODO: Due to a quirk in BL602 SPI, we must set
    //  SPI Polarity-Phase to 1 (CPOL=0, CPHA=1).
    //  But actually Polarity-Phase for SX126X should be 0 (CPOL=0, CPHA=0). 
    1,                    //  SPI Polarity-Phase
    SX126X_SPI_BAUDRATE,  //  SPI Frequency
    2,                    //  Transmit DMA Channel
    3,                    //  Receive DMA Channel
    SX126X_SPI_CLK_PIN,   //  SPI Clock Pin 
    SX126X_SPI_CS_OLD,    //  Unused SPI Chip Select Pin
    SX126X_SPI_SDO_PIN,   //  SPI Serial Data Out Pin (formerly MOSI)
    SX126X_SPI_SDI_PIN    //  SPI Serial Data In Pin  (formerly MISO)
  );
  assert(rc == 0);
}

Note that the SPI Polarity-Phase should be 1 and not 0.

This seems to be another quirk of the SPI implementation on BL602 and BL604…

Swap SPI Pins and tweak the SPI Polarity-Phase

(Source)

§3 Run The Firmware

We build, flash and run the LoRaWAN Firmware for PineDio Stack with these steps…

  1. “Build LoRaWAN Firmware”

  2. “Flash LoRaWAN Firmware”

  3. “Run LoRaWAN Firmware”

Now we enter the LoRaWAN commands to…

  1. Join a LoRaWAN Network

    (Because we’ll transmit data securely over LoRa)

  2. Send a Data Packet to the network

    (So that the packet appears in our LoRaWAN Gateway)

We’ll talk to the ChirpStack LoRaWAN Gateway that we have installed here…

LoRaWAN Commands

(Source)

§3.1 LoRaWAN Commands

At the BL604 Command Prompt, enter these LoRaWAN Commands

  1. First we start the Background Task that will handle LoRa packets…

    create_task
  2. Next we initialise the LoRa SX1262 and LoRaWAN Drivers

    init_lorawan
  3. We set the Device EUI (Extended Unique Identifier)…

    las_wr_dev_eui 0x4b:0xc1:0x5e:0xe7:0x37:0x7b:0xb1:0x5b

    Change the above EUI to the one in our ChirpStack Gateway: Applications → app → Device EUI

  4. Set the App EUI

    las_wr_app_eui 0x00:0x00:0x00:0x00:0x00:0x00:0x00:0x00

    This is not needed for ChirpStack, thus we set to default 0000000000000000.

  5. Set the App Key

    las_wr_app_key 0xaa:0xff:0xad:0x5c:0x7e:0x87:0xf6:0x4d:0xe3:0xf0:0x87:0x32:0xfc:0x1d:0xd2:0x5d

    We get the App Key from ChirpStack at Applications → app → Devices → device_otaa_class_a → Keys (OTAA) → Application Key

  6. We send a request to join the LoRaWAN Network

    las_join 3

    (Retry up to 3 times)

  7. After the ChirpStack LoRaWAN Gateway has accepted our Join Request, we open a LoRaWAN Application Port

    las_app_port open 2

    (2 is the Application Port Number)

  8. Finally we send a LoRaWAN Data Packet containing 5 bytes of data (0x00) to LoRaWAN Port 2…

    las_app_tx 2 5 0

    (0 means that this is an Unconfirmed Message, we’re not expecting an acknowledgement from the LoRaWAN Gateway)

We should see this in our PineDio Stack serial terminal…

Let’s check our ChirpStack LoRaWAN Gateway!

(More about the LoRaWAN Commands)

LoRaWAN Firmware

§4 LoRaWAN Gateway

To see the Join Network Request and the Data Packet received by our ChirpStack LoRaWAN Gateway, we do this…

  1. In ChirpStack, click Applications → app → device_otaa_class_a → LoRaWAN Frames

  2. Restart PineDio Stack.

    Run the LoRaWAN Commands from the previous section.

  3. The Join Network Request appears in ChirpStack, followed by the Data Packet

    Join Network Request and Data Packet in ChirpStack

  4. Click the Device Data tab in ChirpStack.

  5. On PineDio Stack, run this command to send a Data Packet…

    las_app_tx 2 5 0
  6. Our Data Packet appears in ChirpStack.

    DecodedDataHex shows 5 bytes of zero, which is what we sent…

    Data Packet in ChirpStack

LoRaWAN tested OK on PineDio Stack!

Let’s take a peek inside our LoRa SX1262 Transceiver…

PineDio Stack with Logic Analyser

§5 Logic Analyser

How did we find out that the SPI Pins need to be swapped?

And the tweaking for SPI Polarity-Phase?

A Logic Analyser is super helpful for troubleshooting SPI and other interfacing problems on prototype hardware. (Pic above)

PineDio Stack’s GPIO Connector exposes the SPI Pins: SDO (formerly MOSI), SDI (formerly MISO) and SCK…

PineDio Stack GPIO Connector

We connect our Logic Analyser to the GPIO Connector like so…

GPIO NumberSPI PinConnector Pin
17Common SDO (MOSI)7
0Common SDI (MISO)17
11Common SCK4
5Debug CS2

Logic Analyser connected to PineDio Stack

What about the SX1262 Chip Select Pin: GPIO 15?

Unfortunately GPIO 15 is not exposed on the GPIO Connector.

Hence we designate GPIO 5 as the Debug CS Pin that mirrors the GPIO High / Low state of GPIO 15. (Here’s how)

Then we simply connect our Logic Analyser to GPIO 5 as the Chip Select Pin. (Pic above)

Our Logic Analyser shows that BL604 is indeed talking correctly to SX1262 over SPI…

LoRa SX1262 with Logic Analyser

§6 Spectrum Analyser

We’ve used a Logic Analyser to sniff the data inside our LoRa Transceiver. Now we use a Spectrum Analyser to sniff the data in the airwaves!

Our Spectrum Analyser is the Airspy R2 Software Defined Radio, which will sniff a range of radio frequences…

Airspy R2 SDR with PineDio Stack

When we analyse the radio spectrum (with Cubic SDR), we see this healthy radio signal produced by our LoRa Transceiver…

LoRa SX1262 visualised with SDR

This is known as a LoRa Chirp.

LoRa Packets have this unique shape so that the packets can be transmitted over long distances in spite of radio interference.

(Up to 5 kilometres in some urban areas!)

More about LoRa and Software Defined Radio here…

(The “fireflies” look odd though. Are we transmitting with too much power?)

§7 Security

Since LoRa packets can be sniffed over the airwaves…

How do we transmit data securely over LoRa?

That’s why we join a LoRaWAN Network when we transmit data.

LoRaWAN is a layer on top of LoRa that adds security features like…

More about LoRaWAN Security here…

What’s the catch?

Well the LoRaWAN Security Keys would need to be stored and accessed securely on PineDio Stack.

We should never allow the Security Keys to be exposed.

Doesn’t BL604 securely store Security Keys in its Internal EFuse Storage?

Yes. Though there have been past incidents (on other microcontrollers) where Security Keys in EFuse Storage have been compromised. (See this)

§7.1 Cryptographic Co-Processor

Is there a better way to store and access Security Keys?

We could use a Cryptographic Co-Processor like this…

ATECC608A works with The Things Network, the public worldwide LoRaWAN Network…

It also works with Helium, another global LoRaWAN Network…

There are new dev boards with ATECC608 onboard…

This article explains how a microcontroller might connect to a secure network (like LoRaWAN) with ATECC608A…

What’s the catch?

We need to be extra careful when working with Cryptographic Co-Processors…

Once the Security Keys have been injected, they can never be reset!

(Same for EFuse Storage)

§7.2 LoRaWAN Alternatives

Can we send LoRa messages securely… Without LoRaWAN?

Traditional Peer-to-Peer Messaging Protocols (like XMPP and Matrix) won’t run on PineDio Stack with LoRa.

(Because of LoRa’s tiny lossy packets. And JSON over HTTPS is too heavy for BL604)

These newer Peer-to-Peer Messaging Protocols will probably work with PineDio Stack…

There is an experimental Matrix protocol for IoT devices…

Maybe we’ll see messaging protocols based on Blockchain…

But how secure are they?

Calm down, amigo… Sorry I haven’t reviewed their security features.

Someday I might!

PineDio Stack supports triple comms: LoRa, WiFi AND Bluetooth LE…

What can we do with them?

Maybe we can turn PineDio Stack into a (very basic) Solar-Powered Gateway for LoRa + WiFi + Bluetooth LE?

That will relay LoRa and Bluetooth LE messages to the internet over WiFi?

Like for tracking our pets? (Excluding hamsters and goldfish)

Or for connecting our PineTime watches to the internet?

Perhaps super-accurate geolocation with LoRa + WiFi + Bluetooth LE?

Got any ideas? Lemme know!

§8 Seeking Volunteers!

I’m really excited that PineDio Stack BL604 will be available soon!

But in the meantime, JF and I have plenty to test on PineDio Stack

  1. ST7789 Display (SPI)
  2. LoRa SX1262 (SPI)
  3. SPI Flash (SPI)
  4. Accelerometer (I2C)
  5. Heart Rate Sensor (I2C)
  6. Touch Panel (I2C)
  7. Vibrator (GPIO)
  8. Push Button (GPIO)
  9. WiFi
  10. Bluetooth LE
  11. JTAG Debugging
  12. Battery Charging
  13. Solar Power

Please let us know if you’re keen to help! 🙏

Our new LoRaWAN Gateway for The Things Network

(Source)

§9 What’s Next

In the next article, PineDio Stack shall transmit data to the cloud via the public global LoRaWAN Network… The Things Network!

(Sorry for griping… But why doesn’t Singapore have decent coverage for The Things Network? 🙄)

Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…

lupyuen.github.io/src/lorawan2.md

§10 Notes

  1. This article is the expanded version of this Twitter Thread

  2. Here’s a great way run a PineDio Stack BL604 Regression Test with GPIO, ADC, SPI, SX1262, LoRa, LoRaWAN and The Things Network

    “Run Payload Formatter”

    This is how we tested the upstream updates from Pine64’s BL602 IoT SDK before merging them. (See this)

  3. However Bouffalo Lab’s BL602 IoT SDK has just been revamped with the new “hosal” HAL.

    (See this Twitter Thread)

    We have no plans yet to merge with the new HAL, because it will impact all the articles and code that we have written for “The RISC-V BL602 / BL604 Book”.

    How shall we proceed? Lemme know what you think! 🙏