mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-16 04:22:22 +00:00
feat(pthread): Pthread can now use PSRAM as stack
Closes https://github.com/espressif/esp-idf/pull/10623 Closes https://github.com/espressif/esp-idf/issues/8662 Thanks to f-hoepfinger-hr-agrartechnik for the contribution in https://github.com/espressif/esp-idf/pull/10623
This commit is contained in:
6
components/pthread/test_apps/.build-test-rules.yml
Normal file
6
components/pthread/test_apps/.build-test-rules.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
|
||||
|
||||
components/pthread/test_apps/pthread_psram_tests:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32"]
|
||||
reason: PSRAM only available on ESP32, S2, S3; code is fairly generic
|
||||
@@ -0,0 +1,13 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
set(COMPONENTS main esp_psram)
|
||||
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") # For test_utils component
|
||||
|
||||
project(pthread_psram_tests)
|
||||
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "pthread_psram_tests.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils pthread) # note: esp_psram is set in the project's CMakeLists.txt
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "memory_checks.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_pthread.h"
|
||||
#include <errno.h>
|
||||
#include "pthread.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
esp_pthread_cfg_t config = esp_pthread_get_default_config();
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&config));
|
||||
test_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
test_utils_finish_and_evaluate_leaks(0, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("esp_pthread_get_default_config creates correct stack memory capabilities", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t default_config = esp_pthread_get_default_config();
|
||||
|
||||
// The default must always be internal, 8-bit accessible RAM
|
||||
TEST_ASSERT_EQUAL_HEX(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, default_config.stack_alloc_caps);
|
||||
}
|
||||
|
||||
TEST_CASE("correct memory is accepted", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t default_config = esp_pthread_get_default_config();
|
||||
|
||||
default_config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config));
|
||||
}
|
||||
|
||||
TEST_CASE("Setting stack with heap caps 0 sets the default value", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t config = { .stack_size = 4096 }; // all other values are set to 0
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&config));
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_get_cfg(&config));
|
||||
TEST_ASSERT_EQUAL(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, config.stack_alloc_caps);
|
||||
}
|
||||
|
||||
TEST_CASE("Setting stack with non 8-bit caps fails", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t config = esp_pthread_get_default_config();
|
||||
config.stack_alloc_caps = MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&config));
|
||||
}
|
||||
|
||||
static void *check_stack_in_spiram(void *arg)
|
||||
{
|
||||
int ret_value;
|
||||
if (esp_ptr_internal(&ret_value)) {
|
||||
ret_value = 0;
|
||||
} else {
|
||||
ret_value = 1;
|
||||
}
|
||||
vTaskDelay(2); // ensure the test task has time to continue execution
|
||||
pthread_exit((void *) ret_value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST_CASE("pthread_create fails because out of PSRAM", "[psram]")
|
||||
{
|
||||
esp_pthread_cfg_t config = esp_pthread_get_default_config();
|
||||
config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM;
|
||||
config.stack_size = 0xFFFFFFFF; // far larger than the virtual address space on ESP32
|
||||
pthread_t pthread_object = (pthread_t)NULL;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&config));
|
||||
|
||||
TEST_ASSERT_EQUAL(ENOMEM, pthread_create(&pthread_object, NULL, check_stack_in_spiram, NULL));
|
||||
}
|
||||
|
||||
TEST_CASE("pthread create large PSRAM stack", "[psram]")
|
||||
{
|
||||
esp_pthread_cfg_t config = esp_pthread_get_default_config();
|
||||
config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM;
|
||||
config.stack_size = 0x80000; // value is too large for any internal RAM on current chips
|
||||
int res = -1;
|
||||
int thread_rval = -1;
|
||||
pthread_t pthread_object = (pthread_t)NULL;
|
||||
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&config));
|
||||
|
||||
res = pthread_create(&pthread_object, NULL, check_stack_in_spiram, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(0, res);
|
||||
|
||||
res = pthread_join(pthread_object, (void*) &thread_rval);
|
||||
TEST_ASSERT_EQUAL_INT(0, res);
|
||||
TEST_ASSERT_EQUAL_INT(1, thread_rval);
|
||||
|
||||
// Add a short delay to allow the idle task to free any remaining memory
|
||||
vTaskDelay(2);
|
||||
}
|
||||
|
||||
TEST_CASE("pthread with stack in internal RAM", "[psram]")
|
||||
{
|
||||
int res = -1;
|
||||
int thread_rval = -1;
|
||||
pthread_t pthread_object = (pthread_t)NULL;
|
||||
|
||||
res = pthread_create(&pthread_object, NULL, check_stack_in_spiram, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(0, res);
|
||||
|
||||
res = pthread_join(pthread_object, (void*) &thread_rval);
|
||||
TEST_ASSERT_EQUAL_INT(0, res);
|
||||
TEST_ASSERT_EQUAL_INT(0, thread_rval);
|
||||
|
||||
// Add a short delay to allow the idle task to free any remaining memory
|
||||
vTaskDelay(2);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
vTaskPrioritySet(NULL, CONFIG_UNITY_FREERTOS_PRIORITY);
|
||||
printf("pthread PSRAM Test");
|
||||
unity_run_menu();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
def test_pthread_psram(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(timeout=10)
|
||||
@@ -0,0 +1,5 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y
|
||||
CONFIG_SPIRAM=y
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@@ -13,6 +13,33 @@
|
||||
|
||||
#include "unity.h"
|
||||
|
||||
TEST_CASE("esp_pthread_get_default_config creates correct stack memory capabilities", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t default_config = esp_pthread_get_default_config();
|
||||
|
||||
// The default must always be internal, 8-bit accessible RAM
|
||||
TEST_ASSERT_EQUAL_HEX(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, default_config.stack_alloc_caps);
|
||||
}
|
||||
|
||||
TEST_CASE("wrong heap caps are rejected", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t default_config = esp_pthread_get_default_config();
|
||||
|
||||
default_config.stack_alloc_caps = MALLOC_CAP_32BIT;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config));
|
||||
|
||||
default_config.stack_alloc_caps = MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_pthread_set_cfg(&default_config));
|
||||
}
|
||||
|
||||
TEST_CASE("correct memory is accepted", "[set_cfg]")
|
||||
{
|
||||
esp_pthread_cfg_t default_config = esp_pthread_get_default_config();
|
||||
|
||||
default_config.stack_alloc_caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_pthread_set_cfg(&default_config));
|
||||
}
|
||||
|
||||
static void *compute_square(void *arg)
|
||||
{
|
||||
int *num = (int *) arg;
|
||||
|
||||
Reference in New Issue
Block a user