mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
Enable configSUPPORT_STATIC_ALLOCATION on BK72xx
Add build flag and required callbacks (following ESP-IDF's pvPortMalloc approach) so FreeRTOSQueue can use xQueueCreateStatic — queue storage lives in BSS with zero runtime heap allocation.
This commit is contained in:
@@ -438,6 +438,11 @@ async def component_to_code(config):
|
||||
# 4-8KB flash). Even if linked, it would use locks, so explicit FreeRTOS
|
||||
# mutexes are simpler and equivalent.
|
||||
cg.add_define(ThreadModel.MULTI_NO_ATOMICS)
|
||||
# Enable FreeRTOS static allocation so FreeRTOSQueue can use
|
||||
# xQueueCreateStatic (queue storage in BSS, no heap allocation).
|
||||
# BK72xx's FreeRTOSConfig.h doesn't define this, defaulting to 0.
|
||||
# The -D wins over the #ifndef default in FreeRTOS.h.
|
||||
cg.add_build_flag("-DconfigSUPPORT_STATIC_ALLOCATION=1")
|
||||
|
||||
# RTL8710B needs FreeRTOS 8.2.3+ for xTaskNotifyGive/ulTaskNotifyTake
|
||||
# required by AsyncTCP 3.4.3+ (https://github.com/esphome/esphome/issues/10220)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* FreeRTOS static allocation callbacks for LibreTiny platforms.
|
||||
*
|
||||
* Required when configSUPPORT_STATIC_ALLOCATION is enabled. These callbacks
|
||||
* provide memory for the idle and timer tasks. Following ESP-IDF's approach,
|
||||
* we allocate from the FreeRTOS heap (pvPortMalloc) rather than using truly
|
||||
* static buffers, to avoid assumptions about memory layout.
|
||||
*
|
||||
* This enables xQueueCreateStatic, xTaskCreateStatic, etc. throughout ESPHome,
|
||||
* allowing queue storage to live in BSS with zero runtime heap allocation.
|
||||
*/
|
||||
|
||||
#ifdef USE_BK72XX
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||
|
||||
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer,
|
||||
uint32_t *pulIdleTaskStackSize) {
|
||||
/* Stack grows down on ARM — allocate stack first, then TCB,
|
||||
* so the stack does not grow into the TCB. */
|
||||
StackType_t *stack = (StackType_t *) pvPortMalloc(configMINIMAL_STACK_SIZE * sizeof(StackType_t));
|
||||
StaticTask_t *tcb = (StaticTask_t *) pvPortMalloc(sizeof(StaticTask_t));
|
||||
|
||||
*ppxIdleTaskTCBBuffer = tcb;
|
||||
*ppxIdleTaskStackBuffer = stack;
|
||||
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
||||
}
|
||||
|
||||
#if (configUSE_TIMERS == 1)
|
||||
|
||||
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer,
|
||||
uint32_t *pulTimerTaskStackSize) {
|
||||
StackType_t *stack = (StackType_t *) pvPortMalloc(configTIMER_TASK_STACK_DEPTH * sizeof(StackType_t));
|
||||
StaticTask_t *tcb = (StaticTask_t *) pvPortMalloc(sizeof(StaticTask_t));
|
||||
|
||||
*ppxTimerTaskTCBBuffer = tcb;
|
||||
*ppxTimerTaskStackBuffer = stack;
|
||||
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
||||
}
|
||||
|
||||
#endif /* configUSE_TIMERS */
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
#endif /* USE_BK72XX */
|
||||
@@ -16,7 +16,8 @@
|
||||
*
|
||||
* Provides the same API as LockFreeQueue (push, pop, get_and_reset_dropped_count,
|
||||
* empty, full, size) but uses xQueue internally, which synchronizes via
|
||||
* FreeRTOS critical sections.
|
||||
* FreeRTOS critical sections. Uses xQueueCreateStatic so the queue storage
|
||||
* lives in BSS with zero runtime heap allocation.
|
||||
*
|
||||
* @tparam T The type of elements stored in the queue (stored as pointers)
|
||||
* @tparam SIZE The maximum number of elements
|
||||
@@ -26,7 +27,9 @@ namespace esphome {
|
||||
|
||||
template<class T, uint8_t SIZE> class FreeRTOSQueue {
|
||||
public:
|
||||
FreeRTOSQueue() : dropped_count_(0) { this->handle_ = xQueueCreate(SIZE, sizeof(T *)); }
|
||||
FreeRTOSQueue() : dropped_count_(0) {
|
||||
this->handle_ = xQueueCreateStatic(SIZE, sizeof(T *), this->storage_, &this->queue_buf_);
|
||||
}
|
||||
|
||||
// Non-copyable, non-movable — queue handle is not transferable
|
||||
FreeRTOSQueue(const FreeRTOSQueue &) = delete;
|
||||
@@ -35,7 +38,7 @@ template<class T, uint8_t SIZE> class FreeRTOSQueue {
|
||||
FreeRTOSQueue &operator=(FreeRTOSQueue &&) = delete;
|
||||
|
||||
bool push(T *element) {
|
||||
if (element == nullptr || this->handle_ == nullptr)
|
||||
if (element == nullptr)
|
||||
return false;
|
||||
|
||||
if (xQueueSend(this->handle_, &element, 0) != pdPASS) {
|
||||
@@ -46,9 +49,6 @@ template<class T, uint8_t SIZE> class FreeRTOSQueue {
|
||||
}
|
||||
|
||||
T *pop() {
|
||||
if (this->handle_ == nullptr)
|
||||
return nullptr;
|
||||
|
||||
T *element;
|
||||
if (xQueueReceive(this->handle_, &element, 0) != pdTRUE) {
|
||||
return nullptr;
|
||||
@@ -74,25 +74,16 @@ template<class T, uint8_t SIZE> class FreeRTOSQueue {
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
if (this->handle_ == nullptr)
|
||||
return true;
|
||||
return uxQueueMessagesWaiting(this->handle_) == 0;
|
||||
}
|
||||
bool empty() const { return uxQueueMessagesWaiting(this->handle_) == 0; }
|
||||
|
||||
bool full() const {
|
||||
if (this->handle_ == nullptr)
|
||||
return true;
|
||||
return uxQueueSpacesAvailable(this->handle_) == 0;
|
||||
}
|
||||
bool full() const { return uxQueueSpacesAvailable(this->handle_) == 0; }
|
||||
|
||||
size_t size() const {
|
||||
if (this->handle_ == nullptr)
|
||||
return 0;
|
||||
return uxQueueMessagesWaiting(this->handle_);
|
||||
}
|
||||
size_t size() const { return uxQueueMessagesWaiting(this->handle_); }
|
||||
|
||||
protected:
|
||||
// Static storage for the queue — lives in BSS, no heap allocation
|
||||
uint8_t storage_[SIZE * sizeof(T *)];
|
||||
StaticQueue_t queue_buf_;
|
||||
QueueHandle_t handle_;
|
||||
uint16_t dropped_count_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user