* Add software LoRa IRQ polling and an MCP23017 expander HAL for radios behind an I2C expander
Some boards route the SX126x control lines (NRESET/DIO1/BUSY) through an I2C
GPIO expander instead of native GPIOs, and don't wire the expander's /INT to
the MCU, so RadioLib cannot take a hardware DIO1 interrupt.
Two reusable pieces, both gated behind USE_MCP23017 / LORA_DIO1_SOFTWARE_POLL
so builds that don't define them are unaffected:
- ExtensionIOMCP23017 + MCP23017LockingArduinoHal: a RadioLib HAL that maps
virtual pins (MCP23017_VPIN_BASE .. +15) onto an MCP23017's GPIO, so
RESET/BUSY/DIO1 reads and writes become I2C transactions while the real SPI
GPIOs (SCK/MOSI/MISO/CS) pass straight through. A failed I2C read skips the
read-modify-write rather than clobbering the rest of the bank.
- LORA_DIO1_SOFTWARE_POLL: with no DIO1 interrupt available, the SX126x
interface polls the radio IRQ status register from the radio thread and
synthesizes the ISR_TX/ISR_RX events, filtering noisy preamble/header IRQs so
they can't starve TX. A 1 ms ISR_POLL_TICK drives the poll; TX timers may
overwrite the pending tick (pollMissedIrqs() is the backup that bounds the
latency of the busy-Rx contention window). Behaviour is unchanged on all
boards that keep the hardware interrupt.
* Add Meshnology W10 AIOT Dev Kit variant (SX1262 via MCP23017 expander)
ESP32-S3R8 + EBYTE E22-900MM22S (SX1262) + AXP2101 PMIC + Quectel L76KB GPS +
SPI TFT, with the radio's RESET/DIO1/BUSY and the LCD reset routed through an
MCP23017 I2C expander at 0x20. The expander's /INT is not wired to the ESP32,
so DIO1 uses the software poll. Pins come from the board schematic and the
vendor firmware; the expander is an MCP23017 despite the V1.1 schematic's stale
'TCA9555' label (the V1.2 placement diagram and all vendor code use the MCP23017
register map).
A local pins_arduino.h shadows the generic esp32s3 variant to drop RGB_BUILTIN,
which otherwise pulls the Arduino RMT HAL into the link and fails against this
build's trimmed FreeRTOS config.
Reports HardwareModel 140 (MESHNOLOGY_W10, already present in the protobufs).
Hardware-verified on a real W10 AIOT Dev Kit: AXP2101 PMU, MCP23017, SX1262
init + a full over-the-air TX/RX round trip through the expander, PCF85063 RTC,
SHT41 and QMI8658 auto-detected, and an L76KB GPS fix.
* meshnology-w10: enable ES8311 speaker for notification tones
Bring up the ES8311 codec (I2C 0x18) -> NS4150 amp -> speaker so the board can
play notification tones / ringtones over the I2S buzzer path (the
use_i2s_as_buzzer external-notification option). Codec2 voice stays out of
scope: it is SX1280-only and this is a sub-GHz board.
- variant.h: HAS_I2S + DAC_I2S pins (MCLK=1, BCK=2, WS=4, DOUT=5, DIN=3)
- platformio.ini: arduino-audio-driver + ESP8266Audio + ESP8266SAM
- extra_variants/meshnology_w10/variant.cpp: lateInitVariant() configures the
ES8311, mirroring the other Meshtastic ES8311 boards. Kept codec-only (no
main.h) so the audio driver's 'using namespace audio_driver' does not pull a
conflicting GpioPin into scope alongside Meshtastic's class GpioPin.
- AudioThread.h: toggle the NS4150 amp (MCP23017 EXIO_PA_CTRL) around playback.
Verified on hardware: a test tune played audibly through the speaker.
* meshnology-w10: address review feedback on the MCP23017 driver
- ExtensionIOMCP23017: serialize register access with a mutex, since the radio
HAL (BUSY/DIO1/RESET) and AudioThread (amp enable) now reach the expander from
different threads and the read-modify-write paths are not atomic.
- digitalRead: return a fail-safe HIGH on a failed read instead of LOW, so a
transient I2C error on the LoRa BUSY line can't look like 'ready' and let
RadioLib start an SPI transaction early. (DIO1 is polled via the radio IRQ
register, not this pin.)
- enablePinChangeInterrupt: use the checked readReg() overload and skip on a
failed read, matching the other read-modify-write helpers.
- meshnology_w10 variant.cpp: log a warning if an ES8311 register write NACKs
instead of silently leaving the codec half-configured.
- RadioInterface.cpp: guard the MCP23017 HAL branch with ARCH_ESP32 to match the
include and driver-file guards.
* Replace board-model audio/sleep ifdefs with reusable variant capability macros
Two shared-code spots keyed off specific hardware models; move the board-specific
detail into opt-in macros the variants define, so the core code stays generic and
new boards can opt into the behavior class without touching shared files.
- AudioThread amp control: drop the T_LORA_PAGER / MESHNOLOGY_W10 ifdefs. A board
with an I2S amp now defines AUDIO_AMP_ENABLE(on) in its variant.h (T-LoRa Pager
and Meshnology W10 do), and AudioThread just calls it around playback. The
expander includes are keyed on USE_XL9555 / USE_MCP23017 (capabilities) instead
of the model name.
- Light-sleep / DIO1 wakeup: drop the SENSECAP_INDICATOR check. Boards whose
LORA_DIO1 is an expander pin (not an ESP32 GPIO) define LORA_DIO1_EXTENDED_IO
(SenseCAP Indicator and Meshnology W10), and sleep.cpp keys off that for both
the light-sleep skip and the DIO1 GPIO-wakeup skip. This also fixes a latent
issue on the SenseCAP: it previously reached the GPIO-wakeup path and called
gpio_pulldown_en() on a virtual expander pin; it now skips that cleanly.
Builds verified on meshnology_w10, tlora-pager, and seeed-sensecap-indicator.
* meshnology-w10: silence cppcheck constParameterPointer on the ISR-callback helper
isIsrTxCallback() takes a function pointer it only compares; cppcheck's
constParameterPointer wants it 'pointer to const', which is meaningless for a
function pointer (the codebase already globally suppresses the sibling
constParameterCallback). Inline-suppress it to keep the check green.
* HopScaling: qualify the member assignment as this->count
cppcheck (CI's version) flags 'count = newCount;' at the end of trimIfNeeded()
as uselessAssignmentArg ('assignment of function parameter has no effect') - a
false positive, since count is a member that outlives the call. Write it as
this->count (matching the Step-1 assignment above) so the analyzer sees a member
write. This finding comes in via the develop merge, not this board; fixing it
here to unblock the PR's cppcheck check.
145 lines
3.3 KiB
C
145 lines
3.3 KiB
C
// ST7796 TFT LCD
|
|
#define TFT_CS 38
|
|
#define HAS_SPI_TFT 1
|
|
#define ST7796_CS TFT_CS
|
|
#define ST7796_RS 37 // DC
|
|
#define ST7796_SDA MOSI // MOSI
|
|
#define ST7796_SCK SCK
|
|
#define ST7796_RESET -1
|
|
#define ST7796_MISO MISO
|
|
#define ST7796_BUSY -1
|
|
#define ST7796_BL 42
|
|
#define ST7796_SPI_HOST SPI2_HOST
|
|
#define TFT_BL 42
|
|
#define SPI_FREQUENCY 75000000
|
|
#define SPI_READ_FREQUENCY 16000000
|
|
#define TFT_HEIGHT 480
|
|
#define TFT_WIDTH 222
|
|
#define TFT_OFFSET_X 49
|
|
#define TFT_OFFSET_Y 0
|
|
#define TFT_OFFSET_ROTATION 3
|
|
#define SCREEN_ROTATE
|
|
#define SCREEN_TRANSITION_FRAMERATE 30
|
|
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
|
#define USE_TFTDISPLAY 1
|
|
#define HAS_PHYSICAL_KEYBOARD 1
|
|
|
|
#define I2C_SDA SDA
|
|
#define I2C_SCL SCL
|
|
|
|
#define HAS_DRV2605 1
|
|
|
|
#define USE_POWERSAVE
|
|
#define SLEEP_TIME 120
|
|
|
|
// GNNS
|
|
#define HAS_GPS 1
|
|
#define GPS_BAUDRATE 38400
|
|
#define GPS_RX_PIN 4
|
|
#define GPS_TX_PIN 12
|
|
#define PIN_GPS_PPS 13
|
|
|
|
// PCF85063 RTC Module
|
|
#define PCF85063_RTC 0x51
|
|
|
|
// Rotary
|
|
#define ROTARY_A (40)
|
|
#define ROTARY_B (41)
|
|
#define ROTARY_PRESS (7)
|
|
|
|
#define BUTTON_PIN 0
|
|
|
|
// SPI interface SD card slot
|
|
#define SPI_MOSI MOSI
|
|
#define SPI_SCK SCK
|
|
#define SPI_MISO MISO
|
|
#define SPI_CS 21
|
|
#define SDCARD_CS SPI_CS
|
|
#define SD_SPI_FREQUENCY 75000000U
|
|
|
|
// TCA8418 keyboard
|
|
#define I2C_NO_RESCAN
|
|
#define KB_BL_PIN 46
|
|
#define KB_INT 6
|
|
|
|
// audio codec ES8311
|
|
#define HAS_I2S
|
|
#define DAC_I2S_BCK 11
|
|
#define DAC_I2S_WS 18
|
|
#define DAC_I2S_DOUT 45
|
|
#define DAC_I2S_DIN 17
|
|
#define DAC_I2S_MCLK 10
|
|
|
|
// gyroscope BHI260AP
|
|
#define HAS_BHI260AP
|
|
|
|
// battery charger BQ25896
|
|
#define HAS_PPM 1
|
|
#define XPOWERS_CHIP_BQ25896
|
|
|
|
// battery quality management BQ27220
|
|
#define HAS_BQ27220 1
|
|
#define BQ27220_I2C_SDA SDA
|
|
#define BQ27220_I2C_SCL SCL
|
|
#define BQ27220_DESIGN_CAPACITY 1500
|
|
|
|
// NFC ST25R3916
|
|
#define NFC_INT 5
|
|
#define NFC_CS 39
|
|
|
|
// External expansion chip XL9555
|
|
#define USE_XL9555
|
|
#define EXPANDS_DRV_EN (0)
|
|
#define EXPANDS_AMP_EN (1)
|
|
#define EXPANDS_KB_RST (2)
|
|
// AudioThread powers the amp on/off around playback via this (opt-in) hook.
|
|
#define AUDIO_AMP_ENABLE(on) io.digitalWrite(EXPANDS_AMP_EN, (on) ? HIGH : LOW)
|
|
#define EXPANDS_LORA_EN (3)
|
|
#define EXPANDS_GPS_EN (4)
|
|
#define EXPANDS_NFC_EN (5)
|
|
#define EXPANDS_GPS_RST (7)
|
|
#define EXPANDS_KB_EN (8)
|
|
#define EXPANDS_GPIO_EN (9)
|
|
#define EXPANDS_SD_DET (10)
|
|
#define EXPANDS_SD_PULLEN (11)
|
|
#define EXPANDS_SD_EN (12)
|
|
|
|
// LoRa
|
|
#define USE_SX1262
|
|
#define USE_SX1268
|
|
#define USE_SX1280
|
|
#define USE_LR1121
|
|
|
|
#define LORA_SCK 35
|
|
#define LORA_MISO 33
|
|
#define LORA_MOSI 34
|
|
#define LORA_CS 36
|
|
#define LORA_RESET 47
|
|
|
|
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
|
#define LORA_DIO1 14 // SX1262 IRQ
|
|
#define LORA_DIO2 48 // SX1262 BUSY
|
|
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
|
|
|
#define SX126X_CS LORA_CS
|
|
#define SX126X_DIO1 LORA_DIO1
|
|
#define SX126X_BUSY LORA_DIO2
|
|
#define SX126X_RESET LORA_RESET
|
|
#define SX126X_DIO2_AS_RF_SWITCH
|
|
#define SX126X_DIO3_TCXO_VOLTAGE 3.0
|
|
|
|
#define SX128X_CS LORA_CS
|
|
#define SX128X_DIO1 LORA_DIO1
|
|
#define SX128X_BUSY LORA_DIO2
|
|
#define SX128X_RESET LORA_RESET
|
|
|
|
#define LR1121_IRQ_PIN LORA_DIO1
|
|
#define LR1121_NRESET_PIN LORA_RESET
|
|
#define LR1121_BUSY_PIN LORA_DIO2
|
|
#define LR1121_SPI_NSS_PIN LORA_CS
|
|
#define LR1121_SPI_SCK_PIN LORA_SCK
|
|
#define LR1121_SPI_MOSI_PIN LORA_MOSI
|
|
#define LR1121_SPI_MISO_PIN LORA_MISO
|
|
#define LR11X0_DIO3_TCXO_VOLTAGE 3.0
|
|
#define LR11X0_DIO_AS_RF_SWITCH
|