From ed5f68f3fa20d14722fcc7aec2c1f8fb031b9ded Mon Sep 17 00:00:00 2001 From: Nickie Deuxyeux Date: Mon, 11 May 2026 13:24:03 +0300 Subject: [PATCH] Added Heltec T096 support --- Boards.h | 90 ++++++++++++++++++++++++++++++++++++++++++++++ Display.h | 65 ++++++++++++++++++++++++++++++--- RNode_Firmware.ino | 2 +- Utilities.h | 15 +++++++- sx126x.cpp | 4 ++- 5 files changed, 169 insertions(+), 7 deletions(-) diff --git a/Boards.h b/Boards.h index 831ebc4..db3221c 100644 --- a/Boards.h +++ b/Boards.h @@ -1209,6 +1209,96 @@ const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT; const int DISPLAY_RST = PIN_T114_TFT_RST; + #elif BOARD_MODEL == BOARD_HELTEC_T096 + #define MODEM SX1262 + #define HAS_EEPROM false + #define HAS_DISPLAY true + #define HAS_BLUETOOTH false + #define HAS_BLE true + #define HAS_CONSOLE false + #define HAS_PMU false + #define HAS_NP false + #define HAS_SD false + #define HAS_TCXO true + #define HAS_BUSY true + #define HAS_INPUT true + #define HAS_SLEEP false + #define DIO2_AS_RF_SWITCH true + #define CONFIG_UART_BUFFER_SIZE 6144 + #define CONFIG_QUEUE_SIZE 6144 + #define CONFIG_QUEUE_MAX_LENGTH 200 + #define EEPROM_SIZE 296 + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED + #define BLE_MANUFACTURER "Heltec" + #define BLE_MODEL "T096" + + #define HAS_LORA_PA true + #define HAS_LORA_LNA true + #define OCP_TUNED 0x28 + #define LORA_PA_MODEL LORA_PA_KCT8103L + #define LNA_GD_THRSHLD (-109) + #define LNA_GD_LIMIT (-89) + + #define LORA_LNA_GAIN 17 + #define LORA_LNA_GVT 12 + #define LORA_PA_PWR_EN 7 + #define LORA_PA_CPS -1 + #define LORA_PA_CSD 12 + #define LORA_PA_CTX 9 + + #define PA_MAX_OUTPUT 28 + #define PA_GAIN_POINTS 22 + + #define LORA_LNA_KCT8103L_GAIN 21 + const int PA_KCT8103L_VALUES[PA_GAIN_POINTS] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7}; + + // LED + #define PIN_T096_LED 28 + + // SPI + #define PIN_T096_MOSI 11 + #define PIN_T096_MISO 14 + #define PIN_T096_SCK 40 + #define PIN_T096_SS 5 + + // SX1262 + #define PIN_T096_RST 16 + #define PIN_T096_DIO1 21 + #define PIN_T096_BUSY 19 + + // TFT + #define DISPLAY_SCALE 1 + #define PIN_T096_TFT_MOSI 17 + #define PIN_T096_TFT_SCK 20 + #define PIN_T096_TFT_SS 22 + #define PIN_T096_TFT_DC 15 + #define PIN_T096_TFT_RST 13 + #define PIN_T096_TFT_EN 26 + #define PIN_T096_TFT_BLGT 44 + + // pins for buttons on Heltec T096 + const int pin_btn_usr1 = 42; + + // pins for sx1262 on Heltec T096 + const int pin_reset = PIN_T096_RST; + const int pin_cs = PIN_T096_SS; + const int pin_sclk = PIN_T096_SCK; + const int pin_mosi = PIN_T096_MOSI; + const int pin_miso = PIN_T096_MISO; + const int pin_busy = PIN_T096_BUSY; + const int pin_dio = PIN_T096_DIO1; + const int pin_led_rx = 28; + const int pin_led_tx = 28; + const int pin_tcxo_enable = -1; + + // pins for ST7735 display on Heltec T096 + const int DISPLAY_DC = PIN_T096_TFT_DC; + const int DISPLAY_CS = PIN_T096_TFT_SS; + const int DISPLAY_MOSI = PIN_T096_TFT_MOSI; + const int DISPLAY_CLK = PIN_T096_TFT_SCK; + const int DISPLAY_BL_PIN = PIN_T096_TFT_BLGT; + const int DISPLAY_RST = PIN_T096_TFT_RST; + #elif BOARD_MODEL == BOARD_PROMICRO //TODO: // - Fix low output power diff --git a/Display.h b/Display.h index f3f7acb..c8faa0a 100644 --- a/Display.h +++ b/Display.h @@ -22,6 +22,9 @@ #elif BOARD_MODEL == BOARD_HELTEC_T114 #include "ST7789.h" #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) + #elif BOARD_MODEL == BOARD_HELTEC_T096 + #include + #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) #elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3 #include #else @@ -154,6 +157,10 @@ Adafruit_ST7789 display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1); #define SSD1306_WHITE ST77XX_WHITE #define SSD1306_BLACK ST77XX_BLACK +#elif BOARD_MODEL == BOARD_HELTEC_T096 + Adafruit_ST7735 display = Adafruit_ST7735(&SPI1, DISPLAY_CS, DISPLAY_DC, DISPLAY_RST); + #define SSD1306_WHITE ST77XX_WHITE + #define SSD1306_BLACK ST77XX_BLACK #elif BOARD_MODEL == BOARD_HELTEC_T114 ST7789Spi display(&SPI1, DISPLAY_RST, DISPLAY_DC, DISPLAY_CS); #define SSD1306_WHITE ST77XX_WHITE @@ -243,6 +250,18 @@ void update_area_positions() { p_as_x = 126; p_as_y = p_ad_y; } + #elif BOARD_MODEL == BOARD_HELTEC_T096 + if (disp_mode == DISP_MODE_LANDSCAPE) { + p_ad_x = 16; + p_ad_y = 8; + p_as_x = 82; + p_as_y = 8; + } else if (disp_mode == DISP_MODE_PORTRAIT) { + p_ad_x = 8; + p_ad_y = 0; + p_as_x = 8; + p_as_y = 64; + } #elif BOARD_MODEL == BOARD_TECHO if (disp_mode == DISP_MODE_PORTRAIT) { p_ad_x = 61; @@ -276,6 +295,11 @@ uint8_t display_contrast = 0x00; } #elif BOARD_MODEL == BOARD_HELTEC_T114 void set_contrast(ST7789Spi *display, uint8_t value) { } +#elif BOARD_MODEL == BOARD_HELTEC_T096 + void set_contrast(Adafruit_ST7735 *display, uint8_t value) { + if (value == 0) { digitalWrite(PIN_T096_TFT_BLGT, HIGH); } + else { digitalWrite(PIN_T096_TFT_BLGT, LOW); } + } #elif BOARD_MODEL == BOARD_TECHO void set_contrast(void *display, uint8_t value) { if (value == 0) { analogWrite(pin_backlight, 0); } @@ -357,6 +381,9 @@ bool display_init() { #elif BOARD_MODEL == BOARD_HELTEC_T114 pinMode(PIN_T114_TFT_EN, OUTPUT); digitalWrite(PIN_T114_TFT_EN, LOW); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + pinMode(PIN_T096_TFT_EN, OUTPUT); + digitalWrite(PIN_T096_TFT_EN, HIGH); #elif BOARD_MODEL == BOARD_MESHADVENTURER_S3 || BOARD_MODEL == BOARD_MESHPOE_S3 Wire.setPins(SDA_OLED, SCL_OLED); Wire.begin(); @@ -431,6 +458,9 @@ bool display_init() { // set white as default pixel colour for Heltec T114 display.setRGB(COLOR565(0xFF, 0xFF, 0xFF)); if (false) { + #elif BOARD_MODEL == BOARD_HELTEC_T096 + display.initR(INITR_MINI160x80); + if (false) { #elif BOARD_MODEL == BOARD_TBEAM_S_V1 || BOARD_MODEL == BOARD_TBEAM_S_V3 if (!display.begin(display_address, true)) { #else @@ -480,6 +510,9 @@ bool display_init() { #elif BOARD_MODEL == BOARD_HELTEC_T114 disp_mode = DISP_MODE_PORTRAIT; display.setRotation(1); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(1); #elif BOARD_MODEL == BOARD_RAK4631 disp_mode = DISP_MODE_LANDSCAPE; display.setRotation(0); @@ -547,6 +580,10 @@ bool display_init() { fillRect(p_as_x, p_as_y, 128, 128, SSD1306_BLACK); pinMode(PIN_T114_TFT_BLGT, OUTPUT); digitalWrite(PIN_T114_TFT_BLGT, LOW); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + display.fillScreen(SSD1306_BLACK); + pinMode(PIN_T096_TFT_BLGT, OUTPUT); + digitalWrite(PIN_T096_TFT_BLGT, LOW); #endif return true; @@ -586,7 +623,21 @@ void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colo // Draws a bitmap to the display and auto scales it based on the boards configured DISPLAY_SCALE void drawBitmap(int16_t startX, int16_t startY, const uint8_t* bitmap, int16_t bitmapWidth, int16_t bitmapHeight, uint16_t foregroundColour, uint16_t backgroundColour) { - #if DISPLAY_SCALE == 1 + #if BOARD_MODEL == BOARD_HELTEC_T096 + { + static uint16_t rowbuf[64]; + int16_t byteWidth = (bitmapWidth + 7) / 8; + display.startWrite(); + display.setAddrWindow(startX, startY, bitmapWidth, bitmapHeight); + for (int16_t row = 0; row < bitmapHeight; row++) { + for (int16_t col = 0; col < bitmapWidth; col++) { + rowbuf[col] = (bitmap[row * byteWidth + col / 8] & (0x80 >> (col % 8))) ? foregroundColour : backgroundColour; + } + display.writePixels(rowbuf, bitmapWidth); + } + display.endWrite(); + } + #elif DISPLAY_SCALE == 1 display.drawBitmap(startX, startY, bitmap, bitmapWidth, bitmapHeight, foregroundColour, backgroundColour); #else for(int16_t row = 0; row < bitmapHeight; row++){ @@ -1142,6 +1193,8 @@ void update_display(bool blank = false) { display.clear(); display.display(); digitalWrite(PIN_T114_TFT_BLGT, HIGH); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + digitalWrite(PIN_T096_TFT_BLGT, HIGH); #elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO display.clearDisplay(); display.display(); @@ -1163,6 +1216,8 @@ void update_display(bool blank = false) { #if BOARD_MODEL == BOARD_HELTEC_T114 display.clear(); digitalWrite(PIN_T114_TFT_BLGT, LOW); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + digitalWrite(PIN_T096_TFT_BLGT, LOW); #elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO display.clearDisplay(); #endif @@ -1188,7 +1243,7 @@ void update_display(bool blank = false) { last_epd_refresh = millis(); epd_blanked = false; } - #elif BOARD_MODEL != BOARD_TDECK + #elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_HELTEC_T096 display.display(); #endif @@ -1200,8 +1255,10 @@ void update_display(bool blank = false) { void display_unblank() { last_unblank_event = millis(); - #if BOARD_MODEL == BOARD_HELTEC_T114 - digitalWrite(PIN_T114_TFT_BLGT, LOW); + #if BOARD_MODEL == BOARD_HELTEC_T114 + digitalWrite(PIN_T114_TFT_BLGT, LOW); + #elif BOARD_MODEL == BOARD_HELTEC_T096 + digitalWrite(PIN_T096_TFT_BLGT, LOW); #endif } diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 848b075..6759e9c 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -135,7 +135,7 @@ void setup() { boot_seq(); #endif - #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_MESHPOE_S3 && BOARD_MODEL != BOARD_MESHADVENTURER_S3 && BOARD_MODEL != BOARD_PROMICRO && BOARD_MODEL != BOARD_AETHERNODE_S3 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_TBEAM_S_V3 && BOARD_MODEL != BOARD_HELTEC32_V4 + #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_HELTEC_T096 && BOARD_MODEL != BOARD_MESHPOE_S3 && BOARD_MODEL != BOARD_MESHADVENTURER_S3 && BOARD_MODEL != BOARD_PROMICRO && BOARD_MODEL != BOARD_AETHERNODE_S3 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_TBEAM_S_V3 && BOARD_MODEL != BOARD_HELTEC32_V4 // Some boards need to wait until the hardware UART is set up before booting // the full firmware. In the case of the RAK4631 and Heltec T114, the line below will wait // until a serial connection is actually established with a master. Thus, it diff --git a/Utilities.h b/Utilities.h index 65b4d87..17800b3 100644 --- a/Utilities.h +++ b/Utilities.h @@ -424,6 +424,14 @@ uint8_t boot_vector = 0x00; void led_tx_off() { digitalWrite(pin_led_tx, HIGH); } void led_id_on() { } void led_id_off() { } + #elif BOARD_MODEL == BOARD_HELTEC_T096 + // Heltec T096 pulls pins HIGH to turn on + void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } + void led_rx_off() { digitalWrite(pin_led_rx, LOW); } + void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } + void led_tx_off() { digitalWrite(pin_led_tx, LOW); } + void led_id_on() { } + void led_id_off() { } #elif BOARD_MODEL == BOARD_TECHO void led_rx_on() { digitalWrite(pin_led_rx, LED_ON); } void led_rx_off() { digitalWrite(pin_led_rx, LED_OFF); } @@ -1353,6 +1361,9 @@ int getTxPower() { #if BOARD_MODEL == BOARD_HELTEC32_V4 bool pa_values_determined = false; int tx_gain[PA_GAIN_POINTS] = {100}; + #elif BOARD_MODEL == BOARD_HELTEC_T096 + bool pa_values_determined = false; + int tx_gain[PA_GAIN_POINTS] = {100}; #else bool pa_values_determined = true; const int tx_gain[PA_GAIN_POINTS] = {PA_GAIN_VALUES}; @@ -1687,7 +1698,7 @@ bool eeprom_product_valid() { #elif PLATFORM == PLATFORM_ESP32 if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_H32_V4 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1 || rval == PRODUCT_TBEAM_S_V3 || rval == PRODUCT_XIAO_S3) { #elif PLATFORM == PLATFORM_NRF52 - if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) { + if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_HELTEC_T096 || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) { #else if (false) { #endif @@ -1737,6 +1748,8 @@ bool eeprom_model_valid() { if (model == MODEL_C8) { #elif BOARD_MODEL == BOARD_HELTEC_T114 if (model == MODEL_C6 || model == MODEL_C7) { + #elif BOARD_MODEL == BOARD_HELTEC_T096 + if (model == MODEL_D3 || model == MODEL_D5) { #elif BOARD_MODEL == BOARD_RAK4631 if (model == MODEL_11 || model == MODEL_12) { #elif BOARD_MODEL == BOARD_HUZZAH32 diff --git a/sx126x.cpp b/sx126x.cpp index ec414e4..2c445b2 100644 --- a/sx126x.cpp +++ b/sx126x.cpp @@ -88,7 +88,7 @@ #define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X) #if BOARD_MODEL == BOARD_TECHO || BOARD_MODEL == BOARD_PROMICRO - SPIClass spim3 = SPIClass(NRF_SPIM3, pin_miso, pin_sclk, pin_mosi) ; + SPIClass spim3 = SPIClass(NRF_SPIM3, pin_miso, pin_sclk, pin_mosi); #define SPI spim3 #elif defined(NRF52840_XXAA) @@ -736,6 +736,8 @@ void sx126x::enableTCXO() { uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_HELTEC_T114 uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; + #elif BOARD_MODEL == BOARD_HELTEC_T096 + uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_TECHO uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_HELTEC32_V4