mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 10:53:17 +00:00
Board Support: Heltec v3 (#407)
This commit is contained in:
parent
0d8c0a37cc
commit
8335611796
1
.github/workflows/build-firmware.yml
vendored
1
.github/workflows/build-firmware.yml
vendored
@ -31,6 +31,7 @@ jobs:
|
|||||||
{ id: elecrow-crowpanel-basic-28, arch: esp32 },
|
{ id: elecrow-crowpanel-basic-28, arch: esp32 },
|
||||||
{ id: elecrow-crowpanel-basic-35, arch: esp32 },
|
{ id: elecrow-crowpanel-basic-35, arch: esp32 },
|
||||||
{ id: elecrow-crowpanel-basic-50, arch: esp32s3 },
|
{ id: elecrow-crowpanel-basic-50, arch: esp32s3 },
|
||||||
|
{ id: heltec-wifi-lora-32-v3, arch: esp32s3 },
|
||||||
{ id: lilygo-tdeck, arch: esp32s3 },
|
{ id: lilygo-tdeck, arch: esp32s3 },
|
||||||
{ id: lilygo-tdongle-s3, arch: esp32s3 },
|
{ id: lilygo-tdongle-s3, arch: esp32s3 },
|
||||||
{ id: lilygo-tdisplay-s3, arch: esp32s3 },
|
{ id: lilygo-tdisplay-s3, arch: esp32s3 },
|
||||||
|
|||||||
7
Boards/heltec-wifi-lora-32-v3/CMakeLists.txt
Normal file
7
Boards/heltec-wifi-lora-32-v3/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||||
|
|
||||||
|
idf_component_register(
|
||||||
|
SRCS ${SOURCE_FILES}
|
||||||
|
INCLUDE_DIRS "Source"
|
||||||
|
REQUIRES Tactility EspLcdCompat SSD1306 ButtonControl EstimatedPower driver
|
||||||
|
)
|
||||||
71
Boards/heltec-wifi-lora-32-v3/Source/Configuration.cpp
Normal file
71
Boards/heltec-wifi-lora-32-v3/Source/Configuration.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "devices/Display.h"
|
||||||
|
#include "devices/Power.h"
|
||||||
|
#include "devices/Constants.h"
|
||||||
|
|
||||||
|
#include <Tactility/hal/Configuration.h>
|
||||||
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
|
#include <ButtonControl.h>
|
||||||
|
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
#include <Tactility/Log.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
static void enableOledPower() {
|
||||||
|
gpio_config_t io_conf = {
|
||||||
|
.pin_bit_mask = (1ULL << DISPLAY_PIN_POWER),
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_DISABLE, // The board has an external pull-up
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
|
};
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
gpio_set_level(DISPLAY_PIN_POWER, 0); // Active low
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(500)); // Add a small delay for power to stabilize
|
||||||
|
TT_LOG_I("OLED_POWER", "OLED power enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool initBoot() {
|
||||||
|
// Enable power to the OLED before doing anything else
|
||||||
|
enableOledPower();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace tt::hal;
|
||||||
|
|
||||||
|
static std::vector<std::shared_ptr<Device>> createDevices() {
|
||||||
|
return {
|
||||||
|
createPower(),
|
||||||
|
ButtonControl::createOneButtonControl(0),
|
||||||
|
createDisplay()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const Configuration hardwareConfiguration = {
|
||||||
|
.initBoot = initBoot,
|
||||||
|
.uiScale = UiScale::Smallest,
|
||||||
|
.createDevices = createDevices,
|
||||||
|
.i2c = {
|
||||||
|
tt::hal::i2c::Configuration {
|
||||||
|
.name = "Internal",
|
||||||
|
.port = DISPLAY_I2C_PORT,
|
||||||
|
.initMode = tt::hal::i2c::InitMode::ByTactility,
|
||||||
|
.isMutable = true,
|
||||||
|
.config = (i2c_config_t) {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = DISPLAY_PIN_SDA,
|
||||||
|
.scl_io_num = DISPLAY_PIN_SCL,
|
||||||
|
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||||
|
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||||
|
.master = {
|
||||||
|
.clk_speed = DISPLAY_I2C_SPEED
|
||||||
|
},
|
||||||
|
.clk_flags = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.spi {},
|
||||||
|
};
|
||||||
16
Boards/heltec-wifi-lora-32-v3/Source/devices/Constants.h
Normal file
16
Boards/heltec-wifi-lora-32-v3/Source/devices/Constants.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#include <driver/i2c.h>
|
||||||
|
#include <driver/spi_common.h>
|
||||||
|
|
||||||
|
// Display
|
||||||
|
constexpr auto DISPLAY_I2C_ADDRESS = 0x3C;
|
||||||
|
constexpr auto DISPLAY_I2C_SPEED = 200000;
|
||||||
|
constexpr auto DISPLAY_I2C_PORT = I2C_NUM_0;
|
||||||
|
constexpr auto DISPLAY_PIN_SDA = GPIO_NUM_17;
|
||||||
|
constexpr auto DISPLAY_PIN_SCL = GPIO_NUM_18;
|
||||||
|
constexpr auto DISPLAY_PIN_RST = GPIO_NUM_21;
|
||||||
|
constexpr auto DISPLAY_HORIZONTAL_RESOLUTION = 128;
|
||||||
|
constexpr auto DISPLAY_VERTICAL_RESOLUTION = 64;
|
||||||
|
constexpr auto DISPLAY_PIN_POWER = GPIO_NUM_36;
|
||||||
19
Boards/heltec-wifi-lora-32-v3/Source/devices/Display.cpp
Normal file
19
Boards/heltec-wifi-lora-32-v3/Source/devices/Display.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include "Display.h"
|
||||||
|
#include "Constants.h"
|
||||||
|
|
||||||
|
#include <Ssd1306Display.h>
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
|
||||||
|
auto configuration = std::make_unique<Ssd1306Display::Configuration>(
|
||||||
|
DISPLAY_I2C_PORT,
|
||||||
|
DISPLAY_I2C_ADDRESS,
|
||||||
|
DISPLAY_PIN_RST,
|
||||||
|
DISPLAY_HORIZONTAL_RESOLUTION,
|
||||||
|
DISPLAY_VERTICAL_RESOLUTION,
|
||||||
|
nullptr, // no touch
|
||||||
|
false // invert
|
||||||
|
);
|
||||||
|
|
||||||
|
auto display = std::make_shared<Ssd1306Display>(std::move(configuration));
|
||||||
|
return std::static_pointer_cast<tt::hal::display::DisplayDevice>(display);
|
||||||
|
}
|
||||||
5
Boards/heltec-wifi-lora-32-v3/Source/devices/Display.h
Normal file
5
Boards/heltec-wifi-lora-32-v3/Source/devices/Display.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
|
||||||
20
Boards/heltec-wifi-lora-32-v3/Source/devices/Power.cpp
Normal file
20
Boards/heltec-wifi-lora-32-v3/Source/devices/Power.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "Power.h"
|
||||||
|
|
||||||
|
#include <ChargeFromAdcVoltage.h>
|
||||||
|
#include <EstimatedPower.h>
|
||||||
|
#include <Tactility/hal/gpio/Gpio.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// ADC enable pin on GPIO37
|
||||||
|
constexpr auto ADC_CTRL = 37;
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::power::PowerDevice> createPower() {
|
||||||
|
ChargeFromAdcVoltage::Configuration configuration;
|
||||||
|
// 2.0 ratio, but +0.11 added as display voltage sag compensation.
|
||||||
|
configuration.adcMultiplier = 2.11;
|
||||||
|
|
||||||
|
// Configure the ADC enable pin as an output
|
||||||
|
tt::hal::gpio::configure(ADC_CTRL, tt::hal::gpio::Mode::Output, false, false);
|
||||||
|
|
||||||
|
return std::make_shared<EstimatedPower>(configuration);
|
||||||
|
}
|
||||||
7
Boards/heltec-wifi-lora-32-v3/Source/devices/Power.h
Normal file
7
Boards/heltec-wifi-lora-32-v3/Source/devices/Power.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::power::PowerDevice> createPower();
|
||||||
@ -86,6 +86,12 @@ vendor=Elecrow
|
|||||||
boardName=CrowPanel Basic 5"
|
boardName=CrowPanel Basic 5"
|
||||||
incubating=false
|
incubating=false
|
||||||
|
|
||||||
|
[heltec-wifi-lora-32-v3]
|
||||||
|
vendor=Heltec
|
||||||
|
boardName=v3
|
||||||
|
incubating=true
|
||||||
|
infoMessage=Due to the small size of the screen, the icons don't render properly.
|
||||||
|
|
||||||
[lilygo-tdeck]
|
[lilygo-tdeck]
|
||||||
vendor=LilyGO
|
vendor=LilyGO
|
||||||
boardName=T-Deck,T-Deck Plus
|
boardName=T-Deck,T-Deck Plus
|
||||||
|
|||||||
5
Drivers/SSD1306/CMakeLists.txt
Normal file
5
Drivers/SSD1306/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
idf_component_register(
|
||||||
|
SRC_DIRS "Source"
|
||||||
|
INCLUDE_DIRS "Source"
|
||||||
|
REQUIRES Tactility driver EspLcdCompat esp_lcd lvgl
|
||||||
|
)
|
||||||
3
Drivers/SSD1306/README.md
Normal file
3
Drivers/SSD1306/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# SSD1306
|
||||||
|
|
||||||
|
A very custom ESP32 LVGL driver for SSD1306 displays.
|
||||||
204
Drivers/SSD1306/Source/Ssd1306Display.cpp
Normal file
204
Drivers/SSD1306/Source/Ssd1306Display.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
#include "Ssd1306Display.h"
|
||||||
|
|
||||||
|
#include <Tactility/Log.h>
|
||||||
|
#include <esp_lcd_panel_commands.h>
|
||||||
|
#include <esp_lcd_panel_dev.h>
|
||||||
|
#include <esp_lcd_panel_ssd1306.h>
|
||||||
|
#include <esp_lvgl_port.h>
|
||||||
|
#include <esp_lcd_panel_ops.h>
|
||||||
|
#include <driver/i2c.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
#define TAG "ssd1306_display"
|
||||||
|
|
||||||
|
// SSD1306 commands
|
||||||
|
#define SSD1306_CMD_SET_CHARGE_PUMP 0x8D
|
||||||
|
#define SSD1306_CMD_SET_SEGMENT_REMAP 0xA0
|
||||||
|
#define SSD1306_CMD_SET_COM_SCAN_DIR 0xC0
|
||||||
|
#define SSD1306_CMD_SET_COM_PIN_CFG 0xDA
|
||||||
|
#define SSD1306_CMD_SET_CONTRAST 0x81
|
||||||
|
#define SSD1306_CMD_SET_PRECHARGE 0xD9
|
||||||
|
#define SSD1306_CMD_SET_VCOMH_DESELECT 0xDB
|
||||||
|
#define SSD1306_CMD_DISPLAY_INVERT 0xA6
|
||||||
|
#define SSD1306_CMD_DISPLAY_ON 0xAF
|
||||||
|
#define SSD1306_CMD_SET_MEMORY_ADDR_MODE 0x20
|
||||||
|
#define SSD1306_CMD_SET_COLUMN_RANGE 0x21
|
||||||
|
#define SSD1306_CMD_SET_PAGE_RANGE 0x22
|
||||||
|
|
||||||
|
// Helper to send I2C commands directly
|
||||||
|
static bool ssd1306_i2c_send_cmd(i2c_port_t port, uint8_t addr, uint8_t cmd) {
|
||||||
|
uint8_t data[2] = {0x00, cmd}; // 0x00 = command mode
|
||||||
|
esp_err_t ret = i2c_master_write_to_device(port, addr, data, sizeof(data), pdMS_TO_TICKS(1000));
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to send command 0x%02X: %d", cmd, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Ssd1306Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
|
||||||
|
const esp_lcd_panel_io_i2c_config_t io_config = {
|
||||||
|
.dev_addr = configuration->deviceAddress,
|
||||||
|
.control_phase_bytes = 1,
|
||||||
|
.dc_bit_offset = 6,
|
||||||
|
.flags = {
|
||||||
|
.dc_low_on_data = false,
|
||||||
|
.disable_control_phase = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)configuration->port, &io_config, &ioHandle) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to create IO handle");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Ssd1306Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
|
||||||
|
// Manual hardware reset with proper timing for Heltec V3
|
||||||
|
if (configuration->resetPin != GPIO_NUM_NC) {
|
||||||
|
gpio_config_t reset_gpio_config = {
|
||||||
|
.pin_bit_mask = 1ULL << configuration->resetPin,
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
|
};
|
||||||
|
gpio_config(&reset_gpio_config);
|
||||||
|
|
||||||
|
gpio_set_level(configuration->resetPin, 0);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
gpio_set_level(configuration->resetPin, 1);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ESP-IDF panel (but don't call init - we'll do custom init)
|
||||||
|
esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = GPIO_NUM_NC, // Already handled above
|
||||||
|
.color_space = ESP_LCD_COLOR_SPACE_MONOCHROME,
|
||||||
|
.bits_per_pixel = 1, // Must be 1 for monochrome
|
||||||
|
.flags = {
|
||||||
|
.reset_active_high = false,
|
||||||
|
},
|
||||||
|
.vendor_config = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||||
|
esp_lcd_panel_ssd1306_config_t ssd1306_config = {
|
||||||
|
.height = static_cast<uint8_t>(configuration->verticalResolution),
|
||||||
|
};
|
||||||
|
panel_config.vendor_config = &ssd1306_config;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (esp_lcd_new_panel_ssd1306(ioHandle, &panel_config, &panelHandle) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Failed to create panel");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't call esp_lcd_panel_init() - it doesn't configure correctly for Heltec V3!
|
||||||
|
// Instead, send our custom initialization sequence directly via I2C
|
||||||
|
|
||||||
|
auto port = configuration->port;
|
||||||
|
auto addr = configuration->deviceAddress;
|
||||||
|
|
||||||
|
TT_LOG_I(TAG, "Sending Heltec V3 custom init sequence");
|
||||||
|
|
||||||
|
// Display off while configuring
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xAE);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10)); // Important: let display stabilize after turning off
|
||||||
|
|
||||||
|
// Set oscillator frequency (MUST come early in sequence)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xD5);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x80);
|
||||||
|
|
||||||
|
// Set multiplex ratio
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xA8);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, configuration->verticalResolution - 1);
|
||||||
|
|
||||||
|
// Set display offset
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xD3);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x00);
|
||||||
|
|
||||||
|
// Set display start line
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x40);
|
||||||
|
|
||||||
|
// Enable charge pump (required for Heltec V3 - must be before memory mode)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_CHARGE_PUMP);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x14); // Enable
|
||||||
|
|
||||||
|
// Horizontal addressing mode
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_MEMORY_ADDR_MODE);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x00);
|
||||||
|
|
||||||
|
// Segment remap (0xA1 for Heltec V3 orientation)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_SEGMENT_REMAP | 0x01);
|
||||||
|
|
||||||
|
// COM scan direction (0xC8 = reversed)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xC8);
|
||||||
|
|
||||||
|
// COM pin configuration
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_COM_PIN_CFG);
|
||||||
|
if (configuration->verticalResolution == 64) {
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x12); // Alternative COM pin config for 64-row displays
|
||||||
|
} else {
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x02); // Sequential COM pin config for 32-row displays
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contrast (0xCF = bright, good for Heltec OLED)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_CONTRAST);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xCF);
|
||||||
|
|
||||||
|
// Precharge period (0xF1 for Heltec OLED)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_PRECHARGE);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xF1);
|
||||||
|
|
||||||
|
// VCOMH deselect level
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_SET_VCOMH_DESELECT);
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0x40);
|
||||||
|
|
||||||
|
// Normal display mode (not inverse/all-on)
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xA6);
|
||||||
|
|
||||||
|
// Invert display (0xA7)
|
||||||
|
// This is what your old working driver did unconditionally
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, 0xA7);
|
||||||
|
|
||||||
|
// Display ON
|
||||||
|
ssd1306_i2c_send_cmd(port, addr, SSD1306_CMD_DISPLAY_ON);
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100)); // Let display stabilize
|
||||||
|
|
||||||
|
TT_LOG_I(TAG, "Heltec V3 display initialized successfully");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lvgl_port_display_cfg_t Ssd1306Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
|
||||||
|
return {
|
||||||
|
.io_handle = ioHandle,
|
||||||
|
.panel_handle = panelHandle,
|
||||||
|
.control_handle = nullptr,
|
||||||
|
.buffer_size = configuration->bufferSize,
|
||||||
|
.double_buffer = false,
|
||||||
|
.trans_size = 0,
|
||||||
|
.hres = configuration->horizontalResolution,
|
||||||
|
.vres = configuration->verticalResolution,
|
||||||
|
.monochrome = true, // ESP-LVGL-port handles the conversion!
|
||||||
|
.rotation = {
|
||||||
|
.swap_xy = false,
|
||||||
|
.mirror_x = false,
|
||||||
|
.mirror_y = false,
|
||||||
|
},
|
||||||
|
.color_format = LV_COLOR_FORMAT_RGB565, // Use RGB565, monochrome flag makes it work!
|
||||||
|
.flags = {
|
||||||
|
.buff_dma = false,
|
||||||
|
.buff_spiram = false,
|
||||||
|
.sw_rotate = false,
|
||||||
|
.swap_bytes = false,
|
||||||
|
.full_refresh = true,
|
||||||
|
.direct_mode = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
90
Drivers/SSD1306/Source/Ssd1306Display.h
Normal file
90
Drivers/SSD1306/Source/Ssd1306Display.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <EspLcdDisplay.h>
|
||||||
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
|
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#include <esp_lcd_panel_io.h>
|
||||||
|
#include <esp_lcd_types.h>
|
||||||
|
|
||||||
|
class Ssd1306Display final : public EspLcdDisplay {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
class Configuration {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Configuration(
|
||||||
|
i2c_port_t port,
|
||||||
|
uint8_t deviceAddress,
|
||||||
|
gpio_num_t resetPin,
|
||||||
|
unsigned int horizontalResolution, // Typically 128
|
||||||
|
unsigned int verticalResolution, // 32 or 64
|
||||||
|
std::shared_ptr<tt::hal::touch::TouchDevice> touch = nullptr,
|
||||||
|
bool invertColor = false
|
||||||
|
) : port(port),
|
||||||
|
deviceAddress(deviceAddress),
|
||||||
|
resetPin(resetPin),
|
||||||
|
horizontalResolution(horizontalResolution),
|
||||||
|
verticalResolution(verticalResolution),
|
||||||
|
invertColor(invertColor),
|
||||||
|
touch(std::move(touch))
|
||||||
|
{}
|
||||||
|
|
||||||
|
i2c_port_t port;
|
||||||
|
uint8_t deviceAddress;
|
||||||
|
gpio_num_t resetPin = GPIO_NUM_NC;
|
||||||
|
unsigned int horizontalResolution;
|
||||||
|
unsigned int verticalResolution;
|
||||||
|
bool invertColor = false;
|
||||||
|
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
|
||||||
|
uint32_t bufferSize = 0; // Size in pixel count. 0 means default (full screen / 8)
|
||||||
|
int gapX = 0; // Column offset
|
||||||
|
int gapY = 0; // Not used for SSD1306
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::unique_ptr<Configuration> configuration;
|
||||||
|
|
||||||
|
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
|
||||||
|
|
||||||
|
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
|
||||||
|
|
||||||
|
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Ssd1306Display(std::unique_ptr<Configuration> inConfiguration) :
|
||||||
|
EspLcdDisplay(nullptr),
|
||||||
|
configuration(std::move(inConfiguration))
|
||||||
|
{
|
||||||
|
assert(configuration != nullptr);
|
||||||
|
if (configuration->bufferSize == 0) {
|
||||||
|
// For monochrome displays, ESP-LVGL-PORT expects full pixel count
|
||||||
|
// It handles the monochrome conversion internally
|
||||||
|
configuration->bufferSize = configuration->horizontalResolution * configuration->verticalResolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getName() const override { return "SSD1306"; }
|
||||||
|
|
||||||
|
std::string getDescription() const override { return "SSD1306 monochrome OLED display with ESP-LVGL-PORT monochrome support"; }
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
|
||||||
|
|
||||||
|
void setBacklightDuty(uint8_t backlightDuty) override {
|
||||||
|
// SSD1306 does not have backlight control
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supportsBacklightDuty() const override { return false; }
|
||||||
|
|
||||||
|
void setGammaCurve(uint8_t index) override {
|
||||||
|
// SSD1306 does not support gamma curves
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getGammaCurveCount() const override { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
|
||||||
@ -43,6 +43,8 @@ menu "Tactility App"
|
|||||||
bool "Elecrow CrowPanel Basic 3.5"
|
bool "Elecrow CrowPanel Basic 3.5"
|
||||||
config TT_BOARD_ELECROW_CROWPANEL_BASIC_50
|
config TT_BOARD_ELECROW_CROWPANEL_BASIC_50
|
||||||
bool "Elecrow CrowPanel Basic 5.0"
|
bool "Elecrow CrowPanel Basic 5.0"
|
||||||
|
config TT_BOARD_HELTEC_V3
|
||||||
|
bool "Heltec v3"
|
||||||
config TT_BOARD_LILYGO_TDECK
|
config TT_BOARD_LILYGO_TDECK
|
||||||
bool "LilyGo T-Deck"
|
bool "LilyGo T-Deck"
|
||||||
config TT_BOARD_LILYGO_TDONGLE_S3
|
config TT_BOARD_LILYGO_TDONGLE_S3
|
||||||
|
|||||||
@ -38,10 +38,22 @@ class LauncherApp final : public App {
|
|||||||
lv_obj_set_style_shadow_width(apps_button, 0, LV_STATE_DEFAULT);
|
lv_obj_set_style_shadow_width(apps_button, 0, LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_bg_opa(apps_button, 0, LV_STATE_DEFAULT);
|
lv_obj_set_style_bg_opa(apps_button, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
|
// create the image first
|
||||||
auto* button_image = lv_image_create(apps_button);
|
auto* button_image = lv_image_create(apps_button);
|
||||||
lv_image_set_src(button_image, imageFile);
|
lv_image_set_src(button_image, imageFile);
|
||||||
|
|
||||||
|
// Recolor handling:
|
||||||
|
// For color builds use theme primary color
|
||||||
|
// For 1-bit/monochrome builds force a visible color (black)
|
||||||
|
#if LV_COLOR_DEPTH == 1
|
||||||
|
// Try forcing black recolor on monochrome builds
|
||||||
|
lv_obj_set_style_image_recolor(button_image, lv_color_black(), LV_STATE_DEFAULT);
|
||||||
|
lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, LV_STATE_DEFAULT);
|
||||||
|
#else
|
||||||
lv_obj_set_style_image_recolor(button_image, lv_theme_get_color_primary(parent), LV_STATE_DEFAULT);
|
lv_obj_set_style_image_recolor(button_image, lv_theme_get_color_primary(parent), LV_STATE_DEFAULT);
|
||||||
lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, LV_STATE_DEFAULT);
|
lv_obj_set_style_image_recolor_opa(button_image, LV_OPA_COVER, LV_STATE_DEFAULT);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Ensure buttons are still tappable when the asset fails to load
|
// Ensure buttons are still tappable when the asset fails to load
|
||||||
// Icon images are 40x40, so we get some extra padding too
|
// Icon images are 40x40, so we get some extra padding too
|
||||||
lv_obj_set_size(button_image, button_size, button_size);
|
lv_obj_set_size(button_image, button_size, button_size);
|
||||||
|
|||||||
59
sdkconfig.board.heltec-wifi-lora-32-v3
Normal file
59
sdkconfig.board.heltec-wifi-lora-32-v3
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Software defaults
|
||||||
|
# Increase stack size for WiFi (fixes crash after scan)
|
||||||
|
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072
|
||||||
|
CONFIG_ESP_MAIN_TASK_STACK_SIZE=6144
|
||||||
|
CONFIG_LV_FONT_MONTSERRAT_14=y
|
||||||
|
CONFIG_LV_FONT_MONTSERRAT_18=y
|
||||||
|
CONFIG_LV_USE_USER_DATA=y
|
||||||
|
CONFIG_LV_USE_FS_STDIO=y
|
||||||
|
CONFIG_LV_FS_STDIO_LETTER=65
|
||||||
|
CONFIG_LV_FS_STDIO_PATH=""
|
||||||
|
CONFIG_LV_FS_STDIO_CACHE_SIZE=4096
|
||||||
|
CONFIG_LV_USE_LODEPNG=y
|
||||||
|
CONFIG_LV_USE_BUILTIN_MALLOC=n
|
||||||
|
CONFIG_LV_USE_CLIB_MALLOC=y
|
||||||
|
CONFIG_LV_USE_MSGBOX=n
|
||||||
|
CONFIG_LV_USE_SPINNER=n
|
||||||
|
CONFIG_LV_USE_WIN=n
|
||||||
|
CONFIG_LV_USE_SNAPSHOT=y
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
|
||||||
|
CONFIG_FREERTOS_SMP=n
|
||||||
|
CONFIG_FREERTOS_UNICORE=n
|
||||||
|
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=5120
|
||||||
|
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||||
|
CONFIG_FATFS_LFN_HEAP=y
|
||||||
|
CONFIG_FATFS_VOLUME_COUNT=3
|
||||||
|
CONFIG_FATFS_SECTOR_512=y
|
||||||
|
CONFIG_WL_SECTOR_SIZE_512=y
|
||||||
|
CONFIG_WL_SECTOR_SIZE=512
|
||||||
|
CONFIG_WL_SECTOR_MODE_SAFE=y
|
||||||
|
CONFIG_WL_SECTOR_MODE=1
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
|
||||||
|
|
||||||
|
# Hardware: Main
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-8mb.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions-8mb.csv"
|
||||||
|
CONFIG_TT_BOARD_HELTEC_V3=y
|
||||||
|
CONFIG_TT_BOARD_NAME="Heltec v3"
|
||||||
|
CONFIG_TT_BOARD_ID="heltec-wifi-lora-32-v3"
|
||||||
|
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||||
|
CONFIG_IDF_TARGET="esp32s3"
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
# Hardware: No PSRAM
|
||||||
|
# SPI Flash (can set back to 80MHz after ESP-IDF bug is resolved)
|
||||||
|
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||||
|
# LVGL
|
||||||
|
CONFIG_LV_DPI_DEF=90
|
||||||
|
CONFIG_LV_DISP_DEF_REFR_PERIOD=10
|
||||||
|
CONFIG_LV_THEME_DEFAULT_DARK=y
|
||||||
|
CONFIG_LV_COLOR_DEPTH=1
|
||||||
|
CONFIG_LV_USE_THEME_MONO=y
|
||||||
|
CONFIG_LV_LOG_LEVEL=LV_LOG_LEVEL_TRACE
|
||||||
|
# USB
|
||||||
|
CONFIG_TINYUSB_MSC_ENABLED=y
|
||||||
|
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
|
||||||
Loading…
x
Reference in New Issue
Block a user