unPhone implementation and more (#169)
- Implemented [unPhone](https://unphone.net/) v9 board - Updated `.clang-format` to better reflect the intended code style - Fix SD card compatibility issues for all boards (frequency wasn't set well) - Moved `I2cDevice` class from CoreS3 board project to TactilityHeadless project - Tactility configuration now has default empty lists for apps and services fields - Fix for Launcher app: we don't need padding when showing it vertically - Fix for I2cDevice read/write calls that checked for `esp_err_t` instead of `bool` - Fix for TinyUSB init that checked for `esp_err_t` instead of `bool`
This commit is contained in:
parent
3ea02d912f
commit
72230129bb
@ -5,6 +5,7 @@ AccessModifierOffset: -4
|
|||||||
AlignAfterOpenBracket: BlockIndent
|
AlignAfterOpenBracket: BlockIndent
|
||||||
AlignConsecutiveAssignments: None
|
AlignConsecutiveAssignments: None
|
||||||
AlignOperands: DontAlign
|
AlignOperands: DontAlign
|
||||||
|
AlignTrailingComments: false
|
||||||
AllowAllArgumentsOnNextLine: false
|
AllowAllArgumentsOnNextLine: false
|
||||||
AllowAllConstructorInitializersOnNextLine: false
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
AllowAllParametersOfDeclarationOnNextLine: false
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
@ -37,6 +38,8 @@ BreakInheritanceList: BeforeColon
|
|||||||
ColumnLimit: 0
|
ColumnLimit: 0
|
||||||
CompactNamespaces: false
|
CompactNamespaces: false
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
|
EmptyLineBeforeAccessModifier: Always
|
||||||
|
EmptyLineAfterAccessModifier: Always
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentPPDirectives: None
|
IndentPPDirectives: None
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
|
|||||||
9
.github/workflows/build-firmware.yml
vendored
9
.github/workflows/build-firmware.yml
vendored
@ -40,3 +40,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
board_id: m5stack-cores3
|
board_id: m5stack-cores3
|
||||||
arch: esp32s3
|
arch: esp32s3
|
||||||
|
unphone:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: "Build"
|
||||||
|
uses: ./.github/actions/build-firmware
|
||||||
|
with:
|
||||||
|
board_id: unphone
|
||||||
|
arch: esp32s3
|
||||||
|
|||||||
@ -14,6 +14,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
list(APPEND BOARD_COMPONENTS
|
list(APPEND BOARD_COMPONENTS
|
||||||
LilygoTdeck
|
LilygoTdeck
|
||||||
M5stackCoreS3
|
M5stackCoreS3
|
||||||
|
UnPhone
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,8 @@ menu "Tactility App"
|
|||||||
bool "M5Stack Core2"
|
bool "M5Stack Core2"
|
||||||
config TT_BOARD_M5STACK_CORES3
|
config TT_BOARD_M5STACK_CORES3
|
||||||
bool "M5Stack CoreS3"
|
bool "M5Stack CoreS3"
|
||||||
|
config TT_BOARD_UNPHONE
|
||||||
|
bool "unPhone"
|
||||||
help
|
help
|
||||||
Select a board/hardware configuration.
|
Select a board/hardware configuration.
|
||||||
Use TT_BOARD_CUSTOM if you will manually configure the board in your project.
|
Use TT_BOARD_CUSTOM if you will manually configure the board in your project.
|
||||||
|
|||||||
@ -16,6 +16,9 @@
|
|||||||
#elif defined(CONFIG_TT_BOARD_M5STACK_CORES3)
|
#elif defined(CONFIG_TT_BOARD_M5STACK_CORES3)
|
||||||
#include "M5stackCoreS3.h"
|
#include "M5stackCoreS3.h"
|
||||||
#define TT_BOARD_HARDWARE &m5stack_cores3
|
#define TT_BOARD_HARDWARE &m5stack_cores3
|
||||||
|
#elif defined(CONFIG_TT_BOARD_UNPHONE)
|
||||||
|
#include "UnPhone.h"
|
||||||
|
#define TT_BOARD_HARDWARE &unPhone
|
||||||
#else
|
#else
|
||||||
#define TT_BOARD_HARDWARE NULL
|
#define TT_BOARD_HARDWARE NULL
|
||||||
#error Replace TT_BOARD_HARDWARE in main.c with your own. Or copy one of the ./sdkconfig.board.* files into ./sdkconfig.
|
#error Replace TT_BOARD_HARDWARE in main.c with your own. Or copy one of the ./sdkconfig.board.* files into ./sdkconfig.
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
espressif/esp_lcd_ili9341: "2.0.0"
|
espressif/esp_lcd_ili9341: "2.0.0"
|
||||||
|
espressif/esp_lcd_touch: "1.1.2"
|
||||||
|
atanisoft/esp_lcd_touch_xpt2046: "1.0.5"
|
||||||
espressif/esp_lcd_touch_cst816s: "1.0.3"
|
espressif/esp_lcd_touch_cst816s: "1.0.3"
|
||||||
espressif/esp_lcd_touch_gt911: "1.1.1~2"
|
espressif/esp_lcd_touch_gt911: "1.1.1~2"
|
||||||
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
|
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
|
||||||
espressif/esp_lcd_touch: "1.1.2"
|
espressif/esp_io_expander: "1.0.1"
|
||||||
|
espressif/esp_io_expander_tca95xx_16bit: "1.0.1"
|
||||||
espressif/esp_tinyusb:
|
espressif/esp_tinyusb:
|
||||||
version: "1.5.0"
|
version: "1.5.0"
|
||||||
rules:
|
rules:
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
#include <sdmmc_cmd.h>
|
#include <sdmmc_cmd.h>
|
||||||
|
|
||||||
#define TDECK_SDCARD_SPI_FREQUENCY 800000U
|
#define TDECK_SDCARD_SPI_FREQUENCY 20000000U
|
||||||
#define TDECK_SDCARD_PIN_CS GPIO_NUM_39
|
#define TDECK_SDCARD_PIN_CS GPIO_NUM_39
|
||||||
#define TDECK_LCD_PIN_CS GPIO_NUM_12
|
#define TDECK_LCD_PIN_CS GPIO_NUM_12
|
||||||
#define TDECK_RADIO_PIN_CS GPIO_NUM_9
|
#define TDECK_RADIO_PIN_CS GPIO_NUM_9
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
|
|
||||||
#define CORE2_SDCARD_SPI_FREQUENCY 800000U
|
#define CORE2_SDCARD_SPI_FREQUENCY 20000000U
|
||||||
#define CORE2_SDCARD_PIN_CS GPIO_NUM_4
|
#define CORE2_SDCARD_PIN_CS GPIO_NUM_4
|
||||||
#define CORE2_LCD_PIN_CS GPIO_NUM_5
|
#define CORE2_LCD_PIN_CS GPIO_NUM_5
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRC_DIRS "Source" "Source/hal" "Source/Axp2101" "Source/Aw9523" "Source/I2cDevice"
|
SRC_DIRS "Source" "Source/hal" "Source/Axp2101" "Source/Aw9523"
|
||||||
INCLUDE_DIRS "Source"
|
INCLUDE_DIRS "Source"
|
||||||
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 esp_lcd_touch_ft5x06 driver vfs fatfs
|
REQUIRES Tactility esp_lvgl_port esp_lcd esp_lcd_ili9341 esp_lcd_touch_ft5x06 driver vfs fatfs
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "I2cDevice/I2cDevice.h"
|
#include "hal/i2c/I2cDevice.h"
|
||||||
|
|
||||||
#define AW9523_ADDRESS 0x58
|
#define AW9523_ADDRESS 0x58
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hal/i2c/I2c.h"
|
#include "hal/i2c/I2cDevice.h"
|
||||||
#include "I2cDevice/I2cDevice.h"
|
|
||||||
|
|
||||||
#define AXP2101_ADDRESS 0x34
|
#define AXP2101_ADDRESS 0x34
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
|
|
||||||
#define CORES3_SDCARD_SPI_FREQUENCY 800000U
|
#define CORES3_SDCARD_SPI_FREQUENCY 20000000U
|
||||||
#define CORES3_SDCARD_PIN_CS GPIO_NUM_4
|
#define CORES3_SDCARD_PIN_CS GPIO_NUM_4
|
||||||
#define CORES3_LCD_PIN_CS GPIO_NUM_3
|
#define CORES3_LCD_PIN_CS GPIO_NUM_3
|
||||||
|
|
||||||
|
|||||||
5
Boards/UnPhone/CMakeLists.txt
Normal file
5
Boards/UnPhone/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
idf_component_register(
|
||||||
|
SRC_DIRS "Source" "Source/hal" "Source/hx8357" "Source/bq24295"
|
||||||
|
INCLUDE_DIRS "Source"
|
||||||
|
REQUIRES Tactility esp_lvgl_port esp_io_expander esp_io_expander_tca95xx_16bit esp_lcd_touch esp_lcd_touch_xpt2046
|
||||||
|
)
|
||||||
46
Boards/UnPhone/Source/InitHardware.cpp
Normal file
46
Boards/UnPhone/Source/InitHardware.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "TactilityCore.h"
|
||||||
|
#include "hal/UnPhoneDisplayConstants.h"
|
||||||
|
#include "hx8357/disp_spi.h"
|
||||||
|
#include <driver/spi_common.h>
|
||||||
|
#include <soc/gpio_num.h>
|
||||||
|
#include <lvgl.h>
|
||||||
|
|
||||||
|
#define TAG "unphone"
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
#define UNPHONE_SPI_HOST SPI2_HOST
|
||||||
|
#define UNPHONE_SPI_PIN_SCLK GPIO_NUM_39
|
||||||
|
#define UNPHONE_SPI_PIN_MOSI GPIO_NUM_40
|
||||||
|
#define UNPHONE_SPI_PIN_MISO GPIO_NUM_41
|
||||||
|
#define UNPHONE_SPI_TRANSFER_SIZE_LIMIT (UNPHONE_LCD_HORIZONTAL_RESOLUTION * UNPHONE_LCD_SPI_TRANSFER_HEIGHT * LV_COLOR_DEPTH / 8)
|
||||||
|
|
||||||
|
static bool initSpi() {
|
||||||
|
TT_LOG_I(TAG, LOG_MESSAGE_SPI_INIT_START_FMT, UNPHONE_SPI_HOST);
|
||||||
|
|
||||||
|
spi_bus_config_t bus_config = {
|
||||||
|
.mosi_io_num = UNPHONE_SPI_PIN_MOSI,
|
||||||
|
.miso_io_num = UNPHONE_SPI_PIN_MISO,
|
||||||
|
.sclk_io_num = UNPHONE_SPI_PIN_SCLK,
|
||||||
|
.quadwp_io_num = -1, // Quad SPI LCD driver is not yet supported
|
||||||
|
.quadhd_io_num = -1, // Quad SPI LCD driver is not yet supported
|
||||||
|
.data4_io_num = 0,
|
||||||
|
.data5_io_num = 0,
|
||||||
|
.data6_io_num = 0,
|
||||||
|
.data7_io_num = 0,
|
||||||
|
.max_transfer_sz = UNPHONE_SPI_TRANSFER_SIZE_LIMIT,
|
||||||
|
.flags = 0,
|
||||||
|
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO,
|
||||||
|
.intr_flags = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (spi_bus_initialize(UNPHONE_SPI_HOST, &bus_config, SPI_DMA_CH_AUTO) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, LOG_MESSAGE_SPI_INIT_FAILED_FMT, UNPHONE_SPI_HOST);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unPhoneInitHardware() {
|
||||||
|
return initSpi();
|
||||||
|
}
|
||||||
33
Boards/UnPhone/Source/Lvgl.cpp
Normal file
33
Boards/UnPhone/Source/Lvgl.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "Log.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "lvgl/LvglSync.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
#include "hal/UnPhoneDisplay.h"
|
||||||
|
|
||||||
|
#define TAG "unphone_lvgl"
|
||||||
|
|
||||||
|
// LVGL
|
||||||
|
// The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios
|
||||||
|
// At 8192, it sometimes crashes when wifi-auto enables and is busy connecting and then you open WifiManage
|
||||||
|
#define UNPHONE_LVGL_TASK_STACK_DEPTH 9216
|
||||||
|
|
||||||
|
bool unPhoneInitLvgl() {
|
||||||
|
static lv_disp_t* display = nullptr;
|
||||||
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
|
.task_priority = static_cast<UBaseType_t>(tt::THREAD_PRIORITY_RENDER),
|
||||||
|
.task_stack = UNPHONE_LVGL_TASK_STACK_DEPTH,
|
||||||
|
.task_affinity = -1, // core pinning
|
||||||
|
.task_max_sleep_ms = 500,
|
||||||
|
.timer_period_ms = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
TT_LOG_D(TAG, "LVGL port init");
|
||||||
|
if (lvgl_port_init(&lvgl_cfg) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "LVGL port init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
97
Boards/UnPhone/Source/PowerOn.cpp
Normal file
97
Boards/UnPhone/Source/PowerOn.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include "TactilityCore.h"
|
||||||
|
#include "UnPhoneFeatures.h"
|
||||||
|
#include <esp_sleep.h>
|
||||||
|
|
||||||
|
#define TAG "unphone"
|
||||||
|
|
||||||
|
extern UnPhoneFeatures unPhoneFeatures;
|
||||||
|
|
||||||
|
static std::unique_ptr<tt::Thread> powerThread;
|
||||||
|
|
||||||
|
static void updatePowerSwitch() {
|
||||||
|
static bool last_on_state = true;
|
||||||
|
|
||||||
|
if (!unPhoneFeatures.isPowerSwitchOn()) {
|
||||||
|
if (last_on_state) {
|
||||||
|
TT_LOG_W(TAG, "Power off");
|
||||||
|
}
|
||||||
|
|
||||||
|
unPhoneFeatures.turnPeripheralsOff();
|
||||||
|
|
||||||
|
if (!unPhoneFeatures.isUsbPowerConnected()) { // and usb unplugged we go into shipping mode
|
||||||
|
if (last_on_state) {
|
||||||
|
TT_LOG_W(TAG, "Shipping mode until USB connects");
|
||||||
|
unPhoneFeatures.setShipping(true); // tell BM to stop supplying power until USB connects
|
||||||
|
}
|
||||||
|
} else { // power switch off and usb plugged in we sleep
|
||||||
|
unPhoneFeatures.wakeOnPowerSwitch();
|
||||||
|
esp_sleep_enable_timer_wakeup(60000000); // ea min: USB? else->shipping
|
||||||
|
esp_deep_sleep_start(); // deep sleep, wait for wakeup on GPIO
|
||||||
|
}
|
||||||
|
|
||||||
|
last_on_state = false;
|
||||||
|
} else {
|
||||||
|
if (!last_on_state) {
|
||||||
|
TT_LOG_W(TAG, "Power on");
|
||||||
|
unPhoneFeatures.setShipping(false);
|
||||||
|
}
|
||||||
|
last_on_state = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t powerSwitchMain(void*) { // check power switch every 10th of sec
|
||||||
|
while (true) {
|
||||||
|
updatePowerSwitch();
|
||||||
|
tt::kernel::delayMillis(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startPowerSwitchThread() {
|
||||||
|
powerThread = std::make_unique<tt::Thread>(
|
||||||
|
"unphone_power_switch",
|
||||||
|
4096,
|
||||||
|
powerSwitchMain,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
powerThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool unPhonePowerOn() {
|
||||||
|
if (!unPhoneFeatures.init()) {
|
||||||
|
TT_LOG_E(TAG, "UnPhoneFeatures init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unPhoneFeatures.printInfo();
|
||||||
|
|
||||||
|
updatePowerSwitch();
|
||||||
|
startPowerSwitchThread();
|
||||||
|
|
||||||
|
unPhoneFeatures.setBacklightPower(false);
|
||||||
|
|
||||||
|
// Init touch screen GPIOs (used for vibe motor)
|
||||||
|
unPhoneFeatures.setVibePower(false);
|
||||||
|
|
||||||
|
unPhoneFeatures.setIrPower(false);
|
||||||
|
|
||||||
|
// This will be default LOW implicitly, but this makes it explicit
|
||||||
|
unPhoneFeatures.setExpanderPower(false);
|
||||||
|
|
||||||
|
// Vibrate once
|
||||||
|
unPhoneFeatures.setVibePower(true);
|
||||||
|
tt::kernel::delayMillis(150);
|
||||||
|
unPhoneFeatures.setVibePower(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unPhoneInitPower() {
|
||||||
|
ESP_LOGI(TAG, LOG_MESSAGE_POWER_ON_START);
|
||||||
|
|
||||||
|
if (!unPhonePowerOn()) {
|
||||||
|
TT_LOG_E(TAG, LOG_MESSAGE_POWER_ON_FAILED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
57
Boards/UnPhone/Source/UnPhone.cpp
Normal file
57
Boards/UnPhone/Source/UnPhone.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include "UnPhoneFeatures.h"
|
||||||
|
#include "hal/Configuration.h"
|
||||||
|
#include "hal/UnPhoneDisplay.h"
|
||||||
|
#include "hal/UnPhoneSdCard.h"
|
||||||
|
|
||||||
|
bool unPhoneInitPower();
|
||||||
|
bool unPhoneInitHardware();
|
||||||
|
bool unPhoneInitLvgl();
|
||||||
|
|
||||||
|
// Shared object, used in PowerOn and UnPhoneDisplay
|
||||||
|
UnPhoneFeatures unPhoneFeatures;
|
||||||
|
|
||||||
|
extern const tt::hal::Configuration unPhone = {
|
||||||
|
.initBoot = unPhoneInitPower,
|
||||||
|
.initHardware = unPhoneInitHardware,
|
||||||
|
.initLvgl = unPhoneInitLvgl,
|
||||||
|
.createDisplay = createDisplay,
|
||||||
|
.sdcard = createUnPhoneSdCard(),
|
||||||
|
.i2c = {
|
||||||
|
tt::hal::i2c::Configuration {
|
||||||
|
.name = "Internal",
|
||||||
|
.port = I2C_NUM_0,
|
||||||
|
.initMode = tt::hal::i2c::InitMode::ByTactility,
|
||||||
|
.canReinit = false,
|
||||||
|
.hasMutableConfiguration = false,
|
||||||
|
.config = (i2c_config_t) {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = GPIO_NUM_3,
|
||||||
|
.scl_io_num = GPIO_NUM_4,
|
||||||
|
.sda_pullup_en = true,
|
||||||
|
.scl_pullup_en = true,
|
||||||
|
.master = {
|
||||||
|
.clk_speed = 400000
|
||||||
|
},
|
||||||
|
.clk_flags = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tt::hal::i2c::Configuration {
|
||||||
|
.name = "Unused",
|
||||||
|
.port = I2C_NUM_1,
|
||||||
|
.initMode = tt::hal::i2c::InitMode::Disabled,
|
||||||
|
.canReinit = true,
|
||||||
|
.hasMutableConfiguration = true,
|
||||||
|
.config = (i2c_config_t) {
|
||||||
|
.mode = I2C_MODE_MASTER,
|
||||||
|
.sda_io_num = GPIO_NUM_NC,
|
||||||
|
.scl_io_num = GPIO_NUM_NC,
|
||||||
|
.sda_pullup_en = false,
|
||||||
|
.scl_pullup_en = false,
|
||||||
|
.master = {
|
||||||
|
.clk_speed = 400000
|
||||||
|
},
|
||||||
|
.clk_flags = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
5
Boards/UnPhone/Source/UnPhone.h
Normal file
5
Boards/UnPhone/Source/UnPhone.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hal/Configuration.h>
|
||||||
|
|
||||||
|
extern const tt::hal::Configuration unPhone;
|
||||||
279
Boards/UnPhone/Source/UnPhoneFeatures.cpp
Normal file
279
Boards/UnPhone/Source/UnPhoneFeatures.cpp
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
#include "UnPhoneFeatures.h"
|
||||||
|
#include "FreeRTOS-Kernel/include/FreeRTOS.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "service/loader/Loader.h"
|
||||||
|
#include <driver/gpio.h>
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
#include <esp_sleep.h>
|
||||||
|
|
||||||
|
namespace pin {
|
||||||
|
static const gpio_num_t BUTTON1 = GPIO_NUM_45; // left button
|
||||||
|
static const gpio_num_t BUTTON2 = GPIO_NUM_0; // middle button
|
||||||
|
static const gpio_num_t BUTTON3 = GPIO_NUM_21; // right button
|
||||||
|
static const gpio_num_t IR_LEDS = GPIO_NUM_12;
|
||||||
|
static const gpio_num_t LED_RED = GPIO_NUM_13;
|
||||||
|
static const gpio_num_t POWER_SWITCH = GPIO_NUM_18;
|
||||||
|
} // namespace pin
|
||||||
|
|
||||||
|
namespace expanderpin {
|
||||||
|
static const esp_io_expander_pin_num_t BACKLIGHT = IO_EXPANDER_PIN_NUM_2;
|
||||||
|
static const esp_io_expander_pin_num_t EXPANDER_POWER = IO_EXPANDER_PIN_NUM_0; // enable exp brd if high
|
||||||
|
static const esp_io_expander_pin_num_t LED_GREEN = IO_EXPANDER_PIN_NUM_9;
|
||||||
|
static const esp_io_expander_pin_num_t LED_BLUE = IO_EXPANDER_PIN_NUM_13;
|
||||||
|
static const esp_io_expander_pin_num_t USB_VSENSE = IO_EXPANDER_PIN_NUM_14;
|
||||||
|
static const esp_io_expander_pin_num_t VIBE = IO_EXPANDER_PIN_NUM_7;
|
||||||
|
} // namespace expanderpin
|
||||||
|
|
||||||
|
#define TAG "unhpone_features"
|
||||||
|
|
||||||
|
// TODO: Make part of a new type of UnPhoneFeatures data struct that holds all the thread-related data
|
||||||
|
QueueHandle_t interruptQueue;
|
||||||
|
|
||||||
|
static void IRAM_ATTR navButtonInterruptHandler(void* args) {
|
||||||
|
int pinNumber = (int)args;
|
||||||
|
xQueueSendFromISR(interruptQueue, &pinNumber, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t buttonHandlingThreadMain(void* context) {
|
||||||
|
auto* interrupted = (bool*)context;
|
||||||
|
int pinNumber;
|
||||||
|
while (!*interrupted) {
|
||||||
|
if (xQueueReceive(interruptQueue, &pinNumber, portMAX_DELAY)) {
|
||||||
|
TT_LOG_I(TAG, "Pressed button %d", pinNumber);
|
||||||
|
if (pinNumber == pin::BUTTON1) {
|
||||||
|
tt::service::loader::stopApp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnPhoneFeatures::~UnPhoneFeatures() {
|
||||||
|
if (buttonHandlingThread.getState() != tt::Thread::State::Stopped) {
|
||||||
|
buttonHandlingThreadInterruptRequest = true;
|
||||||
|
buttonHandlingThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::initPowerSwitch() {
|
||||||
|
uint64_t power_pin_mask = BIT64(pin::POWER_SWITCH);
|
||||||
|
|
||||||
|
gpio_config_t power_gpio_config = {
|
||||||
|
.pin_bit_mask = power_pin_mask,
|
||||||
|
.mode = GPIO_MODE_INPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_POSEDGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gpio_config(&power_gpio_config) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Power pin init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtc_gpio_pullup_en(pin::POWER_SWITCH) == ESP_OK &&
|
||||||
|
rtc_gpio_pulldown_en(pin::POWER_SWITCH) == ESP_OK) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
TT_LOG_E(TAG, "Failed to set RTC for power switch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::initNavButtons() {
|
||||||
|
interruptQueue = xQueueCreate(4, sizeof(int));
|
||||||
|
|
||||||
|
buttonHandlingThread.setName("unphone_buttons");
|
||||||
|
buttonHandlingThread.setPriority(tt::Thread::Priority::High);
|
||||||
|
buttonHandlingThread.setStackSize(3072);
|
||||||
|
buttonHandlingThread.setCallback(buttonHandlingThreadMain, &buttonHandlingThreadInterruptRequest);
|
||||||
|
buttonHandlingThread.start();
|
||||||
|
|
||||||
|
uint64_t input_pin_mask =
|
||||||
|
BIT64(pin::BUTTON1) |
|
||||||
|
BIT64(pin::BUTTON2) |
|
||||||
|
BIT64(pin::BUTTON3);
|
||||||
|
|
||||||
|
gpio_config_t input_gpio_config = {
|
||||||
|
.pin_bit_mask = input_pin_mask,
|
||||||
|
.mode = GPIO_MODE_INPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_NEGEDGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gpio_config(&input_gpio_config) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Nav button pin init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
gpio_install_isr_service(0) != ESP_OK ||
|
||||||
|
gpio_isr_handler_add(pin::BUTTON1, navButtonInterruptHandler, (void*)pin::BUTTON1) != ESP_OK ||
|
||||||
|
gpio_isr_handler_add(pin::BUTTON2, navButtonInterruptHandler, (void*)pin::BUTTON2) != ESP_OK ||
|
||||||
|
gpio_isr_handler_add(pin::BUTTON3, navButtonInterruptHandler, (void*)pin::BUTTON3) != ESP_OK
|
||||||
|
) {
|
||||||
|
TT_LOG_E(TAG, "Nav buttons ISR init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::initOutputPins() {
|
||||||
|
uint64_t output_pin_mask =
|
||||||
|
BIT64(pin::IR_LEDS) |
|
||||||
|
BIT64(pin::LED_RED);
|
||||||
|
|
||||||
|
gpio_config_t output_gpio_config = {
|
||||||
|
.pin_bit_mask = output_pin_mask,
|
||||||
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||||
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gpio_config(&output_gpio_config) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Output pin init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::initGpioExpander() {
|
||||||
|
// ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_110 corresponds with 0x26 from the docs at
|
||||||
|
// https://gitlab.com/hamishcunningham/unphonelibrary/-/blob/main/unPhone.h?ref_type=heads#L206
|
||||||
|
if (esp_io_expander_new_i2c_tca95xx_16bit(I2C_NUM_0, ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_110, &ioExpander) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "IO expander init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
|
||||||
|
// Output pins
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::BACKLIGHT, IO_EXPANDER_OUTPUT);
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::EXPANDER_POWER, IO_EXPANDER_OUTPUT);
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::LED_GREEN, IO_EXPANDER_OUTPUT);
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::LED_BLUE, IO_EXPANDER_OUTPUT);
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::VIBE, IO_EXPANDER_OUTPUT);
|
||||||
|
// Input pins
|
||||||
|
esp_io_expander_set_dir(ioExpander, expanderpin::USB_VSENSE, IO_EXPANDER_INPUT);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::init() {
|
||||||
|
TT_LOG_I(TAG, "init");
|
||||||
|
|
||||||
|
if (!initNavButtons()) {
|
||||||
|
TT_LOG_E(TAG, "Input pin init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initOutputPins()) {
|
||||||
|
TT_LOG_E(TAG, "Output pin init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initPowerSwitch()) {
|
||||||
|
TT_LOG_E(TAG, "Power button init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initGpioExpander()) {
|
||||||
|
TT_LOG_E(TAG, "GPIO expander init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnPhoneFeatures::printInfo() const {
|
||||||
|
esp_io_expander_print_state(ioExpander);
|
||||||
|
batteryManagement.printInfo();
|
||||||
|
bool backlight_power;
|
||||||
|
const char* backlight_power_state = getBacklightPower(backlight_power) && backlight_power ? "on" : "off";
|
||||||
|
TT_LOG_I(TAG, "Backlight: %s", backlight_power_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setRgbLed(bool red, bool green, bool blue) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
return gpio_set_level(pin::LED_RED, red ? 1U : 0U) == ESP_OK &&
|
||||||
|
esp_io_expander_set_level(ioExpander, expanderpin::LED_GREEN, green ? 1U : 0U) == ESP_OK &&
|
||||||
|
esp_io_expander_set_level(ioExpander, expanderpin::LED_BLUE, blue ? 1U : 0U) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setBacklightPower(bool on) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
return esp_io_expander_set_level(ioExpander, expanderpin::BACKLIGHT, on ? 1U : 0U) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::getBacklightPower(bool& on) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
uint32_t level_mask;
|
||||||
|
if (esp_io_expander_get_level(ioExpander, expanderpin::BACKLIGHT, &level_mask) == ESP_OK) {
|
||||||
|
on = level_mask != 0U;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setIrPower(bool on) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
return gpio_set_level(pin::IR_LEDS, on ? 1U : 0U) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setVibePower(bool on) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
return esp_io_expander_set_level(ioExpander, expanderpin::VIBE, on ? 1U : 0U) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setExpanderPower(bool on) const {
|
||||||
|
assert(ioExpander != nullptr);
|
||||||
|
return esp_io_expander_set_level(ioExpander, expanderpin::EXPANDER_POWER, on ? 1U : 0U) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::isPowerSwitchOn() const {
|
||||||
|
return gpio_get_level(pin::POWER_SWITCH) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnPhoneFeatures::turnPeripheralsOff() const {
|
||||||
|
setExpanderPower(false);
|
||||||
|
setBacklightPower(false);
|
||||||
|
setIrPower(false);
|
||||||
|
setRgbLed(false, false, false);
|
||||||
|
setVibePower(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::setShipping(bool on) const {
|
||||||
|
if (on) {
|
||||||
|
TT_LOG_W(TAG, "setShipping: on");
|
||||||
|
uint8_t mask = (1 << 4) | (1 << 5);
|
||||||
|
// REG05[5:4] = 00
|
||||||
|
batteryManagement.setWatchDogBitOff(mask);
|
||||||
|
// Set bit 5 to disable
|
||||||
|
batteryManagement.setOperationControlBitOn(1 << 5);
|
||||||
|
} else {
|
||||||
|
TT_LOG_W(TAG, "setShipping: off");
|
||||||
|
// REG05[5:4] = 01
|
||||||
|
batteryManagement.setWatchDogBitOff(1 << 5);
|
||||||
|
batteryManagement.setWatchDogBitOn(1 << 4);
|
||||||
|
// Clear bit 5 to enable
|
||||||
|
batteryManagement.setOperationControlBitOff(1 << 5);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnPhoneFeatures::wakeOnPowerSwitch() const {
|
||||||
|
esp_sleep_enable_ext0_wakeup(pin::POWER_SWITCH, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneFeatures::isUsbPowerConnected() const {
|
||||||
|
uint8_t status;
|
||||||
|
if (batteryManagement.getStatus(status)) {
|
||||||
|
return (status & 4U) != 0U;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
Boards/UnPhone/Source/UnPhoneFeatures.h
Normal file
51
Boards/UnPhone/Source/UnPhoneFeatures.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "bq24295/Bq24295.h"
|
||||||
|
#include <esp_io_expander_tca95xx_16bit.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Easy access to GPIO pins
|
||||||
|
*/
|
||||||
|
class UnPhoneFeatures {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
esp_io_expander_handle_t ioExpander = nullptr;
|
||||||
|
Bq24295 batteryManagement = Bq24295(I2C_NUM_0);
|
||||||
|
tt::Thread buttonHandlingThread;
|
||||||
|
bool buttonHandlingThreadInterruptRequest = false;
|
||||||
|
|
||||||
|
bool initNavButtons();
|
||||||
|
static bool initOutputPins();
|
||||||
|
static bool initPowerSwitch();
|
||||||
|
bool initGpioExpander();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
UnPhoneFeatures() = default;
|
||||||
|
~UnPhoneFeatures();
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
|
||||||
|
bool setBacklightPower(bool on) const;
|
||||||
|
bool getBacklightPower(bool& on) const;
|
||||||
|
bool setIrPower(bool on) const;
|
||||||
|
bool setVibePower(bool on) const;
|
||||||
|
bool setExpanderPower(bool on) const;
|
||||||
|
|
||||||
|
bool isPowerSwitchOn() const;
|
||||||
|
|
||||||
|
void turnPeripheralsOff() const;
|
||||||
|
|
||||||
|
/** Battery management (BQ24295) will stop supplying power until USB connects */
|
||||||
|
bool setShipping(bool on) const;
|
||||||
|
|
||||||
|
void wakeOnPowerSwitch() const;
|
||||||
|
|
||||||
|
bool isUsbPowerConnected() const;
|
||||||
|
|
||||||
|
bool setRgbLed(bool red, bool green, bool blue) const;
|
||||||
|
|
||||||
|
void printInfo() const;
|
||||||
|
};
|
||||||
64
Boards/UnPhone/Source/bq24295/Bq24295.cpp
Normal file
64
Boards/UnPhone/Source/bq24295/Bq24295.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "Bq24295.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#define TAG "bq24295"
|
||||||
|
|
||||||
|
/** Reference: https://gitlab.com/hamishcunningham/unphonelibrary/-/blob/main/unPhone.h?ref_type=heads */
|
||||||
|
namespace registers {
|
||||||
|
static const uint8_t WATCHDOG = 0x05U; // Charge end/timer cntrl
|
||||||
|
static const uint8_t OPERATION_CONTROL = 0x07U; // Misc operation control
|
||||||
|
static const uint8_t STATUS = 0x08U; // System status
|
||||||
|
static const uint8_t VERSION = 0x0AU; // Vendor/part/revision status
|
||||||
|
} // namespace registers
|
||||||
|
|
||||||
|
// region Watchdog
|
||||||
|
bool Bq24295::getWatchDog(uint8_t value) const {
|
||||||
|
return readRegister8(registers::WATCHDOG, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bq24295::setWatchDogBitOn(uint8_t mask) const {
|
||||||
|
return bitOn(registers::WATCHDOG, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bq24295::setWatchDogBitOff(uint8_t mask) const {
|
||||||
|
return bitOff(registers::WATCHDOG, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregoin
|
||||||
|
|
||||||
|
// region Operation Control
|
||||||
|
|
||||||
|
bool Bq24295::getOperationControl(uint8_t value) const {
|
||||||
|
return readRegister8(registers::OPERATION_CONTROL, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bq24295::setOperationControlBitOn(uint8_t mask) const {
|
||||||
|
return bitOn(registers::OPERATION_CONTROL, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bq24295::setOperationControlBitOff(uint8_t mask) const {
|
||||||
|
return bitOff(registers::OPERATION_CONTROL, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Other
|
||||||
|
|
||||||
|
bool Bq24295::getStatus(uint8_t& value) const {
|
||||||
|
return readRegister8(registers::STATUS, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bq24295::getVersion(uint8_t& value) const {
|
||||||
|
return readRegister8(registers::VERSION, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bq24295::printInfo() const {
|
||||||
|
uint8_t version, status;
|
||||||
|
if (getStatus(status) && getVersion(version)) {
|
||||||
|
TT_LOG_I(TAG, "Version %d, status %02x", version, status);
|
||||||
|
} else {
|
||||||
|
TT_LOG_E(TAG, "Failed to retrieve version and/or status");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
25
Boards/UnPhone/Source/bq24295/Bq24295.h
Normal file
25
Boards/UnPhone/Source/bq24295/Bq24295.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal/i2c/I2cDevice.h"
|
||||||
|
|
||||||
|
#define BQ24295_ADDRESS 0x6BU
|
||||||
|
|
||||||
|
class Bq24295 : I2cDevice {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Bq24295(i2c_port_t port) : I2cDevice(port, BQ24295_ADDRESS) {}
|
||||||
|
|
||||||
|
bool getWatchDog(uint8_t value) const;
|
||||||
|
bool setWatchDogBitOn(uint8_t mask) const;
|
||||||
|
bool setWatchDogBitOff(uint8_t mask) const;
|
||||||
|
|
||||||
|
bool getOperationControl(uint8_t value) const;
|
||||||
|
bool setOperationControlBitOn(uint8_t mask) const;
|
||||||
|
bool setOperationControlBitOff(uint8_t mask) const;
|
||||||
|
|
||||||
|
bool getStatus(uint8_t& value) const;
|
||||||
|
bool getVersion(uint8_t& value) const;
|
||||||
|
|
||||||
|
void printInfo() const;
|
||||||
|
};
|
||||||
73
Boards/UnPhone/Source/hal/UnPhoneDisplay.cpp
Normal file
73
Boards/UnPhone/Source/hal/UnPhoneDisplay.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "UnPhoneDisplay.h"
|
||||||
|
#include "UnPhoneDisplayConstants.h"
|
||||||
|
#include "UnPhoneTouch.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <TactilityCore.h>
|
||||||
|
|
||||||
|
#include "UnPhoneFeatures.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "hx8357/disp_spi.h"
|
||||||
|
#include "hx8357/hx8357.h"
|
||||||
|
|
||||||
|
#define TAG "unphone_display"
|
||||||
|
#define BUFFER_SIZE (UNPHONE_LCD_HORIZONTAL_RESOLUTION * UNPHONE_LCD_DRAW_BUFFER_HEIGHT * LV_COLOR_DEPTH / 8)
|
||||||
|
|
||||||
|
extern UnPhoneFeatures unPhoneFeatures;
|
||||||
|
|
||||||
|
bool UnPhoneDisplay::start() {
|
||||||
|
TT_LOG_I(TAG, "Starting");
|
||||||
|
|
||||||
|
disp_spi_add_device(SPI2_HOST);
|
||||||
|
|
||||||
|
hx8357_reset(GPIO_NUM_46);
|
||||||
|
hx8357_init(UNPHONE_LCD_PIN_DC);
|
||||||
|
uint8_t madctl = (1U << MADCTL_BIT_INDEX_COLUMN_ADDRESS_ORDER);
|
||||||
|
hx8357_set_madctl(madctl);
|
||||||
|
|
||||||
|
displayHandle = lv_display_create(UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
|
||||||
|
lv_display_set_physical_resolution(displayHandle, UNPHONE_LCD_HORIZONTAL_RESOLUTION, UNPHONE_LCD_VERTICAL_RESOLUTION);
|
||||||
|
lv_display_set_color_format(displayHandle, LV_COLOR_FORMAT_NATIVE);
|
||||||
|
|
||||||
|
// TODO malloc to use SPIRAM
|
||||||
|
static auto* buffer1 = (uint8_t*)heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||||
|
static auto* buffer2 = (uint8_t*)heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||||
|
assert(buffer1 != nullptr);
|
||||||
|
assert(buffer2 != nullptr);
|
||||||
|
|
||||||
|
lv_display_set_buffers(
|
||||||
|
displayHandle,
|
||||||
|
buffer1,
|
||||||
|
buffer2,
|
||||||
|
BUFFER_SIZE,
|
||||||
|
LV_DISPLAY_RENDER_MODE_PARTIAL
|
||||||
|
);
|
||||||
|
|
||||||
|
lv_display_set_flush_cb(displayHandle, hx8357_flush);
|
||||||
|
|
||||||
|
if (displayHandle != nullptr) {
|
||||||
|
TT_LOG_I(TAG, "Finished");
|
||||||
|
unPhoneFeatures.setBacklightPower(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
TT_LOG_I(TAG, "Failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneDisplay::stop() {
|
||||||
|
tt_assert(displayHandle != nullptr);
|
||||||
|
|
||||||
|
lv_display_delete(displayHandle);
|
||||||
|
displayHandle = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt::hal::Touch* _Nullable UnPhoneDisplay::createTouch() {
|
||||||
|
return static_cast<tt::hal::Touch*>(new UnPhoneTouch());
|
||||||
|
}
|
||||||
|
|
||||||
|
tt::hal::Display* createDisplay() {
|
||||||
|
return static_cast<tt::hal::Display*>(new UnPhoneDisplay());
|
||||||
|
}
|
||||||
26
Boards/UnPhone/Source/hal/UnPhoneDisplay.h
Normal file
26
Boards/UnPhone/Source/hal/UnPhoneDisplay.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <esp_lcd_types.h>
|
||||||
|
#include "lvgl.h"
|
||||||
|
#include "hal/Display.h"
|
||||||
|
|
||||||
|
extern lv_disp_t* displayHandle;
|
||||||
|
|
||||||
|
class UnPhoneDisplay : public tt::hal::Display {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
lv_display_t* displayHandle = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool start() override;
|
||||||
|
|
||||||
|
bool stop() override;
|
||||||
|
|
||||||
|
tt::hal::Touch* _Nullable createTouch() override;
|
||||||
|
|
||||||
|
lv_display_t* _Nullable getLvglDisplay() const override { return displayHandle; }
|
||||||
|
};
|
||||||
|
|
||||||
|
tt::hal::Display* createDisplay();
|
||||||
11
Boards/UnPhone/Source/hal/UnPhoneDisplayConstants.h
Normal file
11
Boards/UnPhone/Source/hal/UnPhoneDisplayConstants.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define UNPHONE_LCD_SPI_HOST SPI2_HOST
|
||||||
|
#define UNPHONE_LCD_PIN_CS GPIO_NUM_48
|
||||||
|
#define UNPHONE_LCD_PIN_DC GPIO_NUM_47
|
||||||
|
#define UNPHONE_LCD_PIN_RESET GPIO_NUM_46
|
||||||
|
#define UNPHONE_LCD_SPI_FREQUENCY 27000000
|
||||||
|
#define UNPHONE_LCD_HORIZONTAL_RESOLUTION 320
|
||||||
|
#define UNPHONE_LCD_VERTICAL_RESOLUTION 480
|
||||||
|
#define UNPHONE_LCD_DRAW_BUFFER_HEIGHT (UNPHONE_LCD_VERTICAL_RESOLUTION / 15)
|
||||||
|
#define UNPHONE_LCD_SPI_TRANSFER_HEIGHT (UNPHONE_LCD_VERTICAL_RESOLUTION / 15)
|
||||||
35
Boards/UnPhone/Source/hal/UnPhoneSdCard.cpp
Normal file
35
Boards/UnPhone/Source/hal/UnPhoneSdCard.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "UnPhoneSdCard.h"
|
||||||
|
|
||||||
|
#include "lvgl/LvglSync.h"
|
||||||
|
#include "hal/SpiSdCard.h"
|
||||||
|
|
||||||
|
#include <esp_vfs_fat.h>
|
||||||
|
|
||||||
|
#define UNPHONE_SDCARD_SPI_FREQUENCY 20000000U
|
||||||
|
#define UNPHONE_SDCARD_PIN_CS GPIO_NUM_43
|
||||||
|
#define UNPHONE_LCD_PIN_CS GPIO_NUM_48
|
||||||
|
#define UNPHONE_LORA_PIN_CS GPIO_NUM_44
|
||||||
|
#define UNPHONE_TOUCH_PIN_CS GPIO_NUM_38
|
||||||
|
|
||||||
|
std::shared_ptr<SdCard> createUnPhoneSdCard() {
|
||||||
|
auto* configuration = new tt::hal::SpiSdCard::Config(
|
||||||
|
UNPHONE_SDCARD_SPI_FREQUENCY,
|
||||||
|
UNPHONE_SDCARD_PIN_CS,
|
||||||
|
GPIO_NUM_NC,
|
||||||
|
GPIO_NUM_NC,
|
||||||
|
GPIO_NUM_NC,
|
||||||
|
SdCard::MountBehaviour::AtBoot,
|
||||||
|
tt::lvgl::getLvglSyncLockable(),
|
||||||
|
{
|
||||||
|
UNPHONE_LORA_PIN_CS,
|
||||||
|
UNPHONE_LCD_PIN_CS,
|
||||||
|
UNPHONE_TOUCH_PIN_CS
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
auto* sdcard = (SdCard*) new SpiSdCard(
|
||||||
|
std::unique_ptr<SpiSdCard::Config>(configuration)
|
||||||
|
);
|
||||||
|
|
||||||
|
return std::shared_ptr<SdCard>(sdcard);
|
||||||
|
}
|
||||||
7
Boards/UnPhone/Source/hal/UnPhoneSdCard.h
Normal file
7
Boards/UnPhone/Source/hal/UnPhoneSdCard.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal/SdCard.h"
|
||||||
|
|
||||||
|
using namespace tt::hal;
|
||||||
|
|
||||||
|
std::shared_ptr<SdCard> createUnPhoneSdCard();
|
||||||
83
Boards/UnPhone/Source/hal/UnPhoneTouch.cpp
Normal file
83
Boards/UnPhone/Source/hal/UnPhoneTouch.cpp
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include "UnPhoneTouch.h"
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "esp_lvgl_port.h"
|
||||||
|
#include "esp_lcd_touch_xpt2046.h"
|
||||||
|
|
||||||
|
#define TAG "unphone_touch"
|
||||||
|
|
||||||
|
#define UNPHONE_TOUCH_X_MAX 320
|
||||||
|
#define UNPHONE_TOUCH_Y_MAX 480
|
||||||
|
|
||||||
|
bool UnPhoneTouch::start(lv_display_t* display) {
|
||||||
|
const esp_lcd_panel_io_spi_config_t io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(GPIO_NUM_38);
|
||||||
|
|
||||||
|
if (esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &ioHandle) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "Touch IO SPI creation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_lcd_touch_config_t config = {
|
||||||
|
.x_max = UNPHONE_TOUCH_X_MAX,
|
||||||
|
.y_max = UNPHONE_TOUCH_Y_MAX,
|
||||||
|
.rst_gpio_num = GPIO_NUM_NC,
|
||||||
|
.int_gpio_num = GPIO_NUM_NC,
|
||||||
|
.levels = {
|
||||||
|
.reset = 0,
|
||||||
|
.interrupt = 0,
|
||||||
|
},
|
||||||
|
.flags = {
|
||||||
|
.swap_xy = 0,
|
||||||
|
.mirror_x = 0,
|
||||||
|
.mirror_y = 0,
|
||||||
|
},
|
||||||
|
.process_coordinates = nullptr,
|
||||||
|
.interrupt_callback = nullptr,
|
||||||
|
.user_data = nullptr,
|
||||||
|
.driver_data = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
if (esp_lcd_touch_new_spi_xpt2046(ioHandle, &config, &touchHandle) != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "XPT2046 driver init failed");
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lvgl_port_touch_cfg_t touch_cfg = {
|
||||||
|
.disp = display,
|
||||||
|
.handle = touchHandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
TT_LOG_I(TAG, "Adding touch to LVGL");
|
||||||
|
deviceHandle = lvgl_port_add_touch(&touch_cfg);
|
||||||
|
if (deviceHandle == nullptr) {
|
||||||
|
TT_LOG_E(TAG, "Adding touch failed");
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnPhoneTouch::stop() {
|
||||||
|
cleanup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnPhoneTouch::cleanup() {
|
||||||
|
if (deviceHandle != nullptr) {
|
||||||
|
lv_indev_delete(deviceHandle);
|
||||||
|
deviceHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (touchHandle != nullptr) {
|
||||||
|
esp_lcd_touch_del(touchHandle);
|
||||||
|
touchHandle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioHandle != nullptr) {
|
||||||
|
esp_lcd_panel_io_del(ioHandle);
|
||||||
|
ioHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Boards/UnPhone/Source/hal/UnPhoneTouch.h
Normal file
18
Boards/UnPhone/Source/hal/UnPhoneTouch.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hal/Touch.h"
|
||||||
|
#include "TactilityCore.h"
|
||||||
|
#include "esp_lcd_panel_io_interface.h"
|
||||||
|
#include "esp_lcd_touch.h"
|
||||||
|
|
||||||
|
class UnPhoneTouch : public tt::hal::Touch {
|
||||||
|
private:
|
||||||
|
esp_lcd_panel_io_handle_t _Nullable ioHandle = nullptr;
|
||||||
|
esp_lcd_touch_handle_t _Nullable touchHandle = nullptr;
|
||||||
|
lv_indev_t* _Nullable deviceHandle = nullptr;
|
||||||
|
void cleanup();
|
||||||
|
public:
|
||||||
|
bool start(lv_display_t* display) override;
|
||||||
|
bool stop() override;
|
||||||
|
lv_indev_t* _Nullable getLvglIndev() override { return deviceHandle; }
|
||||||
|
};
|
||||||
4
Boards/UnPhone/Source/hx8357/README.md
Normal file
4
Boards/UnPhone/Source/hx8357/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
The files in this folder are from https://github.com/lvgl/lvgl_esp32_drivers
|
||||||
|
The original license is an MIT license: https://github.com/lvgl/lvgl_esp32_drivers/blob/master/LICENSE
|
||||||
|
|
||||||
|
You may use the files in this folder under the original license, or under GPL v3 from the main Tactility project.
|
||||||
315
Boards/UnPhone/Source/hx8357/disp_spi.c
Normal file
315
Boards/UnPhone/Source/hx8357/disp_spi.c
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
#define LV_USE_PRIVATE_API 1 // For actual lv_obj_t declaration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file disp_spi.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/spi_master.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#define TAG "disp_spi"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
#include "lvgl.h"
|
||||||
|
#else
|
||||||
|
#include "lvgl/lvgl.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "disp_spi.h"
|
||||||
|
//#include "disp_driver.h"
|
||||||
|
|
||||||
|
//#include "../lvgl_helpers.h"
|
||||||
|
#include "../lvgl_spi_conf.h"
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Notes about DMA spi_transaction_ext_t structure pooling
|
||||||
|
*
|
||||||
|
* An xQueue is used to hold a pool of reusable SPI spi_transaction_ext_t
|
||||||
|
* structures that get used for all DMA SPI transactions. While an xQueue may
|
||||||
|
* seem like overkill it is an already built-in RTOS feature that comes at
|
||||||
|
* little cost. xQueues are also ISR safe if it ever becomes necessary to
|
||||||
|
* access the pool in the ISR callback.
|
||||||
|
*
|
||||||
|
* When a DMA request is sent, a transaction structure is removed from the
|
||||||
|
* pool, filled out, and passed off to the esp32 SPI driver. Later, when
|
||||||
|
* servicing pending SPI transaction results, the transaction structure is
|
||||||
|
* recycled back into the pool for later reuse. This matches the DMA SPI
|
||||||
|
* transaction life cycle requirements of the esp32 SPI driver.
|
||||||
|
*
|
||||||
|
* When polling or synchronously sending SPI requests, and as required by the
|
||||||
|
* esp32 SPI driver, all pending DMA transactions are first serviced. Then the
|
||||||
|
* polling SPI request takes place.
|
||||||
|
*
|
||||||
|
* When sending an asynchronous DMA SPI request, if the pool is empty, some
|
||||||
|
* small percentage of pending transactions are first serviced before sending
|
||||||
|
* any new DMA SPI transactions. Not too many and not too few as this balance
|
||||||
|
* controls DMA transaction latency.
|
||||||
|
*
|
||||||
|
* It is therefore not the design that all pending transactions must be
|
||||||
|
* serviced and placed back into the pool with DMA SPI requests - that
|
||||||
|
* will happen eventually. The pool just needs to contain enough to float some
|
||||||
|
* number of in-flight SPI requests to speed up the overall DMA SPI data rate
|
||||||
|
* and reduce transaction latency. If however a display driver uses some
|
||||||
|
* polling SPI requests or calls disp_wait_for_pending_transactions() directly,
|
||||||
|
* the pool will reach the full state more often and speed up DMA queuing.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define SPI_TRANSACTION_POOL_SIZE 50 /* maximum number of DMA transactions simultaneously in-flight */
|
||||||
|
|
||||||
|
/* DMA Transactions to reserve before queueing additional DMA transactions. A 1/10th seems to be a good balance. Too many (or all) and it will increase latency. */
|
||||||
|
#define SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE 10
|
||||||
|
#if SPI_TRANSACTION_POOL_SIZE >= SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE
|
||||||
|
#define SPI_TRANSACTION_POOL_RESERVE (SPI_TRANSACTION_POOL_SIZE / SPI_TRANSACTION_POOL_RESERVE_PERCENTAGE)
|
||||||
|
#else
|
||||||
|
#define SPI_TRANSACTION_POOL_RESERVE 1 /* defines minimum size */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void IRAM_ATTR spi_ready (spi_transaction_t *trans);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static spi_host_device_t spi_host;
|
||||||
|
static spi_device_handle_t spi;
|
||||||
|
static QueueHandle_t TransactionPool = NULL;
|
||||||
|
static transaction_cb_t chained_post_cb;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
void disp_spi_add_device_config(spi_host_device_t host, spi_device_interface_config_t *devcfg)
|
||||||
|
{
|
||||||
|
spi_host=host;
|
||||||
|
chained_post_cb=devcfg->post_cb;
|
||||||
|
devcfg->post_cb=spi_ready;
|
||||||
|
esp_err_t ret=spi_bus_add_device(host, devcfg, &spi);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_add_device(spi_host_device_t host)
|
||||||
|
{
|
||||||
|
disp_spi_add_device_with_speed(host, SPI_TFT_CLOCK_SPEED_HZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_add_device_with_speed(spi_host_device_t host, int clock_speed_hz)
|
||||||
|
{
|
||||||
|
ESP_LOGI(TAG, "Adding SPI device");
|
||||||
|
ESP_LOGI(TAG, "Clock speed: %dHz, mode: %d, CS pin: %d",
|
||||||
|
clock_speed_hz, SPI_TFT_SPI_MODE, DISP_SPI_CS);
|
||||||
|
|
||||||
|
spi_device_interface_config_t devcfg={
|
||||||
|
.clock_speed_hz = clock_speed_hz,
|
||||||
|
.mode = SPI_TFT_SPI_MODE,
|
||||||
|
.spics_io_num=DISP_SPI_CS, // CS pin
|
||||||
|
.input_delay_ns=DISP_SPI_INPUT_DELAY_NS,
|
||||||
|
.queue_size=SPI_TRANSACTION_POOL_SIZE,
|
||||||
|
.pre_cb=NULL,
|
||||||
|
.post_cb=NULL,
|
||||||
|
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||||
|
.flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_HALFDUPLEX, /* dummy bits should be explicitly handled via DISP_SPI_VARIABLE_DUMMY as needed */
|
||||||
|
#else
|
||||||
|
#if defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_FT81X)
|
||||||
|
.flags = 0,
|
||||||
|
#elif defined (CONFIG_LV_TFT_DISPLAY_CONTROLLER_RA8875)
|
||||||
|
.flags = SPI_DEVICE_NO_DUMMY,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
disp_spi_add_device_config(host, &devcfg);
|
||||||
|
|
||||||
|
/* create the transaction pool and fill it with ptrs to spi_transaction_ext_t to reuse */
|
||||||
|
if(TransactionPool == NULL) {
|
||||||
|
TransactionPool = xQueueCreate(SPI_TRANSACTION_POOL_SIZE, sizeof(spi_transaction_ext_t*));
|
||||||
|
assert(TransactionPool != NULL);
|
||||||
|
for (size_t i = 0; i < SPI_TRANSACTION_POOL_SIZE; i++)
|
||||||
|
{
|
||||||
|
spi_transaction_ext_t* pTransaction = (spi_transaction_ext_t*)heap_caps_malloc(sizeof(spi_transaction_ext_t), MALLOC_CAP_DMA);
|
||||||
|
assert(pTransaction != NULL);
|
||||||
|
memset(pTransaction, 0, sizeof(spi_transaction_ext_t));
|
||||||
|
xQueueSend(TransactionPool, &pTransaction, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_change_device_speed(int clock_speed_hz)
|
||||||
|
{
|
||||||
|
if (clock_speed_hz <= 0) {
|
||||||
|
clock_speed_hz = SPI_TFT_CLOCK_SPEED_HZ;
|
||||||
|
}
|
||||||
|
ESP_LOGI(TAG, "Changing SPI device clock speed: %d", clock_speed_hz);
|
||||||
|
disp_spi_remove_device();
|
||||||
|
disp_spi_add_device_with_speed(spi_host, clock_speed_hz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_remove_device()
|
||||||
|
{
|
||||||
|
/* Wait for previous pending transaction results */
|
||||||
|
disp_wait_for_pending_transactions();
|
||||||
|
|
||||||
|
esp_err_t ret=spi_bus_remove_device(spi);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_transaction(const uint8_t *data, size_t length,
|
||||||
|
int flags, uint8_t *out,
|
||||||
|
uint64_t addr, uint8_t dummy_bits)
|
||||||
|
{
|
||||||
|
if (0 == length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_transaction_ext_t t = {0};
|
||||||
|
|
||||||
|
/* transaction length is in bits */
|
||||||
|
t.base.length = length * 8;
|
||||||
|
|
||||||
|
if (length <= 4 && data != NULL) {
|
||||||
|
t.base.flags = SPI_TRANS_USE_TXDATA;
|
||||||
|
memcpy(t.base.tx_data, data, length);
|
||||||
|
} else {
|
||||||
|
t.base.tx_buffer = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DISP_SPI_RECEIVE) {
|
||||||
|
assert(out != NULL && (flags & (DISP_SPI_SEND_POLLING | DISP_SPI_SEND_SYNCHRONOUS)));
|
||||||
|
t.base.rx_buffer = out;
|
||||||
|
|
||||||
|
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||||
|
t.base.rxlength = t.base.length;
|
||||||
|
t.base.length = 0; /* no MOSI phase in half-duplex reads */
|
||||||
|
#else
|
||||||
|
t.base.rxlength = 0; /* in full-duplex mode, zero means same as tx length */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DISP_SPI_ADDRESS_8) {
|
||||||
|
t.address_bits = 8;
|
||||||
|
} else if (flags & DISP_SPI_ADDRESS_16) {
|
||||||
|
t.address_bits = 16;
|
||||||
|
} else if (flags & DISP_SPI_ADDRESS_24) {
|
||||||
|
t.address_bits = 24;
|
||||||
|
} else if (flags & DISP_SPI_ADDRESS_32) {
|
||||||
|
t.address_bits = 32;
|
||||||
|
}
|
||||||
|
if (t.address_bits) {
|
||||||
|
t.base.addr = addr;
|
||||||
|
t.base.flags |= SPI_TRANS_VARIABLE_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DISP_SPI_HALF_DUPLEX)
|
||||||
|
if (flags & DISP_SPI_MODE_DIO) {
|
||||||
|
t.base.flags |= SPI_TRANS_MODE_DIO;
|
||||||
|
} else if (flags & DISP_SPI_MODE_QIO) {
|
||||||
|
t.base.flags |= SPI_TRANS_MODE_QIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DISP_SPI_MODE_DIOQIO_ADDR) {
|
||||||
|
t.base.flags |= SPI_TRANS_MODE_DIOQIO_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & DISP_SPI_VARIABLE_DUMMY) && dummy_bits) {
|
||||||
|
t.dummy_bits = dummy_bits;
|
||||||
|
t.base.flags |= SPI_TRANS_VARIABLE_DUMMY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Save flags for pre/post transaction processing */
|
||||||
|
t.base.user = (void *) flags;
|
||||||
|
|
||||||
|
/* Poll/Complete/Queue transaction */
|
||||||
|
if (flags & DISP_SPI_SEND_POLLING) {
|
||||||
|
disp_wait_for_pending_transactions(); /* before polling, all previous pending transactions need to be serviced */
|
||||||
|
spi_device_polling_transmit(spi, (spi_transaction_t *) &t);
|
||||||
|
} else if (flags & DISP_SPI_SEND_SYNCHRONOUS) {
|
||||||
|
disp_wait_for_pending_transactions(); /* before synchronous queueing, all previous pending transactions need to be serviced */
|
||||||
|
spi_device_transmit(spi, (spi_transaction_t *) &t);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* if necessary, ensure we can queue new transactions by servicing some previous transactions */
|
||||||
|
if(uxQueueMessagesWaiting(TransactionPool) == 0) {
|
||||||
|
spi_transaction_t *presult;
|
||||||
|
while(uxQueueMessagesWaiting(TransactionPool) < SPI_TRANSACTION_POOL_RESERVE) {
|
||||||
|
if (spi_device_get_trans_result(spi, &presult, 1) == ESP_OK) {
|
||||||
|
xQueueSend(TransactionPool, &presult, portMAX_DELAY); /* back to the pool to be reused */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_transaction_ext_t *pTransaction = NULL;
|
||||||
|
xQueueReceive(TransactionPool, &pTransaction, portMAX_DELAY);
|
||||||
|
memcpy(pTransaction, &t, sizeof(t));
|
||||||
|
if (spi_device_queue_trans(spi, (spi_transaction_t *) pTransaction, portMAX_DELAY) != ESP_OK) {
|
||||||
|
xQueueSend(TransactionPool, &pTransaction, portMAX_DELAY); /* send failed transaction back to the pool to be reused */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void disp_wait_for_pending_transactions(void)
|
||||||
|
{
|
||||||
|
spi_transaction_t *presult;
|
||||||
|
|
||||||
|
while(uxQueueMessagesWaiting(TransactionPool) < SPI_TRANSACTION_POOL_SIZE) { /* service until the transaction reuse pool is full again */
|
||||||
|
if (spi_device_get_trans_result(spi, &presult, 1) == ESP_OK) {
|
||||||
|
xQueueSend(TransactionPool, &presult, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_acquire(void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = spi_device_acquire_bus(spi, portMAX_DELAY);
|
||||||
|
assert(ret == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disp_spi_release(void)
|
||||||
|
{
|
||||||
|
spi_device_release_bus(spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void IRAM_ATTR spi_ready(spi_transaction_t *trans)
|
||||||
|
{
|
||||||
|
disp_spi_send_flag_t flags = (disp_spi_send_flag_t) trans->user;
|
||||||
|
|
||||||
|
if (flags & DISP_SPI_SIGNAL_FLUSH) {
|
||||||
|
lv_disp_t* disp = lv_refr_get_disp_refreshing();
|
||||||
|
lv_disp_flush_ready(disp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chained_post_cb) {
|
||||||
|
chained_post_cb(trans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
81
Boards/UnPhone/Source/hx8357/disp_spi.h
Normal file
81
Boards/UnPhone/Source/hx8357/disp_spi.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* @file disp_spi.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DISP_SPI_H
|
||||||
|
#define DISP_SPI_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <driver/spi_master.h>
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
typedef enum _disp_spi_send_flag_t {
|
||||||
|
DISP_SPI_SEND_QUEUED = 0x00000000,
|
||||||
|
DISP_SPI_SEND_POLLING = 0x00000001,
|
||||||
|
DISP_SPI_SEND_SYNCHRONOUS = 0x00000002,
|
||||||
|
DISP_SPI_SIGNAL_FLUSH = 0x00000004,
|
||||||
|
DISP_SPI_RECEIVE = 0x00000008,
|
||||||
|
DISP_SPI_CMD_8 = 0x00000010, /* Reserved */
|
||||||
|
DISP_SPI_CMD_16 = 0x00000020, /* Reserved */
|
||||||
|
DISP_SPI_ADDRESS_8 = 0x00000040,
|
||||||
|
DISP_SPI_ADDRESS_16 = 0x00000080,
|
||||||
|
DISP_SPI_ADDRESS_24 = 0x00000100,
|
||||||
|
DISP_SPI_ADDRESS_32 = 0x00000200,
|
||||||
|
DISP_SPI_MODE_DIO = 0x00000400,
|
||||||
|
DISP_SPI_MODE_QIO = 0x00000800,
|
||||||
|
DISP_SPI_MODE_DIOQIO_ADDR = 0x00001000,
|
||||||
|
DISP_SPI_VARIABLE_DUMMY = 0x00002000,
|
||||||
|
} disp_spi_send_flag_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void disp_spi_add_device(spi_host_device_t host);
|
||||||
|
void disp_spi_add_device_config(spi_host_device_t host, spi_device_interface_config_t *devcfg);
|
||||||
|
void disp_spi_add_device_with_speed(spi_host_device_t host, int clock_speed_hz);
|
||||||
|
void disp_spi_change_device_speed(int clock_speed_hz);
|
||||||
|
void disp_spi_remove_device();
|
||||||
|
|
||||||
|
/* Important!
|
||||||
|
All buffers should also be 32-bit aligned and DMA capable to prevent extra allocations and copying.
|
||||||
|
When DMA reading (even in polling mode) the ESP32 always read in 4-byte chunks even if less is requested.
|
||||||
|
Extra space will be zero filled. Always ensure the out buffer is large enough to hold at least 4 bytes!
|
||||||
|
*/
|
||||||
|
void disp_spi_transaction(const uint8_t *data, size_t length,
|
||||||
|
int flags, uint8_t *out, uint64_t addr, uint8_t dummy_bits);
|
||||||
|
|
||||||
|
void disp_wait_for_pending_transactions(void);
|
||||||
|
void disp_spi_acquire(void);
|
||||||
|
void disp_spi_release(void);
|
||||||
|
|
||||||
|
static inline void disp_spi_send_data(uint8_t *data, size_t length) {
|
||||||
|
disp_spi_transaction(data, length, DISP_SPI_SEND_POLLING, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void disp_spi_send_colors(uint8_t *data, size_t length) {
|
||||||
|
disp_spi_transaction(data, length,
|
||||||
|
DISP_SPI_SEND_QUEUED | DISP_SPI_SIGNAL_FLUSH,
|
||||||
|
NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*DISP_SPI_H*/
|
||||||
292
Boards/UnPhone/Source/hx8357/hx8357.c
Normal file
292
Boards/UnPhone/Source/hx8357/hx8357.c
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
/**
|
||||||
|
* @file HX8357.c
|
||||||
|
*
|
||||||
|
* Roughly based on the Adafruit_HX8357_Library
|
||||||
|
*
|
||||||
|
* This library should work with:
|
||||||
|
* Adafruit 3.5" TFT 320x480 + Touchscreen Breakout
|
||||||
|
* http://www.adafruit.com/products/2050
|
||||||
|
*
|
||||||
|
* Adafruit TFT FeatherWing - 3.5" 480x320 Touchscreen for Feathers
|
||||||
|
* https://www.adafruit.com/product/3651
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "hx8357.h"
|
||||||
|
#include "disp_spi.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include <esp_log.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
#define TAG "HX8357"
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static gpio_num_t dcPin = GPIO_NUM_NC;
|
||||||
|
|
||||||
|
/*The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t data[16];
|
||||||
|
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
|
||||||
|
} lcd_init_cmd_t;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void hx8357_send_cmd(uint8_t cmd);
|
||||||
|
static void hx8357_send_data(void * data, uint16_t length);
|
||||||
|
static void hx8357_send_color(void * data, uint16_t length);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* INITIALIZATION ARRAYS
|
||||||
|
**********************/
|
||||||
|
// Taken from the Adafruit driver
|
||||||
|
static const uint8_t
|
||||||
|
initb[] = {
|
||||||
|
HX8357B_SETPOWER, 3,
|
||||||
|
0x44, 0x41, 0x06,
|
||||||
|
HX8357B_SETVCOM, 2,
|
||||||
|
0x40, 0x10,
|
||||||
|
HX8357B_SETPWRNORMAL, 2,
|
||||||
|
0x05, 0x12,
|
||||||
|
HX8357B_SET_PANEL_DRIVING, 5,
|
||||||
|
0x14, 0x3b, 0x00, 0x02, 0x11,
|
||||||
|
HX8357B_SETDISPLAYFRAME, 1,
|
||||||
|
0x0c, // 6.8mhz
|
||||||
|
HX8357B_SETPANELRELATED, 1,
|
||||||
|
0x01, // BGR
|
||||||
|
0xEA, 3, // seq_undefined1, 3 args
|
||||||
|
0x03, 0x00, 0x00,
|
||||||
|
0xEB, 4, // undef2, 4 args
|
||||||
|
0x40, 0x54, 0x26, 0xdb,
|
||||||
|
HX8357B_SETGAMMA, 12,
|
||||||
|
0x00, 0x15, 0x00, 0x22, 0x00, 0x08, 0x77, 0x26, 0x66, 0x22, 0x04, 0x00,
|
||||||
|
HX8357_MADCTL, 1,
|
||||||
|
0xC0,
|
||||||
|
HX8357_COLMOD, 1,
|
||||||
|
0x55,
|
||||||
|
HX8357_PASET, 4,
|
||||||
|
0x00, 0x00, 0x01, 0xDF,
|
||||||
|
HX8357_CASET, 4,
|
||||||
|
0x00, 0x00, 0x01, 0x3F,
|
||||||
|
HX8357B_SETDISPMODE, 1,
|
||||||
|
0x00, // CPU (DBI) and internal oscillation ??
|
||||||
|
HX8357_SLPOUT, 0x80 + 120/5, // Exit sleep, then delay 120 ms
|
||||||
|
HX8357_DISPON, 0x80 + 10/5, // Main screen turn on, delay 10 ms
|
||||||
|
0 // END OF COMMAND LIST
|
||||||
|
}, initd[] = {
|
||||||
|
HX8357_SWRESET, 0x80 + 100/5, // Soft reset, then delay 10 ms
|
||||||
|
HX8357D_SETC, 3,
|
||||||
|
0xFF, 0x83, 0x57,
|
||||||
|
0xFF, 0x80 + 500/5, // No command, just delay 300 ms
|
||||||
|
HX8357_SETRGB, 4,
|
||||||
|
0x80, 0x00, 0x06, 0x06, // 0x80 enables SDO pin (0x00 disables)
|
||||||
|
HX8357D_SETCOM, 1,
|
||||||
|
0x25, // -1.52V
|
||||||
|
HX8357_SETOSC, 1,
|
||||||
|
0x68, // Normal mode 70Hz, Idle mode 55 Hz
|
||||||
|
HX8357_SETPANEL, 1,
|
||||||
|
0x05, // BGR, Gate direction swapped
|
||||||
|
HX8357_SETPWR1, 6,
|
||||||
|
0x00, // Not deep standby
|
||||||
|
0x15, // BT
|
||||||
|
0x1C, // VSPR
|
||||||
|
0x1C, // VSNR
|
||||||
|
0x83, // AP
|
||||||
|
0xAA, // FS
|
||||||
|
HX8357D_SETSTBA, 6,
|
||||||
|
0x50, // OPON normal
|
||||||
|
0x50, // OPON idle
|
||||||
|
0x01, // STBA
|
||||||
|
0x3C, // STBA
|
||||||
|
0x1E, // STBA
|
||||||
|
0x08, // GEN
|
||||||
|
HX8357D_SETCYC, 7,
|
||||||
|
0x02, // NW 0x02
|
||||||
|
0x40, // RTN
|
||||||
|
0x00, // DIV
|
||||||
|
0x2A, // DUM
|
||||||
|
0x2A, // DUM
|
||||||
|
0x0D, // GDON
|
||||||
|
0x78, // GDOFF
|
||||||
|
HX8357D_SETGAMMA, 34,
|
||||||
|
0x02, 0x0A, 0x11, 0x1d, 0x23, 0x35, 0x41, 0x4b, 0x4b,
|
||||||
|
0x42, 0x3A, 0x27, 0x1B, 0x08, 0x09, 0x03, 0x02, 0x0A,
|
||||||
|
0x11, 0x1d, 0x23, 0x35, 0x41, 0x4b, 0x4b, 0x42, 0x3A,
|
||||||
|
0x27, 0x1B, 0x08, 0x09, 0x03, 0x00, 0x01,
|
||||||
|
HX8357_COLMOD, 1,
|
||||||
|
0x57, // 0x55 = 16 bit, 0x57 = 24bit
|
||||||
|
HX8357_MADCTL, 1,
|
||||||
|
0xC0,
|
||||||
|
HX8357_TEON, 1,
|
||||||
|
0x00, // TW off
|
||||||
|
HX8357_TEARLINE, 2,
|
||||||
|
0x00, 0x02,
|
||||||
|
HX8357_SLPOUT, 0x80 + 150/5, // Exit Sleep, then delay 150 ms
|
||||||
|
HX8357_DISPON, 0x80 + 50/5, // Main screen turn on, delay 50 ms
|
||||||
|
0, // END OF COMMAND LIST
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
static uint8_t displayType = HX8357D;
|
||||||
|
|
||||||
|
void hx8357_reset(gpio_num_t resetPin) {
|
||||||
|
if (resetPin != GPIO_NUM_NC) {
|
||||||
|
esp_rom_gpio_pad_select_gpio(resetPin);
|
||||||
|
gpio_set_direction(resetPin, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
//Reset the display
|
||||||
|
gpio_set_level(resetPin, 0);
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
gpio_set_level(resetPin, 1);
|
||||||
|
vTaskDelay(120 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hx8357_init(gpio_num_t newDcPin) {
|
||||||
|
ESP_LOGI(TAG, "Initialization.");
|
||||||
|
|
||||||
|
dcPin = newDcPin;
|
||||||
|
|
||||||
|
//Initialize non-SPI GPIOs
|
||||||
|
esp_rom_gpio_pad_select_gpio(dcPin);
|
||||||
|
gpio_set_direction(dcPin, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
//Send all the commands
|
||||||
|
const uint8_t *addr = (displayType == HX8357B) ? initb : initd;
|
||||||
|
uint8_t cmd, x, numArgs;
|
||||||
|
while((cmd = *addr++) > 0) { // '0' command ends list
|
||||||
|
x = *addr++;
|
||||||
|
numArgs = x & 0x7F;
|
||||||
|
if (cmd != 0xFF) { // '255' is ignored
|
||||||
|
if (x & 0x80) { // If high bit set, numArgs is a delay time
|
||||||
|
hx8357_send_cmd(cmd);
|
||||||
|
} else {
|
||||||
|
hx8357_send_cmd(cmd);
|
||||||
|
hx8357_send_data((void *) addr, numArgs);
|
||||||
|
addr += numArgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x & 0x80) { // If high bit set...
|
||||||
|
vTaskDelay(numArgs * 5 / portTICK_PERIOD_MS); // numArgs is actually a delay time (5ms units)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HX8357_INVERT_COLORS
|
||||||
|
hx8357_send_cmd(HX8357_INVON);
|
||||||
|
#else
|
||||||
|
hx8357_send_cmd(HX8357_INVOFF);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
|
||||||
|
void hx8357_flush(lv_disp_t* drv, const lv_area_t * area, uint8_t * color_map)
|
||||||
|
{
|
||||||
|
uint32_t size = lv_area_get_width(area) * lv_area_get_height(area);
|
||||||
|
|
||||||
|
/* Column addresses */
|
||||||
|
uint8_t xb[] = {
|
||||||
|
(uint8_t) (area->x1 >> 8) & 0xFF,
|
||||||
|
(uint8_t) (area->x1) & 0xFF,
|
||||||
|
(uint8_t) (area->x2 >> 8) & 0xFF,
|
||||||
|
(uint8_t) (area->x2) & 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Page addresses */
|
||||||
|
uint8_t yb[] = {
|
||||||
|
(uint8_t) (area->y1 >> 8) & 0xFF,
|
||||||
|
(uint8_t) (area->y1) & 0xFF,
|
||||||
|
(uint8_t) (area->y2 >> 8) & 0xFF,
|
||||||
|
(uint8_t) (area->y2) & 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Column addresses*/
|
||||||
|
hx8357_send_cmd(HX8357_CASET);
|
||||||
|
hx8357_send_data(xb, 4);
|
||||||
|
|
||||||
|
/*Page addresses*/
|
||||||
|
hx8357_send_cmd(HX8357_PASET);
|
||||||
|
hx8357_send_data(yb, 4);
|
||||||
|
|
||||||
|
/*Memory write*/
|
||||||
|
hx8357_send_cmd(HX8357_RAMWR);
|
||||||
|
hx8357_send_color((void*)color_map, size * (LV_COLOR_DEPTH / 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hx8357_set_madctl(uint8_t value) {
|
||||||
|
hx8357_send_cmd(HX8357_MADCTL);
|
||||||
|
hx8357_send_data(&value, 1);
|
||||||
|
}
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
|
||||||
|
static void hx8357_send_cmd(uint8_t cmd)
|
||||||
|
{
|
||||||
|
disp_wait_for_pending_transactions();
|
||||||
|
gpio_set_level(dcPin, 0); /*Command mode*/
|
||||||
|
disp_spi_send_data(&cmd, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hx8357_send_data(void * data, uint16_t length)
|
||||||
|
{
|
||||||
|
disp_wait_for_pending_transactions();
|
||||||
|
gpio_set_level(dcPin, 1); /*Data mode*/
|
||||||
|
disp_spi_send_data(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hx8357_send_color(void * data, uint16_t length)
|
||||||
|
{
|
||||||
|
disp_wait_for_pending_transactions();
|
||||||
|
gpio_set_level(dcPin, 1); /*Data mode*/
|
||||||
|
disp_spi_send_colors(data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hx8357d_get_gamma_curve_count() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hx8357d_set_gamme_curve(uint8_t index) {
|
||||||
|
uint8_t curve = 1;
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
curve = 0x01;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
curve = 0x02;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
curve = 0x04;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
curve = 0x08;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hx8357_send_cmd(HX8357D_SETGAMMA_BY_ID);
|
||||||
|
hx8357_send_data(&curve, 1);
|
||||||
|
}
|
||||||
133
Boards/UnPhone/Source/hx8357/hx8357.h
Normal file
133
Boards/UnPhone/Source/hx8357/hx8357.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* @file hx8357.h
|
||||||
|
*
|
||||||
|
* Roughly based on the Adafruit_HX8357_Library
|
||||||
|
*
|
||||||
|
* This library should work with:
|
||||||
|
* Adafruit 3.5" TFT 320x480 + Touchscreen Breakout
|
||||||
|
* http://www.adafruit.com/products/2050
|
||||||
|
*
|
||||||
|
* Adafruit TFT FeatherWing - 3.5" 480x320 Touchscreen for Feathers
|
||||||
|
* https://www.adafruit.com/product/3651
|
||||||
|
*
|
||||||
|
* Datasheet:
|
||||||
|
* https://cdn-shop.adafruit.com/datasheets/HX8357-D_DS_April2012.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HX8357_H
|
||||||
|
#define HX8357_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <soc/gpio_num.h>
|
||||||
|
|
||||||
|
#define HX8357D 0xD ///< Our internal const for D type
|
||||||
|
#define HX8357B 0xB ///< Our internal const for B type
|
||||||
|
|
||||||
|
#define HX8357_TFTWIDTH 320 ///< 320 pixels wide
|
||||||
|
#define HX8357_TFTHEIGHT 480 ///< 480 pixels tall
|
||||||
|
|
||||||
|
#define HX8357_NOP 0x00 ///< No op
|
||||||
|
#define HX8357_SWRESET 0x01 ///< software reset
|
||||||
|
#define HX8357_RDDID 0x04 ///< Read ID
|
||||||
|
#define HX8357_RDDST 0x09 ///< (unknown)
|
||||||
|
|
||||||
|
#define HX8357_RDPOWMODE 0x0A ///< Read power mode Read power mode
|
||||||
|
#define HX8357_RDMADCTL 0x0B ///< Read MADCTL
|
||||||
|
#define HX8357_RDCOLMOD 0x0C ///< Column entry mode
|
||||||
|
#define HX8357_RDDIM 0x0D ///< Read display image mode
|
||||||
|
#define HX8357_RDDSDR 0x0F ///< Read dosplay signal mode
|
||||||
|
|
||||||
|
#define HX8357_SLPIN 0x10 ///< Enter sleep mode
|
||||||
|
#define HX8357_SLPOUT 0x11 ///< Exit sleep mode
|
||||||
|
#define HX8357B_PTLON 0x12 ///< Partial mode on
|
||||||
|
#define HX8357B_NORON 0x13 ///< Normal mode
|
||||||
|
|
||||||
|
#define HX8357_INVOFF 0x20 ///< Turn off invert
|
||||||
|
#define HX8357_INVON 0x21 ///< Turn on invert
|
||||||
|
#define HX8357_DISPOFF 0x28 ///< Display on
|
||||||
|
#define HX8357_DISPON 0x29 ///< Display off
|
||||||
|
|
||||||
|
#define HX8357_CASET 0x2A ///< Column addr set
|
||||||
|
#define HX8357_PASET 0x2B ///< Page addr set
|
||||||
|
#define HX8357_RAMWR 0x2C ///< Write VRAM
|
||||||
|
#define HX8357_RAMRD 0x2E ///< Read VRAm
|
||||||
|
|
||||||
|
#define HX8357B_PTLAR 0x30 ///< (unknown)
|
||||||
|
#define HX8357_TEON 0x35 ///< Tear enable on
|
||||||
|
#define HX8357_TEARLINE 0x44 ///< (unknown)
|
||||||
|
#define HX8357_MADCTL 0x36 ///< Memory access control
|
||||||
|
#define HX8357_COLMOD 0x3A ///< Color mode
|
||||||
|
|
||||||
|
#define HX8357_SETOSC 0xB0 ///< Set oscillator
|
||||||
|
#define HX8357_SETPWR1 0xB1 ///< Set power control
|
||||||
|
#define HX8357B_SETDISPLAY 0xB2 ///< Set display mode
|
||||||
|
#define HX8357_SETRGB 0xB3 ///< Set RGB interface
|
||||||
|
#define HX8357D_SETCOM 0xB6 ///< Set VCOM voltage
|
||||||
|
|
||||||
|
#define HX8357B_SETDISPMODE 0xB4 ///< Set display mode
|
||||||
|
#define HX8357D_SETCYC 0xB4 ///< Set display cycle reg
|
||||||
|
#define HX8357B_SETOTP 0xB7 ///< Set OTP memory
|
||||||
|
#define HX8357D_SETC 0xB9 ///< Enable extension command
|
||||||
|
|
||||||
|
#define HX8357B_SET_PANEL_DRIVING 0xC0 ///< Set panel drive mode
|
||||||
|
#define HX8357D_SETSTBA 0xC0 ///< Set source option
|
||||||
|
#define HX8357B_SETDGC 0xC1 ///< Set DGC settings
|
||||||
|
#define HX8357B_SETID 0xC3 ///< Set ID
|
||||||
|
#define HX8357B_SETDDB 0xC4 ///< Set DDB
|
||||||
|
#define HX8357B_SETDISPLAYFRAME 0xC5 ///< Set display frame
|
||||||
|
#define HX8357B_GAMMASET 0xC8 ///< Set Gamma correction
|
||||||
|
#define HX8357B_SETCABC 0xC9 ///< Set CABC
|
||||||
|
#define HX8357_SETPANEL 0xCC ///< Set Panel
|
||||||
|
|
||||||
|
#define HX8357B_SETPOWER 0xD0 ///< Set power control
|
||||||
|
#define HX8357B_SETVCOM 0xD1 ///< Set VCOM
|
||||||
|
#define HX8357B_SETPWRNORMAL 0xD2 ///< Set power normal
|
||||||
|
|
||||||
|
#define HX8357B_RDID1 0xDA ///< Read ID #1
|
||||||
|
#define HX8357B_RDID2 0xDB ///< Read ID #2
|
||||||
|
#define HX8357B_RDID3 0xDC ///< Read ID #3
|
||||||
|
#define HX8357B_RDID4 0xDD ///< Read ID #4
|
||||||
|
|
||||||
|
#define HX8357D_SETGAMMA 0xE0 ///< Set Gamma curve data
|
||||||
|
#define HX8357D_SETGAMMA_BY_ID 0x26 ///< Set Gamma curve by curve identifier (0x01, 0x02, 0x04, 0x08)
|
||||||
|
#define HX8357B_SETGAMMA 0xC8 ///< Set Gamma
|
||||||
|
#define HX8357B_SETPANELRELATED 0xE9 ///< Set panel related
|
||||||
|
|
||||||
|
// MADCTL
|
||||||
|
// See datasheet page 123: https://cdn-shop.adafruit.com/datasheets/HX8357-D_DS_April2012.pdf
|
||||||
|
#define MADCTL_BIT_INDEX_COMMON_OUTPUTS_RAM 0 // N/A - set to 0
|
||||||
|
#define MADCTL_BIT_INDEX_SEGMENT_OUTPUTS_RAM 1 // N/A - set to 0
|
||||||
|
#define MADCTL_BIT_INDEX_DATA_LATCH_ORDER 2 // 0 = left-to-right refresh, 1 = right-to-left
|
||||||
|
#define MADCTL_BIT_INDEX_RGB_BGR_ORDER 3 // 0 = RGB, 1 = BGR
|
||||||
|
#define MADCTL_BIT_INDEX_LINE_ADDRESS_ORDER 4 // 0 = top-to-bottom refresh, 1 = bottom-to-top
|
||||||
|
#define MADCTL_BIT_INDEX_PAGE_COLUMN_ORDER 5 // 0 = normal, 1 = reverse
|
||||||
|
#define MADCTL_BIT_INDEX_COLUMN_ADDRESS_ORDER 6 // 0 = left-to-right, 1 = right-to-left
|
||||||
|
#define MADCTL_BIT_INDEX_PAGE_ADDRESS_ORDER 7 // 0 = top-to-bottom, 1 = bottom-to-top
|
||||||
|
|
||||||
|
void hx8357_reset(gpio_num_t resetPin);
|
||||||
|
void hx8357_init(gpio_num_t dcPin);
|
||||||
|
void hx8357_set_madctl(uint8_t value);
|
||||||
|
void hx8357_flush(lv_disp_t* drv, const lv_area_t* area, uint8_t* color_map);
|
||||||
|
|
||||||
|
uint8_t hx8357d_get_gamma_curve_count();
|
||||||
|
/**
|
||||||
|
* Note: this doesn't work, even though the manual says it should
|
||||||
|
* Page 141: https://cdn-shop.adafruit.com/datasheets/HX8357-D_DS_April2012.pdf
|
||||||
|
*/
|
||||||
|
void hx8357d_set_gamme_curve(uint8_t index);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*HX8357_H*/
|
||||||
7
Boards/UnPhone/Source/lvgl_spi_conf.h
Normal file
7
Boards/UnPhone/Source/lvgl_spi_conf.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SPI_TFT_CLOCK_SPEED_HZ (26*1000*1000)
|
||||||
|
#define SPI_TFT_SPI_MODE (0)
|
||||||
|
#define DISP_SPI_CS GPIO_NUM_48
|
||||||
|
#define DISP_SPI_INPUT_DELAY_NS 0
|
||||||
|
|
||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#define SDCARD_SPI_HOST SPI3_HOST
|
#define SDCARD_SPI_HOST SPI3_HOST
|
||||||
#define SDCARD_PIN_CS GPIO_NUM_5
|
#define SDCARD_PIN_CS GPIO_NUM_5
|
||||||
#define SDCARD_SPI_FREQUENCY 800000U
|
#define SDCARD_SPI_FREQUENCY 20000000U
|
||||||
|
|
||||||
std::shared_ptr<SdCard> createYellowSdCard() {
|
std::shared_ptr<SdCard> createYellowSdCard() {
|
||||||
auto* configuration = new tt::hal::SpiSdCard::Config(
|
auto* configuration = new tt::hal::SpiSdCard::Config(
|
||||||
|
|||||||
@ -42,6 +42,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
if(NOT "${IDF_TARGET}" STREQUAL "esp32s3")
|
if(NOT "${IDF_TARGET}" STREQUAL "esp32s3")
|
||||||
set(EXCLUDE_COMPONENTS "LilygoTdeck")
|
set(EXCLUDE_COMPONENTS "LilygoTdeck")
|
||||||
set(EXCLUDE_COMPONENTS "M5stackCoreS3")
|
set(EXCLUDE_COMPONENTS "M5stackCoreS3")
|
||||||
|
set(EXCLUDE_COMPONENTS "UnPhone")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# LVGL
|
# LVGL
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
The basic formatting rules are set in `.clang-format`. Use auto-formatting in your editor.
|
The basic formatting rules are set in `.clang-format`. Use auto-formatting in your editor.
|
||||||
|
|
||||||
All code should target C++ language revision 17.
|
All code should target C++ language revision 20.
|
||||||
|
|
||||||
|
If you use CLion, please enable the setting called "Enable ClangFormat" under Settings > Editor > Code Style.
|
||||||
|
|
||||||
## Naming
|
## Naming
|
||||||
|
|
||||||
@ -81,3 +83,7 @@ enum class {
|
|||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Exceptions
|
||||||
|
|
||||||
|
Don't ever throw them. Make a return type that wraps all the error and success scenarios that are relevant.
|
||||||
|
|||||||
@ -15,8 +15,12 @@
|
|||||||
- tt_check() failure during app argument bundle nullptr check seems to trigger SIGSEGV
|
- tt_check() failure during app argument bundle nullptr check seems to trigger SIGSEGV
|
||||||
- Fix bug in T-Deck/etc: esp_lvgl_port settings has a large stack size (~9kB) to fix an issue where the T-Deck would get a stackoverflow. This sometimes happens when WiFi is auto-enabled and you open the app while it is still connecting.
|
- Fix bug in T-Deck/etc: esp_lvgl_port settings has a large stack size (~9kB) to fix an issue where the T-Deck would get a stackoverflow. This sometimes happens when WiFi is auto-enabled and you open the app while it is still connecting.
|
||||||
- M5Stack Core only shows 4MB of SPIRAM in use
|
- M5Stack Core only shows 4MB of SPIRAM in use
|
||||||
|
- Try to improve Core2 and CoreS3 performance by setting swap_bytes of display driver to false (this is a software operation on the display buffer!) and use 24 bit colour mode if needed
|
||||||
|
|
||||||
# TODOs
|
# TODOs
|
||||||
|
- Boards' CMakeLists.txt manually declare each source folder. Update them all to do a recursive search of all folders.
|
||||||
|
- We currently make all boards for a given platform (e.g. ESP32S3), but it's better to filter all irrelevant ones based on the Kconfig board settings:
|
||||||
|
Projects will load and compile faster as it won't compile all the dependencies of all these other boards
|
||||||
- Make a ledger for setting CPU affinity of various services and tasks
|
- Make a ledger for setting CPU affinity of various services and tasks
|
||||||
- Make "blocking" argument the last one, and put it default to false (or remove it entirely?): void startApp(const std::string& id, bool blocking, std::shared_ptr<const Bundle> parameters) {
|
- Make "blocking" argument the last one, and put it default to false (or remove it entirely?): void startApp(const std::string& id, bool blocking, std::shared_ptr<const Bundle> parameters) {
|
||||||
- Boot hooks instead of a single boot method in config. Define different boot phases/levels in enum.
|
- Boot hooks instead of a single boot method in config. Define different boot phases/levels in enum.
|
||||||
|
|||||||
@ -14,9 +14,9 @@ struct Configuration {
|
|||||||
/** HAL configuration (drivers) */
|
/** HAL configuration (drivers) */
|
||||||
const hal::Configuration* hardware;
|
const hal::Configuration* hardware;
|
||||||
/** List of user applications */
|
/** List of user applications */
|
||||||
const std::vector<const app::AppManifest*> apps;
|
const std::vector<const app::AppManifest*> apps = {};
|
||||||
/** List of user services */
|
/** List of user services */
|
||||||
const std::vector<const service::ServiceManifest*> services;
|
const std::vector<const service::ServiceManifest*> services = {};
|
||||||
/** Optional app to start automatically after the splash screen. */
|
/** Optional app to start automatically after the splash screen. */
|
||||||
const char* _Nullable autoStartAppId = nullptr;
|
const char* _Nullable autoStartAppId = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -62,7 +62,7 @@ static void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t available_width = lv_display_get_horizontal_resolution(display) - (3 * 80);
|
int32_t available_width = lv_display_get_horizontal_resolution(display) - (3 * 80);
|
||||||
int32_t padding = TT_MIN(available_width / 4, 64);
|
int32_t padding = is_landscape_display ? TT_MIN(available_width / 4, 64) : 0;
|
||||||
|
|
||||||
auto paths = app.getPaths();
|
auto paths = app.getPaths();
|
||||||
auto apps_icon_path = paths->getSystemPathLvgl("icon_apps.png");
|
auto apps_icon_path = paths->getSystemPathLvgl("icon_apps.png");
|
||||||
|
|||||||
@ -74,7 +74,7 @@ bool SpiSdCard::mountInternal(const char* mountPoint) {
|
|||||||
// The following value is from T-Deck repo's UnitTest.ino project:
|
// The following value is from T-Deck repo's UnitTest.ino project:
|
||||||
// https://github.com/Xinyuan-LilyGO/T-Deck/blob/master/examples/UnitTest/UnitTest.ino
|
// https://github.com/Xinyuan-LilyGO/T-Deck/blob/master/examples/UnitTest/UnitTest.ino
|
||||||
// Observation: Using this automatically sets the bus to 20MHz
|
// Observation: Using this automatically sets the bus to 20MHz
|
||||||
host.max_freq_khz = config->spiFrequency;
|
host.max_freq_khz = config->spiFrequency / 1000U;
|
||||||
host.slot = config->spiHost;
|
host.slot = config->spiHost;
|
||||||
|
|
||||||
esp_err_t result = esp_vfs_fat_sdspi_mount(mountPoint, &host, &slot_config, &mount_config, &card);
|
esp_err_t result = esp_vfs_fat_sdspi_mount(mountPoint, &host, &slot_config, &mount_config, &card);
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT) == ESP_OK) {
|
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||||
out = (data[0] & 0x0F) << 8 | data[1];
|
out = (data[0] & 0x0F) << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -12,7 +12,7 @@ bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
|||||||
|
|
||||||
bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT) == ESP_OK) {
|
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||||
out = (data[0] & 0x3F) << 8 | data[1];
|
out = (data[0] & 0x3F) << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -22,7 +22,7 @@ bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
|||||||
|
|
||||||
bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT) == ESP_OK) {
|
if (tt::hal::i2c::masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
||||||
out = data[0] << 8 | data[1];
|
out = data[0] << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -1,7 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hal/i2c/I2c.h"
|
#include "./I2c.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an I2C peripheral at a specific port and address.
|
||||||
|
* It helps to read and write registers.
|
||||||
|
*
|
||||||
|
* All read and write calls are thread-safe.
|
||||||
|
*/
|
||||||
class I2cDevice {
|
class I2cDevice {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -18,7 +24,8 @@ protected:
|
|||||||
bool readRegister16(uint8_t reg, uint16_t& out) const;
|
bool readRegister16(uint8_t reg, uint16_t& out) const;
|
||||||
bool bitOn(uint8_t reg, uint8_t bitmask) const;
|
bool bitOn(uint8_t reg, uint8_t bitmask) const;
|
||||||
bool bitOff(uint8_t reg, uint8_t bitmask) const;
|
bool bitOff(uint8_t reg, uint8_t bitmask) const;
|
||||||
|
bool bitOnByIndex(uint8_t reg, uint8_t index) const { return bitOn(reg, 1 << index); }
|
||||||
|
bool bitOffByIndex(uint8_t reg, uint8_t index) const { return bitOff(reg, 1 << index); }
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit I2cDevice(i2c_port_t port, uint32_t address) : port(port), address(address) {}
|
explicit I2cDevice(i2c_port_t port, uint32_t address) : port(port), address(address) {}
|
||||||
@ -80,14 +80,6 @@ bool isStarted(i2c_port_t port) {
|
|||||||
return started;
|
return started;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read(i2c_port_t port, uint16_t address, uint32_t reg, uint8_t* buffer, uint16_t size, TickType_t timeout) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool write(i2c_port_t port, uint16_t address, uint32_t reg, const uint8_t* buffer, uint16_t size, TickType_t timeout) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lock(i2c_port_t port, TickType_t timeout) {
|
bool lock(i2c_port_t port, TickType_t timeout) {
|
||||||
return dataArray[port].mutex.lock(timeout);
|
return dataArray[port].mutex.lock(timeout);
|
||||||
}
|
}
|
||||||
@ -96,6 +88,30 @@ bool unlock(i2c_port_t port) {
|
|||||||
return dataArray[port].mutex.unlock();
|
return dataArray[port].mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool masterRead(i2c_port_t port, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterReadRegister(i2c_port_t port, uint8_t address, uint8_t reg, uint8_t* data, size_t dataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterWrite(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterWriteRegister(i2c_port_t port, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterWriteRegisterArray(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool masterWriteRead(i2c_port_t port, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool masterHasDeviceAtAddress(i2c_port_t port, uint8_t address, TickType_t timeout) {
|
bool masterHasDeviceAtAddress(i2c_port_t port, uint8_t address, TickType_t timeout) {
|
||||||
return (rand()) % 25 == 0;
|
return (rand()) % 25 == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,13 +60,12 @@ bool startMassStorageWithSdmmc() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = tusbStartMassStorageWithSdmmc();
|
if (tusbStartMassStorageWithSdmmc()) {
|
||||||
if (result != ESP_OK) {
|
|
||||||
TT_LOG_E(TAG, "Failed to init mass storage: %s", esp_err_to_name(result));
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
currentMode = Mode::MassStorageSdmmc;
|
currentMode = Mode::MassStorageSdmmc;
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
TT_LOG_E(TAG, "Failed to init mass storage");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -149,7 +149,12 @@ bool tusbStartMassStorageWithSdmmc() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return tinyusb_msc_storage_init_sdmmc(&config_sdmmc) == ESP_OK;
|
auto result = tinyusb_msc_storage_init_sdmmc(&config_sdmmc);
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
TT_LOG_E(TAG, "TinyUSB init failed: %s", esp_err_to_name(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result == ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tusbStop() {
|
void tusbStop() {
|
||||||
|
|||||||
52
sdkconfig.board.unphone
Normal file
52
sdkconfig.board.unphone
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Software defaults
|
||||||
|
# Increase stack size for WiFi (fixes crash after scan)
|
||||||
|
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072
|
||||||
|
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=4096
|
||||||
|
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||||
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
|
CONFIG_ELF_LOADER_CUSTOMER_SYMBOLS=y
|
||||||
|
CONFIG_FATFS_LFN_HEAP=y
|
||||||
|
CONFIG_FATFS_VOLUME_COUNT=3
|
||||||
|
|
||||||
|
# Hardware: Main
|
||||||
|
CONFIG_TT_BOARD_UNPHONE=y
|
||||||
|
CONFIG_IDF_TARGET="esp32s3"
|
||||||
|
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||||
|
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
CONFIG_FLASHMODE_QIO=y
|
||||||
|
# Hardware: SPI RAM
|
||||||
|
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
|
||||||
|
CONFIG_SPIRAM_MODE_OCT=y
|
||||||
|
CONFIG_SPIRAM_SPEED_80M=y
|
||||||
|
CONFIG_SPIRAM_USE_MALLOC=y
|
||||||
|
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||||
|
# LVGL
|
||||||
|
CONFIG_LV_DISP_DEF_REFR_PERIOD=17
|
||||||
|
CONFIG_LV_INDEV_DEF_READ_PERIOD=17
|
||||||
|
CONFIG_LV_DPI_DEF=139
|
||||||
|
CONFIG_LV_COLOR_DEPTH_24=y
|
||||||
|
CONFIG_LV_COLOR_DEPTH=24
|
||||||
|
# TinyUSB: Currently not working (no error in log, mounting takes minutes or more)
|
||||||
|
CONFIG_TINYUSB_MSC_ENABLED=n
|
||||||
|
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"
|
||||||
Loading…
x
Reference in New Issue
Block a user