📝 7 Mar 2021
Suppose we have a garden in our home. (Or rooftop)
Is there an affordable way to monitor our garden with Environmental Sensors (and Soil Sensors)…
That doesn’t require WiFi… (Think rooftop)
And consumes very little power? (Think batteries)
Here’s a solution: PineCone BL602 RISC-V Board with a LoRa Transceiver!
Today we shall transmit some LoRa packets by connecting PineCone BL602 to a LoRa Transceiver: Semtech SX1276 or Hope RF96
UPDATE: We have a new LoRa Driver for SX1262 (Pine64 RFM90 LoRa Module)… Check this out
The LoRa Firmware in this article will run on PineCone, Pinenut and Any BL602 Board.
PineCone BL602 RISC-V Board connected to Hope RF96 LoRa Transceiver
Connect BL602 to SX1276 or RF96 as follows…
BL602 Pin | SX1276 / RF96 Pin | Wire Colour |
---|---|---|
GPIO 1 | ISO (MISO) | Green |
GPIO 2 | Do Not Connect | |
GPIO 3 | SCK | Yellow |
GPIO 4 | OSI (MOSI) | Blue |
GPIO 14 | NSS | Orange |
GPIO 17 | RST | White |
3V3 | 3.3V | Red |
GND | GND | Black |
Here’s a closer look at the pins connected on BL602…
Why is BL602 Pin 2 unused?
GPIO 2
is the Unused SPI Chip Select on BL602.
We won’t use this pin because we’ll control Chip Select ourselves on GPIO 14
. (See this)
Here are the pins connected on our LoRa Transceiver: SX1276 or RF96…
(ISO
and OSI
appear flipped in this pic… Rotate your phone / computer screen 180 degrees for the proper perspective)
Why are so many pins on SX1276 (or RF96) unused?
Unlike WiFi, LoRa networks can be really simple. Today we shall configure our LoRa Transceiver for the simplest “Fire And Forget” Mode…
Blast out a packet of 64 bytes over the airwaves
Don’t verify whether our packet has been received
Don’t receive any packets
This is ideal for simple sensors (like our garden sensors) that are powered by batteries and can tolerate a few lost packets. (Because we’ll send the sensor data periodically anyway)
So this means we won’t use all the pins on SX1276 (or RF96)?
Yep we may leave pins D0
to D5
disconnected. (Otherwise we’ll run out of pins on BL602!)
The LoRa Transceiver should support the right LoRa Frequency for your region: 434, 780, 868, 915 or 923 MHz…
To find a LoRa Transceiver for your region, go to the Tindie Maker Marketplace and search for SX1276 or RF96. Look for a transceiver that matches your frequency.
The length of the antenna depends on the frequency. They are standard parts and should be easy to find.
I bought the Hope RF96 Breakout Board (923 MHz) and Antenna (923 MHz) from M2M Shop on Tindie. (See this)
What if my region allows multiple LoRa Frequencies?
Choose the LoRa Frequency that’s most popular in your region for The Things Network. (That’s the free, public LoRaWAN network)
Because one day we will probably connect our LoRa Transceiver to The Things Network for collecting sensor data.
Here are the base stations worldwide for The Things Network
Let’s look at the code inside our LoRa Firmware for BL602: sdk_app_lora
Super Important: We should set the LoRa Frequency in demo.c
like so…
/// TODO: We are using LoRa Frequency 923 MHz
/// for Singapore. Change this for your region.
#define USE_BAND_923
In a while we shall change 923
to the LoRa Frequency for our region: 434
, 780
, 868
, 915
or 923
MHz. (Check this list)
For now we’ll study this function init_driver
that initialises the LoRa Driver for SX1276 (and RF96) in demo.c
/// Command to initialise the SX1276 / RF96 driver
static void init_driver(char *buf, int len, int argc, char **argv) {
// Set the LoRa Callback Functions
RadioEvents_t radio_events;
memset(&radio_events, 0, sizeof(radio_events)); // Must init radio_events to null, because radio_events lives on stack!
radio_events.TxDone = on_tx_done;
radio_events.RxDone = on_rx_done;
radio_events.TxTimeout = on_tx_timeout;
radio_events.RxTimeout = on_rx_timeout;
radio_events.RxError = on_rx_error;
init_driver
begins by defining the Callback Functions that will be called when we have transmitted or received a LoRa Packet (successfully or unsuccessfully).
But we’re doing LoRa “Fire And Forget” Mode… We’re not checking for errors and we’re not receiving LoRa Packets, remember?
Yep so these Callback Functions are not used today. They will be used in future when we receive LoRa Packets and check for errors.
Next we call Radio.Init
to initialise BL602’s SPI Port and the LoRa Transceiver…
// Init the SPI Port and the LoRa Transceiver
Radio.Init(&radio_events);
Radio.Init
will set some registers on our LoRa Transceiver (over SPI).
Then we call Radio.SetChannel
to set the LoRa Frequency…
// Set the LoRa Frequency, which is specific to our region.
// For USE_BAND_923: RF_FREQUENCY is set to 923000000.
Radio.SetChannel(RF_FREQUENCY);
Radio.SetChannel
configures the LoRa Frequency by writing to the Frequency Registers in our LoRa Transceiver.
We get ready to transmit by calling Radio.SetTxConfig
…
// Configure the LoRa Transceiver for transmitting messages
Radio.SetTxConfig(
MODEM_LORA,
LORAPING_TX_OUTPUT_POWER,
0, // Frequency deviation: Unused with LoRa
LORAPING_BANDWIDTH,
LORAPING_SPREADING_FACTOR,
LORAPING_CODINGRATE,
LORAPING_PREAMBLE_LENGTH,
LORAPING_FIX_LENGTH_PAYLOAD_ON,
true, // CRC enabled
0, // Frequency hopping disabled
0, // Hop period: N/A
LORAPING_IQ_INVERSION_ON,
LORAPING_TX_TIMEOUT_MS
);
These LoRa Parameters should match the settings in the LoRa Receiver. For details, check the Appendix.
At the end of the function we call Radio.SetRxConfig
to get ready for receiving LoRa Packets…
// Configure the LoRa Transceiver for receiving messages
Radio.SetRxConfig(
MODEM_LORA,
LORAPING_BANDWIDTH,
LORAPING_SPREADING_FACTOR,
LORAPING_CODINGRATE,
0, // AFC bandwidth: Unused with LoRa
LORAPING_PREAMBLE_LENGTH,
LORAPING_SYMBOL_TIMEOUT,
LORAPING_FIX_LENGTH_PAYLOAD_ON,
0, // Fixed payload length: N/A
true, // CRC enabled
0, // Frequency hopping disabled
0, // Hop period: N/A
LORAPING_IQ_INVERSION_ON,
true // Continuous receive mode
);
}
Since we’re not receiving LoRa Packets, this code won’t be used.
(The code in this article is based on the LoRa Ping program from Mynewt OS. More about this in the Appendix.)
Now that we have initialised our LoRa Transceiver, let’s send a LoRa Packet!
We’ll send a PING
message like so: demo.c
/// Command to send a LoRa message. Assume that
/// SX1276 / RF96 driver has been initialised.
static void send_message(char *buf, int len, int argc, char **argv) {
// Send the "PING" message
send_once(1);
}
send_message
calls send_once
to send the PING
message.
send_once
is defined here…
/// We send a "PING" message
const uint8_t loraping_ping_msg[] = "PING";
/// We expect a "PONG" response (in future)
const uint8_t loraping_pong_msg[] = "PONG";
/// 64-byte buffer for our LoRa message
static uint8_t loraping_buffer[LORAPING_BUFFER_SIZE];
/// Send a LoRa message. If is_ping is 0,
/// send "PONG". Otherwise send "PING".
static void send_once(int is_ping) {
// Copy the "PING" or "PONG" message to the transmit buffer
if (is_ping) {
memcpy(loraping_buffer, loraping_ping_msg, 4);
} else {
memcpy(loraping_buffer, loraping_pong_msg, 4);
}
Here we copy PING
into our 64-byte Transmit Buffer.
We fill up the remaining space in the Transmit Buffer with the values 0
, 1
, 2
, …
// Fill up the remaining space in the transmit
// buffer (64 bytes) with values 0, 1, 2, ...
for (int i = 4; i < sizeof loraping_buffer; i++) {
loraping_buffer[i] = i - 4;
}
Then we call Radio.Send
to transmit the 64-byte buffer as a LoRa Packet…
// Send the transmit buffer (64 bytes)
Radio.Send(
loraping_buffer, // Transmit buffer
sizeof loraping_buffer // Buffer size: 64 bytes
);
}
Did we forget to specify the receipient for the LoRa message…?
That’s the simplicity of the LoRa “Fire And Forget” Mode… It broadcasts our message over the airwaves!
We shouldn’t broadcast sensitive messages in the clear. But we’ll allow it for our simple garden sensors. (LoRaWAN supports encrypted messages, as we’ll learn in a while)
(The Radio
functions belong to the LoRa SX1276 Driver that was ported from Mynewt OS to BL602. More about this in the Appendix)
Let’s run the LoRa Demo Firmware for BL602.
Find out which LoRa Frequency we should use for your region…
Download the Firmware Binary File sdk_app_lora.bin
for your LoRa Frequency…
Alternatively, we may build the Firmware Binary File sdk_app_lora.bin
from the source code…
## Download the lora branch of lupyuen's bl_iot_sdk
git clone --recursive --branch lora https://github.com/lupyuen/bl_iot_sdk
cd bl_iot_sdk/customer_app/sdk_app_lora
## TODO: Set the LoRa Frequency in sdk_app_lora/demo.c.
## Edit the file and look for the line...
## #define USE_BAND_923
## Change 923 to the LoRa Frequency for your region:
## 434, 780, 868, 915 or 923 MHz
## See https://www.thethingsnetwork.org/docs/lorawan/frequencies-by-country.html
## TODO: Change this to the full path of bl_iot_sdk
export BL60X_SDK_PATH=$HOME/bl_iot_sdk
export CONFIG_CHIP_NAME=BL602
make
## For WSL: Copy the firmware to /mnt/c/blflash, which refers to c:\blflash in Windows
mkdir /mnt/c/blflash
cp build_out/sdk_app_lora.bin /mnt/c/blflash
More details on building bl_iot_sdk
(Remember to use the lora
branch, not the default master
branch)
Follow these steps to install blflash
…
We assume that our Firmware Binary File sdk_app_lora.bin
has been copied to the blflash
folder.
Set BL602 to Flashing Mode and restart the board…
For PineCone:
Set the PineCone Jumper (IO 8) to the H
Position (Like this)
Press the Reset Button
For BL10:
Connect BL10 to the USB port
Press and hold the D8 Button (GPIO 8)
Press and release the EN Button (Reset)
Release the D8 Button
For Ai-Thinker Ai-WB2, Pinenut and MagicHome BL602:
Disconnect the board from the USB Port
Connect GPIO 8 to 3.3V
Reconnect the board to the USB port
Enter these commands to flash sdk_app_lora.bin
to BL602 over UART…
## For Linux:
blflash flash build_out/sdk_app_lora.bin \
--port /dev/ttyUSB0
## For macOS:
blflash flash build_out/sdk_app_lora.bin \
--port /dev/tty.usbserial-1420 \
--initial-baud-rate 230400 \
--baud-rate 230400
## For Windows: Change COM5 to the BL602 Serial Port
blflash flash c:\blflash\sdk_app_lora.bin --port COM5
(For WSL: Do this under plain old Windows CMD, not WSL, because blflash needs to access the COM port)
More details on flashing firmware
Set BL602 to Normal Mode (Non-Flashing) and restart the board…
For PineCone:
Set the PineCone Jumper (IO 8) to the L
Position (Like this)
Press the Reset Button
For BL10:
For Ai-Thinker Ai-WB2, Pinenut and MagicHome BL602:
Disconnect the board from the USB Port
Connect GPIO 8 to GND
Reconnect the board to the USB port
After restarting, connect to BL602’s UART Port at 2 Mbps like so…
For Linux:
screen /dev/ttyUSB0 2000000
For macOS: Use CoolTerm (See this)
For Windows: Use putty
(See this)
Alternatively: Use the Web Serial Terminal (See this)
More details on connecting to BL602
Let’s enter some commands to transmit a LoRa Packet!
Press Enter to reveal the command prompt.
Enter help
to see the available commands…
help
====User Commands====
read_registers : Read registers
send_message : Send LoRa message
spi_result : Show SPI counters
First we initialise our LoRa Transceiver.
Enter this command…
init_driver
This command calls the function init_driver
, which we have seen earlier.
We should see this…
init_driver
port0 eventloop init = 42010760
[HAL] [SPI] Init :
port=0, mode=0, polar_phase = 1, freq=200000, tx_dma_ch=2, rx_dma_ch=3, pin_clk=3, pin_cs=2, pin_mosi=1, pin_miso=4
set rwspeed = 200000
hal_gpio_init: cs:2, clk:3, mosi:1, miso: 4
hal_gpio_init: SPI controller mode
hal_spi_init.
The above messages say that our SPI Port has been configured by the BL602 SPI HAL.
hal_spi_transfer = 1
transfer xfer[0].len = 1
Tx DMA src=0x4200cc58, dest=0x4000a288, size=1, si=1, di=0, i=1
Rx DMA src=0x4000a28c, dest=0x4200cc54, size=1, si=0, di=1, i=1
recv all event group.
...
init_driver
has just configured our SPI Transceiver by setting the registers over SPI.
Next we transmit a LoRa Packet…
send_message
This command calls the function send_message
, which we have seen earlier.
We should see this…
send_message
hal_spi_transfer = 1
transfer xfer[0].len = 1
Tx DMA src=0x4200cc58, dest=0x4000a288, size=1, si=1, di=0, i=1
Rx DMA src=0x4000a28c, dest=0x4200cc54, size=1, si=0, di=1, i=1
recv all event group.
...
That’s send_message
blasting the 64-byte LoRa Packet to the airwave, in the simple “Fire And Forget” Mode.
(The LoRa Driver copies the 64-byte Transmit Buffer to our LoRa Transceiver over SPI, byte by byte. Hence the numerous SPI requests.)
If we wish to transmit LoRa Packets automatically on startup (without entering any commands), check out the LoRa Ping Firmware…
How will we know whether BL602 is connected correctly to the LoRa Transceiver?
Enter this command to read the first 16 registers from our LoRa Transceiver over SPI…
read_registers
We should see…
...
Register 0x02 = 0x1a
Register 0x03 = 0x0b
Register 0x04 = 0x00
Register 0x05 = 0x52
...
Take the values of Registers 2, 3, 4 and 5.
Compare them with the Register Table in the SX1276 (or RF96) Datasheet.
The values should be identical: 0x1a
, 0x0b
, 0x00
, 0x52
Can we find out the frequency that’s used by our LoRa Transceiver?
Enter these commands…
init_driver
read_registers
Look for the values of Registers 6, 7 and 8…
Register 0x06 = 0x6c
Register 0x07 = 0x80
Register 0x08 = 0x00
Put the values together and multiply by the Frequency Step…
0x6c8000 * 61.03515625
This produces 434,000,000… Which means that our LoRa Transceiver is transmitting at 434 MHz.
What about the ACTUAL frequency that our LoRa Transceiver is transmitting on?
Use a Spectrum Analyser like RF Explorer.
In the next section we’ll use a more advanced tool for spectrum analysis: Software Defined Radio.
RF Explorer (at right) featured in WandaVision season 1 episode 4
See the source code for read_registers
See the output from read_registers
What’s this? A glowing helix? Magic seahorse?
That’s how our 64-byte LoRa Packet appears when captured with a Software Defined Radio!
LoRa Packets look like a column of diagonal strokes. Here’s a clearer example…
This is called a LoRa Chirp… A clever way to transmit packets over great distances (with little power) by shifting the pitch (frequency) up or down during transmission…
(Yep it’s inspired by chirping birds)
Why is this important for LoRa?
LoRa operates on the Radio Frequency band known as the ISM Band (for Industrial, Scientific and Medical purpose).
The ISM Band is used by many types of wireless gadgets. (It’s like 2.4 GHz WiFi, but at a lower frequency: 434, 868, 915 or 923 MHz) And it’s prone to noise and interference caused by other gadgets.
By transmitting packets in this unique chirping pattern, LoRa ensures that packets will be delivered over long distances in spite of the noise and interference.
(LoRa doesn’t guarantee 100% reliable delivery, of course)
Airspy R2 SDR
Let’s capture and visualise our LoRa Packet with Airspy R2 SDR (Software Defined Radio)…
Place the Airspy R2 SDR close to our LoRa Antenna (See pic above)
Download and install CubicSDR
Launch CubicSDR. Set the Airspy SDR Sample Rate to 10 MHz
Set the Center Frequency to our LoRa Frequency
Click and drag the Speed Bar (at right) to the maximum speed
Run the LoRa Firmware for BL602 and enter the commands…
init_driver
send_message
Our LoRa Packet should scroll down like so…
CubicSDR software with Airspy R2 SDR
If there is a lot of background noise, cover the LoRa Transceiver and Airspy SDR with a Metal Pot (as an improvised Faraday Cage)…
Improvised Faraday Cage
What’s the difference between LoRa, LoRaWAN and The Things Network?
LoRa = The wireless network protocol
WiFi is also a wireless network protocol.
LoRaWAN = A managed, secure LoRa network
It’s like going to Starbucks and connecting to their WiFi.
The Things Network = The free LoRaWAN network that’s operated by volunteers around the world.
People actually set up base stations and allow free access.
Our garden sensors could connect to The Things Network… So that we may browse the sensor data conveniently.
(More about The Things Network)
(There are commercial LoRaWAN networks, like Helium and potentially Amazon Sidewalk)
3 Levels of LoRa! Where are we right now?
Our BL602 implementation of LoRa is at Level 1. Well actually, half of Level 1. (Since we only transmit packets)
To complete Level 1 of our Wireless IoT Endeavour, we need to receive LoRa Packets.
In the next two articles, we shall use RAKwireless WisBlock as a LoRa Node for receiving the LoRa Packets from BL602 (and the other way around).
Read the followup articles here…
“RAKwireless WisBlock talks LoRa with PineCone BL602 RISC-V Board”
“Build a LoRaWAN Network with RAKwireless WisGate Developer Gateway”
(Many thanks to RAKwireless for providing the WisBlock Connected Box!)
RAKwireless WisBlock Connected Box
We have come a loooong way since I first experimented with LoRa in 2016…
Cheaper Transceivers: Shipped overnight from Thailand!
Mature Networks: LoRaWAN, The Things Network
Better Drivers: Thanks to Apache Mynewt OS!
Powerful Microcontrollers: Arduino Uno vs RISC-V BL602
Awesome Tools: RAKwireless WisBlock, Airspy SDR, RF Explorer
Now is the right time to build LoRa gadgets. Stay tuned for more LoRa Adventures!
Meanwhile there’s plenty more code in the BL602 IoT SDK to be deciphered and documented: ADC, DAC, WiFi, Bluetooth LE, …
Come Join Us… Make BL602 Better!
🙏 👍 😀
Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…
This article is the expanded version of this Twitter Thread
How much power would our BL602 + LoRa sensor actually consume? How long would our battery-powered sensor last?
We would need to do a thorough Power Profiling. (See this)
Excellent project for schools and universities!
LoRa is a proprietary protocol, but it has been reverse engineered.
There is an open-source implementation of LoRa with SDR. (See this)
What’s the Maximum LoRa Packet Size?
A LoRa Packet can have up to 222 bytes of data. (See this)
So LoRa is good for sending sensor data (like our garden sensors) and short messages… But not graphical images.
Thanks to Pine64 for featuring this article on their podcast!
We configure the LoRa Frequency here: demo.c
/// TODO: We are using LoRa Frequency 923 MHz for Singapore. Change this for your region.
#define USE_BAND_923
#if defined(USE_BAND_433)
#define RF_FREQUENCY 434000000 /* Hz */
#elif defined(USE_BAND_780)
#define RF_FREQUENCY 780000000 /* Hz */
#elif defined(USE_BAND_868)
#define RF_FREQUENCY 868000000 /* Hz */
#elif defined(USE_BAND_915)
#define RF_FREQUENCY 915000000 /* Hz */
#elif defined(USE_BAND_923)
#define RF_FREQUENCY 923000000 /* Hz */
#else
#error "Please define a frequency band in the compiler options."
#endif
Here are the LoRa Parameters: demo.c
/// LoRa Parameters
#define LORAPING_TX_OUTPUT_POWER 14 /* dBm */
#define LORAPING_BANDWIDTH 0 /* [0: 125 kHz, */
/* 1: 250 kHz, */
/* 2: 500 kHz, */
/* 3: Reserved] */
#define LORAPING_SPREADING_FACTOR 7 /* [SF7..SF12] */
#define LORAPING_CODINGRATE 1 /* [1: 4/5, */
/* 2: 4/6, */
/* 3: 4/7, */
/* 4: 4/8] */
#define LORAPING_PREAMBLE_LENGTH 8 /* Same for Tx and Rx */
#define LORAPING_SYMBOL_TIMEOUT 5 /* Symbols */
#define LORAPING_FIX_LENGTH_PAYLOAD_ON false
#define LORAPING_IQ_INVERSION_ON false
#define LORAPING_TX_TIMEOUT_MS 3000 /* ms */
#define LORAPING_RX_TIMEOUT_MS 1000 /* ms */
#define LORAPING_BUFFER_SIZE 64 /* LoRa message size */
Below are the LoRa Transceiver Settings for SX1276 and RF96: sx1276.h
#define SX1276_SPI_IDX 0 // SPI Port 0
#define SX1276_SPI_SDI_PIN 1 // SPI Serial Data In Pin (formerly MISO)
#define SX1276_SPI_SDO_PIN 4 // SPI Serial Data Out Pin (formerly MOSI)
#define SX1276_SPI_CLK_PIN 3 // SPI Clock Pin
#define SX1276_SPI_CS_PIN 14 // SPI Chip Select Pin
#define SX1276_SPI_CS_OLD 2 // Unused SPI Chip Select Pin
#define SX1276_NRESET 17 // Reset Pin
#define SX1276_DIO0 12 // DIO0 Pin
#define SX1276_DIO1 11 // DIO1 Pin
#define SX1276_DIO2 5 // DIO2 Pin
#define SX1276_DIO3 8 // DIO3 Pin
#define SX1276_DIO4 0 // TODO: DIO4 Pin
#define SX1276_DIO5 0 // TODO: DIO5 Pin
#define SX1276_SPI_BAUDRATE (200 * 1000) // SPI Frequency (200 kHz)
#define SX1276_LF_USE_PA_BOOST 1 // Enable Power Amplifier Boost for LoRa Frequency below 525 MHz
#define SX1276_HF_USE_PA_BOOST 1 // Enable Power Amplifier Boost for LoRa Frequency 525 MHz and above
In this article, we called some Radio
Functions that belong to the LoRa SX1276 Driver.
Here’s where the Radio
Functions are defined…
Radio.Init
calls SX1276Init
Radio.SetChannel
calls SX1276SetChannel
Radio.SetTxConfig
calls SX1276SetTxConfig
Radio.SetRxConfig
calls SX1276SetRxConfig
Radio.Send
calls SX1276Send
The LoRa SX1276 Driver was ported from Mynewt OS to BL602 IoT SDK…
Here’s how we ported the SX1276 driver code from Mynewt to BL602.
In Mynewt we call hal_gpio_init_out
to configure a GPIO Output Pin and set the output to High: sx1276-board.c
// Configure Chip Select pin as a GPIO Output Pin and set to High
int rc = hal_gpio_init_out(
RADIO_NSS, // Pin number
1 // Set to High
);
assert(rc == 0);
Here’s the equivalent code in BL602: sx1276-board.c
// Configure Chip Select pin as a GPIO Pin
GLB_GPIO_Type pins[1];
pins[0] = RADIO_NSS; // Pin number
BL_Err_Type rc2 = GLB_GPIO_Func_Init(
GPIO_FUN_SWGPIO, // Configure as GPIO
pins, // Pins to be configured
sizeof(pins) / sizeof(pins[0]) // Number of pins (1)
);
assert(rc2 == SUCCESS);
// Configure Chip Select pin as a GPIO Output Pin (instead of GPIO Input)
int rc = bl_gpio_enable_output(RADIO_NSS, 0, 0);
assert(rc == 0);
// Set Chip Select pin to High, to deactivate SX1276
rc = bl_gpio_output_set(RADIO_NSS, 1);
assert(rc == 0);
In Mynewt we configure the SPI Port like so: sx1276-board.c
// Disable the SPI port
hal_spi_disable(RADIO_SPI_IDX);
// Configure the SPI port
spi_settings.data_order = HAL_SPI_MSB_FIRST;
spi_settings.data_mode = HAL_SPI_MODE0;
spi_settings.baudrate = MYNEWT_VAL(SX1276_SPI_BAUDRATE);
spi_settings.word_size = HAL_SPI_WORD_SIZE_8BIT;
int rc = hal_spi_config(RADIO_SPI_IDX, &spi_settings);
assert(rc == 0);
// Enable the SPI port
rc = hal_spi_enable(RADIO_SPI_IDX);
assert(rc == 0);
Here’s how we do the same on BL602: sx1276-board.c
// Configure the SPI Port
int rc = spi_init(
&spi_device, // SPI Device
RADIO_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 SX1276 should be 0 (CPOL=0, CPHA=0).
1, // SPI Polarity-Phase
SX1276_SPI_BAUDRATE, // SPI Frequency
2, // Transmit DMA Channel
3, // Receive DMA Channel
SX1276_SPI_CLK_PIN, // SPI Clock Pin
SX1276_SPI_CS_OLD, // Unused SPI Chip Select Pin
SX1276_SPI_SDI_PIN, // SPI Serial Data In Pin (formerly MISO)
SX1276_SPI_SDO_PIN // SPI Serial Data Out Pin (formerly MOSI)
);
assert(rc == 0);
Note: SPI Mode 0 in Mynewt (CPOL=0, CPHA=0) becomes SPI Polarity-Phase 1 in BL602 (CPOL=0, CPHA=1).
In Mynewt, we call hal_spi_tx_val
to read and write a byte over SPI.
On BL602, we implement hal_spi_tx_val
like so: sx1276.c
In Mynewt we configure pins D0 to D5 to trigger an interrupt when the input changes: sx1276-board.c
// Configure GPIO Input Pin for Interrupt
int rc = hal_gpio_irq_init(
SX1276_DIO0, // Pin number
irqHandlers[0], // Interrupt handler
NULL, // Argument
HAL_GPIO_TRIG_RISING, // Trigger interrupt when input goes from Low to High
HAL_GPIO_PULL_NONE // No pullup and no pulldown
);
assert(rc == 0);
// Enable the GPIO Input interrupt
hal_gpio_irq_enable(SX1276_DIO0);
For receiving LoRa Packets, we handle GPIO Interrupts with the BL602 Interrupt HAL and the NimBLE Porting Library…
For receiving LoRa Packets with Timeout, we use Timers from the NimBLE Porting Library…