Basic CPU affinity configuration

This commit is contained in:
Ken Van Hoeylandt 2025-08-19 23:45:40 +02:00
parent c809cea6c8
commit 75be23eca2
10 changed files with 130 additions and 14 deletions

View File

@ -13,7 +13,6 @@
- Mutex: Implement give/take from ISR support (works only for non-recursive ones)
- Extend unPhone power driver: add charging status, usb connection status, etc.
- Expose app::Paths to TactilityC
- Make a ledger for setting CPU affinity of various services and tasks
- CrashHandler: use "corrupted" flag
- CrashHandler: process other types of crashes (WDT?)
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.

View File

@ -11,6 +11,7 @@
#include <Tactility/kernel/SystemEvents.h>
#include <lvgl.h>
#include <Tactility/CpuAffinity.h>
#ifdef ESP_PLATFORM
#include "Tactility/app/crashdiagnostics/CrashDiagnostics.h"
@ -30,7 +31,12 @@ static std::shared_ptr<hal::display::DisplayDevice> getHalDisplay() {
class BootApp : public App {
Thread thread = Thread("boot", 4096, [] { return bootThreadCallback(); });
Thread thread = Thread(
"boot",
4096,
[] { return bootThreadCallback(); },
getCpuAffinityConfiguration().system
);
static void setupDisplay() {
const auto hal_display = getHalDisplay();

View File

@ -24,8 +24,6 @@ extern const AppManifest manifest;
class I2cScannerApp : public App {
private:
// Core
Mutex mutex = Mutex(Mutex::Type::Recursive);
std::unique_ptr<Timer> scanTimer = nullptr;
@ -286,7 +284,7 @@ void I2cScannerApp::startScanning() {
lv_obj_clean(scanListWidget);
scanState = ScanStateScanning;
scanTimer = std::make_unique<Timer>(Timer::Type::Once, [](){
scanTimer = std::make_unique<Timer>(Timer::Type::Once, []{
onScanTimerCallback();
});
scanTimer->start(10);

View File

@ -2,23 +2,23 @@
#include <Tactility/lvgl/LvglSync.h>
#include <esp_lvgl_port.h>
#include <Tactility/CpuAffinity.h>
#include <Tactility/Mutex.h>
// 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 TDECK_LVGL_TASK_STACK_DEPTH 9216
#define TAG "lvgl"
auto constexpr TAG = "lvgl";
namespace tt::lvgl {
bool initEspLvglPort() {
TT_LOG_D(TAG, "Port init");
static lv_disp_t* display = nullptr;
const lvgl_port_cfg_t lvgl_cfg = {
.task_priority = static_cast<UBaseType_t>(Thread::Priority::Critical),
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
.task_affinity = 1, // -1 = disabled, 0 = core 1, 1 = core 2
.task_affinity = getCpuAffinityConfiguration().graphics,
.task_max_sleep_ms = 500,
.timer_period_ms = 5
};
@ -28,7 +28,7 @@ bool initEspLvglPort() {
return false;
}
tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock);
syncSet(&lvgl_port_lock, &lvgl_port_unlock);
return true;
}

View File

@ -13,7 +13,6 @@
#endif
#include <lvgl.h>
#include <Tactility/Tactility.h>
#include <Tactility/TactilityHeadless.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/service/ServiceRegistry.h>

View File

@ -11,6 +11,7 @@
#include <Tactility/TactilityCore.h>
#include <format>
#include <Tactility/CpuAffinity.h>
namespace tt::service::screenshot {
@ -109,10 +110,11 @@ void ScreenshotTask::taskStart() {
thread = new Thread(
"screenshot",
8192,
[this]() {
[this] {
this->taskMain();
return 0;
}
},
getCpuAffinityConfiguration().graphics
);
thread->start();
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "RtosCompat.h"
namespace tt {
typedef portBASE_TYPE CpuAffinity;
constexpr static CpuAffinity None = -1;
/**
* Determines the preferred affinity for certain (sub)systems.
*/
struct CpuAffinityConfiguration {
CpuAffinity system;
CpuAffinity graphics; // Display, LVGL
CpuAffinity wifi;
CpuAffinity mainDispatcher;
CpuAffinity apps;
CpuAffinity timer; // Tactility Timer (based on FreeRTOS)
};
void setCpuAffinityConfiguration(const CpuAffinityConfiguration& config);
const CpuAffinityConfiguration& getCpuAffinityConfiguration();
}

View File

@ -18,7 +18,7 @@ public:
private:
struct TimerHandleDeleter {
void operator()(TimerHandle_t handleToDelete) {
void operator()(TimerHandle_t handleToDelete) const {
xTimerDelete(handleToDelete, portMAX_DELAY);
}
};

View File

@ -0,0 +1,85 @@
#include "Tactility/CpuAffinity.h"
#include <Tactility/Check.h>
namespace tt {
#ifdef ESP_PLATFORM
static CpuAffinity getEspWifiAffinity() {
#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0
return 0;
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
return 1;
#endif
}
// Warning: Must watch ESP WiFi, as this task is used by WiFi
static CpuAffinity getEspMainSchedulerAffinity() {
#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0
return 0;
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
return 1;
#endif
}
static CpuAffinity getFreeRtosTimerAffinity() {
#if defined(CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY)
return None;
#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0)
return 0;
#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1)
return 1;
#else
static_assert(false);
#endif
}
#if CONFIG_FREERTOS_NUMBER_OF_CORES == 1
static const CpuAffinityConfiguration esp = {
.system = 0,
.graphics = 0,
.wifi = 0,
.mainDispatcher = 0,
.apps = 0,
.timer = getFreeRtosTimerAffinity()
};
#elif CONFIG_FREERTOS_NUMBER_OF_CORES == 2
static const CpuAffinityConfiguration esp = {
.system = 0,
.graphics = 1,
.wifi = getEspWifiAffinity(),
.mainDispatcher = getEspMainSchedulerAffinity(),
.apps = 1,
.timer = getFreeRtosTimerAffinity()
};
#endif
#else
static const CpuAffinityConfiguration simulator = {
.system = None,
.graphics = None,
.wifi = None,
.mainDispatcher = 0,
.apps = None,
.timer = None
};
#endif
const CpuAffinityConfiguration& getCpuAffinityConfiguration() {
#ifdef ESP_PLATFORM
#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2
// WiFi uses the main dispatcher to defer operations in the background
assert(esp.wifi == esp.mainDispatcher);
#endif // CORES
return esp;
#else
return simulator;
#endif
}
}

View File

@ -13,7 +13,7 @@ void Timer::onCallback(TimerHandle_t hTimer) {
}
}
static inline TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) {
static TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) {
assert(timerId != nullptr);
assert(callback != nullptr);