Initial support for nano g2 ultra

not yet implemented are GPS and external notification LED and buzzer
This commit is contained in:
Rob Loranger
2025-05-15 11:15:55 -07:00
parent 9048142f63
commit 7e14fb3f65
8 changed files with 610 additions and 0 deletions

72
boards/nano-g2-ultra.json Normal file
View File

@@ -0,0 +1,72 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x8029"
],
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
],
"usb_product": "BQ nRF52840",
"mcu": "nrf52840",
"variant": "nano-g2-ultra",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "BQ nRF52840",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
"vendor": "BQ Consulting"
}

View File

@@ -0,0 +1,103 @@
#include <Arduino.h>
#include "nano-g2.h"
#ifdef NANO_G2_ULTRA
#include <bluefruit.h>
#include <Wire.h>
static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle)
{
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
}
void NanoG2Ultra::begin()
{
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
pinMode(PIN_BUTTON1, INPUT);
// the external notification circuit is shared for both buzzer and led
// need to find out the switch state or somehow write a function that can
// sound the buzzer or signal the led. the led will stay on once brought HIGH
// and can be then brought LOW. It turns off with a hardware btn.
pinMode(EXT_NOTIFY_OUT, OUTPUT);
digitalWrite(EXT_NOTIFY_OUT, LOW);
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10);
}
uint16_t NanoG2Ultra::getBattMilliVolts()
{
int adcvalue = 0;
analogReference(AR_INTERNAL_3_0);
analogReadResolution(12);
delay(10);
// ADC range is 0..3000mV and resolution is 12-bit (0..4095)
adcvalue = analogRead(PIN_VBAT_READ);
// Convert the raw value to compensated mv, taking the resistor-
// divider into account (providing the actual LIPO voltage)
return (uint16_t)((float)adcvalue * REAL_VBAT_MV_PER_LSB);
}
bool NanoG2Ultra::startOTAUpdate(const char *id, char reply[])
{
// 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("TECHO_OTA");
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// To be consistent OTA DFU should be added first if it exists
bledfu.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
strcpy(reply, "OK - started");
return true;
}
#endif

View File

@@ -0,0 +1,57 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
// LoRa radio module pins
#define P_LORA_DIO_1 (32 + 10)
#define P_LORA_NSS (32 + 13)
#define P_LORA_RESET (32 + 15)
#define P_LORA_BUSY (32 + 11)
#define P_LORA_SCLK (0 + 12)
#define P_LORA_MISO (32 + 9)
#define P_LORA_MOSI (0 + 11)
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define SX126X_POWER_EN 37
// buttons
#define PIN_BUTTON1 (32 + 6)
#define BUTTON_PIN PIN_BUTTON1
#define PIN_USER_BTN BUTTON_PIN
// built-ins
#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
#define VBAT_DIVIDER (0.5F) // 150K + 150K voltage divider on VBAT, actually 100K + 100K
#define VBAT_DIVIDER_COMP (2.0F) // Compensation factor for the VBAT divider
#define PIN_VBAT_READ (0 + 2)
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
class NanoG2Ultra : public mesh::MainBoard
{
protected:
uint8_t startup_reason;
public:
void begin();
uint16_t getBattMilliVolts() override;
bool startOTAUpdate(const char *id, char reply[]) override;
uint8_t getStartupReason() const override
{
return startup_reason;
}
const char *getManufacturerName() const override
{
return "Nano G2 Ultra";
}
void reboot() override
{
NVIC_SystemReset();
}
};

View File

@@ -0,0 +1,57 @@
[nrf52840_g2_ultra]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
lewisxhe/PCF8563_Library@^1.0.1
[Nano_G2_Ultra]
extends = nrf52840_g2_ultra
board = nano-g2-ultra
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_g2_ultra.build_flags}
-I variants/nano_g2_ultra
-D NANO_G2_ULTRA
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D PIN_USER_BTN=38
build_src_filter = ${nrf52840_g2_ultra.build_src_filter}
+<helpers/*.cpp>
+<../variants/nano_g2_ultra>
debug_tool = jlink
upload_protocol = nrfutil
[env:Nano_G2_Ultra_companion_radio_ble]
extends = Nano_G2_Ultra
build_flags =
${Nano_G2_Ultra.build_flags}
-I src/helpers/ui
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=0
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
-D SH1106
-D DISPLAY_CLASS=SH1106Display
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Nano_G2_Ultra.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<helpers/ui/SH1106Display.cpp>
+<../examples/companion_radio>
lib_deps =
${Nano_G2_Ultra.lib_deps}
densaugeo/base64 @ ~1.4.0
adafruit/Adafruit SH110X @ ~2.1.13
adafruit/Adafruit GFX Library @ ^1.12.1

View File

@@ -0,0 +1,76 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
NanoG2Ultra board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init()
{
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE)
{
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed()
{
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr)
{
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm)
{
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity()
{
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,20 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include "nano-g2.h"
#include <helpers/RadioLibWrappers.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
extern NanoG2Ultra board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -0,0 +1,36 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// Nothing need to be inited for now
}

View File

@@ -0,0 +1,189 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VARIANT_Nano_G2_
#define _VARIANT_Nano_G2_
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
// #define USE_LFRC // Board uses 32khz RC for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (1)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (-1)
#define PIN_LED2 (-1)
#define PIN_LED3 (-1)
#define LED_RED PIN_LED3
#define LED_BLUE PIN_LED1
#define LED_GREEN PIN_LED2
#define LED_BUILTIN LED_BLUE
#define LED_CONN PIN_GREEN
#define LED_STATE_ON 0 // State when LED is lit
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 6)
#define EXT_NOTIFY_OUT (0 + 4) // Default pin to use for Ext Notify Module.
/*
* Analog pins
*/
#define PIN_A4 (0 + 2) // Battery ADC
#define BATTERY_PIN PIN_A4
static const uint8_t A4 = PIN_A4;
#define ADC_RESOLUTION 14
/*
* Serial interfaces
*/
#define PIN_SERIAL2_RX (0 + 22)
#define PIN_SERIAL2_TX (0 + 20)
/**
Wire Interfaces
*/
#define WIRE_INTERFACES_COUNT 1
#define PIN_WIRE_SDA (0 + 17)
#define PIN_WIRE_SCL (0 + 15)
#define PIN_RTC_INT (0 + 14) // Interrupt from the PCF8563 RTC
/*
External serial flash W25Q16JV_IQ
*/
// QSPI Pins
#define PIN_QSPI_SCK (0 + 8)
#define PIN_QSPI_CS (32 + 7)
#define PIN_QSPI_IO0 (0 + 6) // MOSI if using two bit interface
#define PIN_QSPI_IO1 (0 + 26) // MISO if using two bit interface
#define PIN_QSPI_IO2 (32 + 4) // WP if using two bit interface (i.e. not used)
#define PIN_QSPI_IO3 (32 + 2) // HOLD if using two bit interface (i.e. not used)
// On-board QSPI Flash
#define EXTERNAL_FLASH_DEVICES W25Q16JV_IQ
#define EXTERNAL_FLASH_USE_QSPI
/*
* Lora radio
*/
#define USE_SX1262
#define SX126X_CS (32 + 13) // FIXME - we really should define LORA_CS instead
#define SX126X_DIO1 (32 + 10)
// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching
// #define SX1262_DIO3 (0 + 21)
// This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main CPU?
#define SX126X_BUSY (32 + 11)
#define SX126X_RESET (32 + 15)
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...)
// #undef SX126X_CS
/*
* GPS pins
*/
#define GPS_L76K
#define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY
#define PIN_GPS_TX (0 + 9) // This is for bits going TOWARDS the CPU
#define PIN_GPS_RX (0 + 10) // This is for bits going TOWARDS the GPS
// #define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX PIN_GPS_RX
// PCF8563 RTC Module
#define PCF8563_RTC 0x51
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
// For LORA, spi 0
#define PIN_SPI_MISO (32 + 9)
#define PIN_SPI_MOSI (0 + 11)
#define PIN_SPI_SCK (0 + 12)
// #define PIN_PWR_EN (0 + 6)
// To debug via the segger JLINK console rather than the CDC-ACM serial device
// #define USE_SEGGER
// Battery
// The battery sense is hooked to pin A0 (2)
// it is defined in the anlaolgue pin section of this file
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F)
#define HAS_RTC 1
/**
OLED Screen Model
*/
#define ARDUINO_ARCH_AVR
#define USE_SH1107_128_64
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif