Many wireless transceivers are now available as pluggable modules using high density connectors like the M.2 edge connector or plug and socket board-to-board connectors. This provides to implement custom PCBs where you can quickly add or customize wireless capability.
I've been looking for a module that has both BLE and LoRa protocols and I found the RAK4631 from RAK Wireless - RAK4631 LPWan Node.
Key Features:
- RAK4631: LoRaWAN® 1.0.2 protocol stack (supports Class A & C)
- RAK4631-R: LoRaWAN® 1.0.3 protocol stack (supports Class A, B & C)
- Bluetooth Low Energy 5.0 protocol stack
- Nordic nRF52840:
- Ultra-low-power MCU
- 32-bit ARM® Cortex-M4F CPU
- 64MHz CPU clock
- 1 MB Flash, 256 KB RAM
- Wide range of connections:
- I2C, SPI, Analog inputs,
- Digital inputs and outputs
- Semtech SX1262:
- Low power high range
- LoRa® transceiver
The module does require a carrier (base) board, either a custom one or RAK offers a variety of base boards that also provide connectors for sensors and other accessories plus a USB interface. I decided to buy a starter kit that included the RAK4631 and WisBlock Base RAK 5005-O plus LoRa and BLE u.FL antennas. The board also provides a micro USB connector and power connectors for a LiPo battery or solar. It also has connectors for 4 sensor modules and 1 IO module (e.g. GNSS, display).
The daughter boards connect to the base board using either a 24 pin (Sensor) or 40 pin (IO/Core) WisConnector.
Good news for me - the RAK boards are supported in the Arduino IDE and Platform IO. Since I'm familiar with the nRF52840, I thought I'd try out a quick BLE example.
I decided to try a simple BLE UART and connect it to the Adafruit Bluefruit LE Connect app that I have running on my iPad.
Here's my setup:
The Arduino sketch
RAK4631_ble_uart.ino
/*
file ble_uart.ino
author Bernd Giesecke
brief BLE example shows how to implement UART over BLE
version 0.1
date 2020-07-27
copyright Copyright (c) 2020
note RAK4631 GPIO mapping to nRF52840 GPIO ports
RAK4631 <-> nRF52840
WB_IO1 <-> P0.17 (GPIO 17)
WB_IO2 <-> P1.02 (GPIO 34)
WB_IO3 <-> P0.21 (GPIO 21)
WB_IO4 <-> P0.04 (GPIO 4)
WB_IO5 <-> P0.09 (GPIO 9)
WB_IO6 <-> P0.10 (GPIO 10)
WB_SW1 <-> P0.01 (GPIO 1)
WB_A0 <-> P0.04/AIN2 (AnalogIn A2)
WB_A1 <-> P0.31/AIN7 (AnalogIn A7)
*/
#include <Arduino.h>
#include <bluefruit.h>
// Forward declarations for functions
void ble_connect_callback(uint16_t conn_handle);
void ble_disconnect_callback(uint16_t conn_handle, uint8_t reason);
/**
@brief BLE UART service
@note Used for BLE UART communication
*/
BLEUart g_BleUart;
/** Flag if BLE UART client is connected */
bool g_BleUartConnected = false;
/**
@brief Arduino setup function. Called once after power on or reset
*/
void setup()
{
// Initialize built in green LED
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
// Initialize Serial for debug output
Serial.begin(115200);
// Wait for USB Serial to be ready or terminal to be connected
time_t timeout = millis(); // Timeout in case the system runs on its own
// Waiting for Serial
while (!Serial)
{
if ((millis() - timeout) < 5000)
{
// Blink the LED to show that we are alive
delay(100);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
else
{
// Timeout while waiting for USB Serial
break;
}
}
Serial.println("================================");
Serial.println("RAK4631 BLE UART example");
Serial.println("================================");
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
Bluefruit.begin(1, 0);
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
// Set the BLE device name
Bluefruit.setName("RAK4631_UART");
Bluefruit.Periph.setConnectCallback(ble_connect_callback);
Bluefruit.Periph.setDisconnectCallback(ble_disconnect_callback);
// Configure and Start BLE Uart Service
g_BleUart.begin();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
}
/**
@brief Callback when client connects
@param conn_handle: Connection handle id
*/
void ble_connect_callback(uint16_t conn_handle)
{
(void)conn_handle;
g_BleUartConnected = true;
Serial.println("BLE client connected");
}
/**
@brief Callback invoked when a connection is dropped
@param conn_handle: connection handle id
@param reason: disconnect reason
*/
void ble_disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void)conn_handle;
(void)reason;
g_BleUartConnected = false;
Serial.println("BLE client disconnected");
}
/**
@brief Arduino loop. Runs forever until power off or reset
*/
void loop()
{
// Forward anything received from USB Serial to BLE UART
if (Serial.available() && g_BleUartConnected)
{
g_BleUart.print(Serial.readString());
}
// Forward anything received from BLE UART to USB Serial
if (g_BleUart.available())
{
Serial.print(g_BleUart.readString());
}
}
{gallery}BLE UART Test |
---|
Bluefruit LE Connect: Select Service |
Bluefruit LE Connect: UART Send Message |
Bluefruit LE Connect: UART Message Sent |
Arduino Serial Monitor: UART Message Received |
So, BLE UART is working.
I should have gotten a Sensor IO adapter module so that I could add Grove, Stemma QT or Click sensors - that's on my list to buy.
Next to try is using LoRa and BLE together, or maybe just try LoRa separately first.