From 409a74933bb8ba357e710c7b3d2e8fbaa917c722 Mon Sep 17 00:00:00 2001 From: Vladimir Zaytsev Date: Mon, 30 Mar 2026 10:46:57 -0500 Subject: [PATCH] Add initial MuziWorks Base Duo board support (nRF52840 + LR1121) --- boards/muziworks-duo.json | 59 +++++++++ src/helpers/radiolib/CustomLR1121.h | 35 ++++++ src/helpers/radiolib/CustomLR1121Wrapper.h | 34 +++++ variants/muziworks_duo/MuziWorksDuoBoard.cpp | 28 +++++ variants/muziworks_duo/MuziWorksDuoBoard.h | 42 +++++++ variants/muziworks_duo/platformio.ini | 113 +++++++++++++++++ variants/muziworks_duo/target.cpp | 89 ++++++++++++++ variants/muziworks_duo/target.h | 20 +++ variants/muziworks_duo/variant.cpp | 73 +++++++++++ variants/muziworks_duo/variant.h | 123 +++++++++++++++++++ 10 files changed, 616 insertions(+) create mode 100644 boards/muziworks-duo.json create mode 100644 src/helpers/radiolib/CustomLR1121.h create mode 100644 src/helpers/radiolib/CustomLR1121Wrapper.h create mode 100644 variants/muziworks_duo/MuziWorksDuoBoard.cpp create mode 100644 variants/muziworks_duo/MuziWorksDuoBoard.h create mode 100644 variants/muziworks_duo/platformio.ini create mode 100644 variants/muziworks_duo/target.cpp create mode 100644 variants/muziworks_duo/target.h create mode 100644 variants/muziworks_duo/variant.cpp create mode 100644 variants/muziworks_duo/variant.h diff --git a/boards/muziworks-duo.json b/boards/muziworks-duo.json new file mode 100644 index 0000000000..139f90cec0 --- /dev/null +++ b/boards/muziworks-duo.json @@ -0,0 +1,59 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_MUZIWORKS_DUO -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "MuziWorks-Duo-BOOT", + "mcu": "nrf52840", + "variant": "muziworks_duo", + "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", + "openocd_target": "nrf52.cfg" + }, + "frameworks": ["arduino"], + "name": "MuziWorks Base Duo", + "upload": { + "maximum_ram_size": 235520, + "maximum_size": 811008, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://www.muziworks.com", + "vendor": "MuziWorks" +} diff --git a/src/helpers/radiolib/CustomLR1121.h b/src/helpers/radiolib/CustomLR1121.h new file mode 100644 index 0000000000..b618f6d60b --- /dev/null +++ b/src/helpers/radiolib/CustomLR1121.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include "MeshCore.h" + +class CustomLR1121 : public LR1121 { + bool _rx_boosted = false; + + public: + CustomLR1121(Module *mod) : LR1121(mod) { } + + size_t getPacketLength(bool update) override { + size_t len = LR1121::getPacketLength(update); + if (len == 0 && getIrqStatus() & RADIOLIB_LR11X0_IRQ_HEADER_ERR) { + MESH_DEBUG_PRINTLN("LR1121: got header err, calling standby()"); + standby(); + } + return len; + } + + float getFreqMHz() const { return freqMHz; } + + int16_t setRxBoostedGainMode(bool en) { + _rx_boosted = en; + return LR1121::setRxBoostedGainMode(en); + } + + bool getRxBoostedGainMode() const { return _rx_boosted; } + + bool isReceiving() { + uint16_t irq = getIrqStatus(); + bool detected = ((irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID) || (irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED)); + return detected; + } +}; diff --git a/src/helpers/radiolib/CustomLR1121Wrapper.h b/src/helpers/radiolib/CustomLR1121Wrapper.h new file mode 100644 index 0000000000..6017c1c1dc --- /dev/null +++ b/src/helpers/radiolib/CustomLR1121Wrapper.h @@ -0,0 +1,34 @@ +#pragma once + +#include "CustomLR1121.h" +#include "RadioLibWrappers.h" +#include "LR11x0Reset.h" + +class CustomLR1121Wrapper : public RadioLibWrapper { +public: + CustomLR1121Wrapper(CustomLR1121& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } + void doResetAGC() override { lr11x0ResetAGC((LR11x0 *)_radio, ((CustomLR1121 *)_radio)->getFreqMHz()); } + bool isReceivingPacket() override { + return ((CustomLR1121 *)_radio)->isReceiving(); + } + float getCurrentRSSI() override { + float rssi = -110; + ((CustomLR1121 *)_radio)->getRssiInst(&rssi); + return rssi; + } + + void onSendFinished() override { + RadioLibWrapper::onSendFinished(); + _radio->setPreambleLength(16); // overcomes weird issues with small and big pkts + } + + float getLastRSSI() const override { return ((CustomLR1121 *)_radio)->getRSSI(); } + float getLastSNR() const override { return ((CustomLR1121 *)_radio)->getSNR(); } + + void setRxBoostedGainMode(bool en) override { + ((CustomLR1121 *)_radio)->setRxBoostedGainMode(en); + } + bool getRxBoostedGainMode() const override { + return ((CustomLR1121 *)_radio)->getRxBoostedGainMode(); + } +}; diff --git a/variants/muziworks_duo/MuziWorksDuoBoard.cpp b/variants/muziworks_duo/MuziWorksDuoBoard.cpp new file mode 100644 index 0000000000..60ce2a0fe2 --- /dev/null +++ b/variants/muziworks_duo/MuziWorksDuoBoard.cpp @@ -0,0 +1,28 @@ +#ifdef MUZIWORKS_DUO + +#include "MuziWorksDuoBoard.h" + +#include +#include + +void MuziWorksDuoBoard::begin() { + NRF52BoardDCDC::begin(); + + pinMode(PIN_VBAT_READ, INPUT); + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_BLUE, OUTPUT); + + // LEDs off (active LOW) + digitalWrite(LED_GREEN, !LED_STATE_ON); + digitalWrite(LED_BLUE, LED_STATE_ON); + +#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL) + Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL); +#endif + + Wire.begin(); + + delay(10); +} + +#endif diff --git a/variants/muziworks_duo/MuziWorksDuoBoard.h b/variants/muziworks_duo/MuziWorksDuoBoard.h new file mode 100644 index 0000000000..185b77936f --- /dev/null +++ b/variants/muziworks_duo/MuziWorksDuoBoard.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +#ifdef MUZIWORKS_DUO + +#define PIN_VBAT_READ BATTERY_PIN +#define BATTERY_SAMPLES 8 + +class MuziWorksDuoBoard : public NRF52BoardDCDC { +public: + MuziWorksDuoBoard() : NRF52Board("MuziWorksDuo_OTA") {} + void begin(); + + uint16_t getBattMilliVolts() override { + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + return (ADC_MULTIPLIER * raw); + } + + const char* getManufacturerName() const override { + return "MuziWorks Duo"; + } + +#if defined(LED_GREEN) + void onBeforeTransmit() override { + digitalWrite(LED_GREEN, LED_STATE_ON); + } + void onAfterTransmit() override { + digitalWrite(LED_GREEN, !LED_STATE_ON); + } +#endif +}; + +#endif diff --git a/variants/muziworks_duo/platformio.ini b/variants/muziworks_duo/platformio.ini new file mode 100644 index 0000000000..49ffaf3ba7 --- /dev/null +++ b/variants/muziworks_duo/platformio.ini @@ -0,0 +1,113 @@ +; ----------------- MuziWorks Base Duo (nRF52840 + LR1121) --------------------- +[muziworks_duo] +extends = nrf52_base +board = muziworks-duo +board_build.ldscript = boards/nrf52840_s140_v6.ld +build_flags = ${nrf52_base.build_flags} + ${sensor_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 + -I variants/muziworks_duo + -D NRF52_PLATFORM + -D MUZIWORKS_DUO + -D ENV_INCLUDE_GPS=0 + -D CONFIG_NFCT_PINS_AS_GPIOS=1 + -D RADIO_CLASS=CustomLR1121 + -D WRAPPER_CLASS=CustomLR1121Wrapper + -D LORA_TX_POWER=22 + -D MAX_LORA_TX_POWER=22 + -D RX_BOOSTED_GAIN=true + -D RF_SWITCH_TABLE + -D P_LORA_DIO_1=40 + -D P_LORA_RESET=42 + -D P_LORA_BUSY=43 + -D P_LORA_NSS=44 + -D P_LORA_SCLK=45 + -D P_LORA_MOSI=46 + -D P_LORA_MISO=47 + -D LR11X0_DIO_AS_RF_SWITCH=true + -D LR11X0_DIO3_TCXO_VOLTAGE=3.0 +build_src_filter = ${nrf52_base.build_src_filter} + + + + + +<../variants/muziworks_duo> +debug_tool = jlink +upload_protocol = nrfutil +lib_deps = ${nrf52_base.lib_deps} + ${sensor_base.lib_deps} + +[env:muziworks_duo_repeater] +extends = muziworks_duo +build_flags = + ${muziworks_duo.build_flags} + -D ADVERT_NAME='"MuziDuo Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +build_src_filter = ${muziworks_duo.build_src_filter} + +<../examples/simple_repeater/*.cpp> + +[env:muziworks_duo_room_server] +extends = muziworks_duo +build_flags = + ${muziworks_duo.build_flags} + -D ADVERT_NAME='"MuziDuo Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +build_src_filter = ${muziworks_duo.build_src_filter} + +<../examples/simple_room_server/*.cpp> + +[env:muziworks_duo_companion_radio_usb] +extends = muziworks_duo +board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld +board_upload.maximum_size = 708608 +build_flags = + ${muziworks_duo.build_flags} + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${muziworks_duo.build_src_filter} + + + +<../examples/companion_radio/*.cpp> +lib_deps = + ${muziworks_duo.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:muziworks_duo_terminal_chat] +extends = muziworks_duo +build_flags = + ${muziworks_duo.build_flags} + -D ADVERT_NAME='"MuziDuo Chat"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +build_src_filter = ${muziworks_duo.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = + ${muziworks_duo.lib_deps} + densaugeo/base64 @ ~1.4.0 + +[env:muziworks_duo_companion_radio_ble] +extends = muziworks_duo +board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld +board_upload.maximum_size = 708608 +build_flags = + ${muziworks_duo.build_flags} + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D QSPIFLASH=1 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${muziworks_duo.build_src_filter} + + + +<../examples/companion_radio/*.cpp> +lib_deps = + ${muziworks_duo.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/muziworks_duo/target.cpp b/variants/muziworks_duo/target.cpp new file mode 100644 index 0000000000..110609157e --- /dev/null +++ b/variants/muziworks_duo/target.cpp @@ -0,0 +1,89 @@ +#include +#include "target.h" +#include + +MuziWorksDuoBoard 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 rtc_clock; +EnvironmentSensorManager sensors; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +#ifdef RF_SWITCH_TABLE +static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = { + RADIOLIB_LR11X0_DIO5, + RADIOLIB_LR11X0_DIO6, + RADIOLIB_NC, + RADIOLIB_NC, + RADIOLIB_NC +}; + +static const Module::RfSwitchMode_t rfswitch_table[] = { + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, {LOW, LOW }}, + { LR11x0::MODE_RX, {HIGH, LOW }}, + { LR11x0::MODE_TX, {LOW, HIGH}}, + { LR11x0::MODE_TX_HP, {LOW, HIGH}}, + { LR11x0::MODE_TX_HF, {LOW, LOW }}, + { LR11x0::MODE_GNSS, {LOW, LOW }}, + { LR11x0::MODE_WIFI, {LOW, LOW }}, + END_OF_MODE_TABLE, +}; +#endif + +bool radio_init() { +#ifdef LR11X0_DIO3_TCXO_VOLTAGE + float tcxo = LR11X0_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 3.0f; +#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_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; + } + + radio.setCRC(2); + radio.explicitHeader(); + +#ifdef RF_SWITCH_TABLE + radio.setRfSwitchTable(rfswitch_dios, rfswitch_table); +#endif + +#ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); +#endif + + return true; +} + +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(int8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); +} diff --git a/variants/muziworks_duo/target.h b/variants/muziworks_duo/target.h new file mode 100644 index 0000000000..583f6f5f3e --- /dev/null +++ b/variants/muziworks_duo/target.h @@ -0,0 +1,20 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include "MuziWorksDuoBoard.h" +#include +#include +#include + +extern MuziWorksDuoBoard board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; +extern EnvironmentSensorManager 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(int8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/muziworks_duo/variant.cpp b/variants/muziworks_duo/variant.cpp new file mode 100644 index 0000000000..3075c30efd --- /dev/null +++ b/variants/muziworks_duo/variant.cpp @@ -0,0 +1,73 @@ +/* + * variant.cpp - MuziWorks Base Duo + * Pin mapping for nRF52840 + */ + +#include "variant.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = +{ + 0, // P0.00 + 1, // P0.01 + 2, // P0.02 + 3, // P0.03 + 4, // P0.04 + 5, // P0.05 + 6, // P0.06 + 7, // P0.07 + 8, // P0.08 + 9, // P0.09 + 10, // P0.10 + 11, // P0.11 + 12, // P0.12 + 13, // P0.13 + 14, // P0.14 + 15, // P0.15 + 16, // P0.16 + 17, // P0.17 + 18, // P0.18 + 19, // P0.19 + 20, // P0.20 + 21, // P0.21 + 22, // P0.22 + 23, // P0.23 + 24, // P0.24, PIN_WIRE_SDA + 25, // P0.25, PIN_WIRE_SCL + 26, // P0.26 + 27, // P0.27 + 28, // P0.28 + 29, // P0.29 + 30, // P0.30 + 31, // P0.31, BATTERY_PIN (AIN7) + 32, // P1.00 + 33, // P1.01 + 34, // P1.02 + 35, // P1.03, LED_GREEN + 36, // P1.04, LED_BLUE + 37, // P1.05 + 38, // P1.06 + 39, // P1.07 + 40, // P1.08, LORA_DIO_1 (LR1121 IRQ) + 41, // P1.09 + 42, // P1.10, LORA_RESET (LR1121 NRESET) + 43, // P1.11, LORA_BUSY (LR1121 BUSY) + 44, // P1.12, PIN_SPI_NSS (LR1121 NSS) + 45, // P1.13, PIN_SPI_SCK (LR1121 SCK) + 46, // P1.14, PIN_SPI_MOSI (LR1121 MOSI) + 47, // P1.15, PIN_SPI_MISO (LR1121 MISO) + 255, // NRFX_SPIM_PIN_NOT_USED +}; + +void initVariant() +{ + pinMode(BATTERY_PIN, INPUT); + + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_BLUE, OUTPUT); + + // LEDs off (active LOW) + digitalWrite(LED_GREEN, !LED_STATE_ON); + digitalWrite(LED_BLUE, !LED_STATE_ON); +} diff --git a/variants/muziworks_duo/variant.h b/variants/muziworks_duo/variant.h new file mode 100644 index 0000000000..a9f8eb7349 --- /dev/null +++ b/variants/muziworks_duo/variant.h @@ -0,0 +1,123 @@ +/* + * variant.h - MuziWorks Base Duo + * nRF52840 + LR1121 (Sub-GHz LoRa) + * Elecrow nRFLR1121 module + */ + +#pragma once + +#include "WVariant.h" + +//////////////////////////////////////////////////////////////////////////////// +// Low frequency clock source + +#define USE_LFXO // 32.768 kHz crystal oscillator +#define VARIANT_MCK (64000000ul) + +//////////////////////////////////////////////////////////////////////////////// +// Power + +#define BATTERY_PIN (31) // P0.31 (AIN7) +#define BATTERY_IMMUTABLE +#define ADC_MULTIPLIER (1.537F) + +#define ADC_RESOLUTION (12) +#define BATTERY_SENSE_RES (12) + +//////////////////////////////////////////////////////////////////////////////// +// Number of pins + +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (8) +#define NUM_ANALOG_OUTPUTS (0) + +//////////////////////////////////////////////////////////////////////////////// +// UART pin definition + +#define PIN_SERIAL1_RX (20) // P0.20 (GPS RX) +#define PIN_SERIAL1_TX (19) // P0.19 (GPS TX) + +//////////////////////////////////////////////////////////////////////////////// +// I2C pin definition + +#define HAS_WIRE (1) +#define WIRE_INTERFACES_COUNT (1) + +#define PIN_WIRE_SDA (24) // P0.24 +#define PIN_WIRE_SCL (25) // P0.25 +#define I2C_NO_RESCAN + +//////////////////////////////////////////////////////////////////////////////// +// SPI pin definition (internal to Elecrow nRFLR1121 module) + +#define SPI_INTERFACES_COUNT (1) + +#define PIN_SPI_MISO (47) // P1.15 +#define PIN_SPI_MOSI (46) // P1.14 +#define PIN_SPI_SCK (45) // P1.13 +#define PIN_SPI_NSS (44) // P1.12 + +//////////////////////////////////////////////////////////////////////////////// +// Builtin LEDs (active LOW) + +#define LED_GREEN (35) // P1.03 +#define LED_BLUE (36) // P1.04 +#define LED_BUILTIN LED_GREEN +#define LED_PIN LED_GREEN + +#define LED_STATE_ON LOW + +//////////////////////////////////////////////////////////////////////////////// +// Builtin buttons + +#define PIN_BUTTON1 (-1) +#define BUTTON_PIN PIN_BUTTON1 + +//////////////////////////////////////////////////////////////////////////////// +// LR1121 LoRa Radio (sub-GHz) + +#define LORA_DIO_1 (40) // P1.08 - LR1121 IRQ (DIO1) +#define LORA_NSS (PIN_SPI_NSS) // P1.12 +#define LORA_RESET (42) // P1.10 - LR1121 NRESET +#define LORA_BUSY (43) // P1.11 - LR1121 BUSY +#define LORA_SCLK (PIN_SPI_SCK) // P1.13 +#define LORA_MISO (PIN_SPI_MISO) // P1.15 +#define LORA_MOSI (PIN_SPI_MOSI) // P1.14 +#define LORA_CS PIN_SPI_NSS // P1.12 + +#define LR11X0_DIO_AS_RF_SWITCH true +#define LR11X0_DIO3_TCXO_VOLTAGE 3.0 + +//////////////////////////////////////////////////////////////////////////////// +// GPS/GNSS + +#define HAS_GPS 0 +#define PIN_GPS_TX (-1) +#define PIN_GPS_RX (-1) +#define GPS_EN (-1) +#define GPS_RESET (-1) + +//////////////////////////////////////////////////////////////////////////////// +// QSPI Flash (W25Q32JVSS - 8MB) + +#define PIN_QSPI_SCK (3) // P0.03 +#define PIN_QSPI_CS (26) // P0.26 +#define PIN_QSPI_IO0 (30) // P0.30 +#define PIN_QSPI_IO1 (29) // P0.29 +#define PIN_QSPI_IO2 (28) // P0.28 +#define PIN_QSPI_IO3 (2) // P0.02 + +#define EXTERNAL_FLASH_DEVICES W25Q64JV +#define EXTERNAL_FLASH_USE_QSPI + +//////////////////////////////////////////////////////////////////////////////// +// Additional peripheral pins (not enabled) +// +// I2C bus 1 (IMU): SDA P0.04, SCL P0.06 +// Display (SH1107 OLED): I2C bus 0, power enable P0.23 +// Trackball: UP P0.21, DOWN P0.17, LEFT P1.05, RIGHT P0.16, PRESS P0.10 +// Buzzer: P0.22 +// Buttons: Cancel P0.15, Mode1 P1.09, Mode2 P0.12 +// GPS: RX P0.20, TX P0.19, EN P1.01 +// Charge status: P1.02 (inverted)