| 187 | static constexpr size_t kMinStackSize = 2048; |
| 188 | |
| 189 | TaskCoroutinePtr TaskCoroutineESP32::create( |
| 190 | fl::string name, |
| 191 | TaskFunction function, |
| 192 | size_t stack_size, |
| 193 | u8 priority, |
| 194 | int core_id) FL_NOEXCEPT { |
| 195 | if (stack_size < kMinStackSize) { |
| 196 | stack_size = kMinStackSize; |
| 197 | } |
| 198 | |
| 199 | // Resolve requested core_id against platform capabilities. An out-of-range |
| 200 | // or negative value is silently downgraded to tskNO_AFFINITY — the caller's |
| 201 | // task still runs, just without affinity. This matches the existing |
| 202 | // behaviour where every caller was implicitly tskNO_AFFINITY. |
| 203 | BaseType_t affinity = tskNO_AFFINITY; |
| 204 | if (core_id >= 0 && core_id < FL_CPU_CORES) { |
| 205 | affinity = static_cast<BaseType_t>(core_id); |
| 206 | } |
| 207 | |
| 208 | TaskCoroutinePtr task(new TaskCoroutineESP32()) FL_NOEXCEPT; // ok bare allocation |
| 209 | auto* impl = static_cast<TaskCoroutineESP32*>(task.get()); |
| 210 | impl->mName = fl::move(name); |
| 211 | impl->mFunction = fl::move(function); |
| 212 | |
| 213 | #if ESP_IDF_VERSION_4_OR_HIGHER |
| 214 | // IDF 4.0+: Allocate stack + TCB in internal RAM — SPIRAM crashes on ESP32-P4 |
| 215 | impl->mStackBuf.reset(static_cast<StackType_t*>( |
| 216 | heap_caps_malloc(stack_size * sizeof(StackType_t), |
| 217 | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))); |
| 218 | impl->mTaskTcb.reset(static_cast<StaticTask_t*>( |
| 219 | heap_caps_malloc(sizeof(StaticTask_t), |
| 220 | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))); |
| 221 | if (!impl->mStackBuf || !impl->mTaskTcb) { |
| 222 | FL_WARN("TaskCoroutineESP32: Failed to allocate stack/TCB for '" |
| 223 | << impl->mName << "'"); |
| 224 | task.reset(); |
| 225 | return nullptr; |
| 226 | } |
| 227 | |
| 228 | impl->mTask = xTaskCreateStaticPinnedToCore( |
| 229 | task_entry, |
| 230 | impl->mName.c_str(), |
| 231 | stack_size, |
| 232 | impl, // param = this |
| 233 | tskIDLE_PRIORITY + priority, |
| 234 | impl->mStackBuf.get(), |
| 235 | impl->mTaskTcb.get(), |
| 236 | affinity); |
| 237 | #else |
| 238 | // IDF 3.x: xTaskCreateStaticPinnedToCore may not be available |
| 239 | // (configSUPPORT_STATIC_ALLOCATION not guaranteed). Use dynamic |
| 240 | // allocation variant instead. |
| 241 | BaseType_t rc = xTaskCreatePinnedToCore( |
| 242 | task_entry, |
| 243 | impl->mName.c_str(), |
| 244 | stack_size, |
| 245 | impl, // param = this |
| 246 | tskIDLE_PRIORITY + priority, |