mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/ulp_mutex' into 'master'
ulp-riscv: mutex/lock Closes IDF-5754 See merge request espressif/esp-idf!19377
This commit is contained in:
commit
f54972d95d
@ -24,10 +24,12 @@ if(CONFIG_SOC_ULP_SUPPORTED OR CONFIG_SOC_RISCV_COPROC_SUPPORTED)
|
||||
elseif(CONFIG_ULP_COPROC_TYPE_RISCV)
|
||||
list(APPEND srcs
|
||||
"ulp_riscv/ulp_riscv.c"
|
||||
"ulp_riscv/ulp_riscv_lock.c"
|
||||
"ulp_riscv/ulp_riscv_adc.c")
|
||||
|
||||
list(APPEND includes
|
||||
ulp_riscv/include)
|
||||
ulp_riscv/include
|
||||
ulp_riscv/shared/include)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -75,6 +75,7 @@ if(ULP_COCPU_IS_RISCV)
|
||||
list(APPEND ULP_S_SOURCES
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/start.S"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_adc.c"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_lock.c"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_uart.c"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_print.c"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_utils.c")
|
||||
@ -100,7 +101,8 @@ if(ULP_COCPU_IS_RISCV)
|
||||
list(APPEND EXTRA_LINKER_ARGS "-Wl,--gc-sections")
|
||||
list(APPEND EXTRA_LINKER_ARGS "-Wl,-Map=\"${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}.map\"")
|
||||
#Makes the csr utillies for riscv visible:
|
||||
target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/include")
|
||||
target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/include"
|
||||
"${IDF_PATH}/components/ulp/ulp_riscv/shared/include")
|
||||
target_link_libraries(${ULP_APP_NAME} "-T \"${IDF_PATH}/components/ulp/ld/${IDF_TARGET}.periperals.ld\"")
|
||||
target_compile_definitions(${ULP_APP_NAME} PRIVATE IS_ULP_COCPU)
|
||||
|
||||
|
@ -2,6 +2,7 @@ set(app_sources "test_app_main.c" "test_ulp_riscv.c")
|
||||
set(ulp_sources "ulp/test_main.c")
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "ulp"
|
||||
REQUIRES ulp unity
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
|
@ -12,27 +12,14 @@
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/rtc_periph.h"
|
||||
#include "ulp_riscv.h"
|
||||
#include "ulp_riscv_lock.h"
|
||||
#include "ulp_test_app.h"
|
||||
#include "ulp_test_shared.h"
|
||||
#include "unity.h"
|
||||
#include <sys/time.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
typedef enum{
|
||||
RISCV_READ_WRITE_TEST = 1,
|
||||
RISCV_DEEP_SLEEP_WAKEUP_TEST,
|
||||
RISCV_LIGHT_SLEEP_WAKEUP_TEST,
|
||||
RISCV_STOP_TEST,
|
||||
RISCV_NO_COMMAND,
|
||||
} riscv_test_commands_t;
|
||||
|
||||
typedef enum {
|
||||
RISCV_COMMAND_OK = 1,
|
||||
RISCV_COMMAND_NOK,
|
||||
RISCV_COMMAND_INVALID,
|
||||
} riscv_test_command_reply_t;
|
||||
|
||||
#define XOR_MASK 0xDEADBEEF
|
||||
#define ULP_WAKEUP_PERIOD 1000000 // 1 second
|
||||
|
||||
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_test_app_bin_start");
|
||||
@ -212,3 +199,31 @@ TEST_CASE("ULP-RISC-V is able to wakeup main CPU from deep sleep", "[ulp][reset=
|
||||
esp_deep_sleep_start();
|
||||
UNITY_TEST_FAIL(__LINE__, "Should not get here!");
|
||||
}
|
||||
|
||||
TEST_CASE("ULP-RISC-V mutex", "[ulp]")
|
||||
{
|
||||
/* Load ULP RISC-V firmware and start the ULP RISC-V Coprocessor */
|
||||
load_and_start_ulp_firmware();
|
||||
|
||||
/* Setup test data */
|
||||
ulp_riscv_incrementer = 0;
|
||||
ulp_main_cpu_reply = RISCV_NO_COMMAND;
|
||||
ulp_main_cpu_command = RISCV_MUTEX_TEST;
|
||||
|
||||
ulp_riscv_lock_t *lock = (ulp_riscv_lock_t*)&ulp_lock;
|
||||
|
||||
for (int i = 0; i < MUTEX_TEST_ITERATIONS; i++) {
|
||||
ulp_riscv_lock_acquire(lock);
|
||||
ulp_riscv_incrementer++;
|
||||
ulp_riscv_lock_release(lock);
|
||||
}
|
||||
|
||||
while(ulp_main_cpu_reply != RISCV_COMMAND_OK) {
|
||||
// Wait for ULP to finish
|
||||
}
|
||||
|
||||
/* If the variable is protected there should be no race conditions
|
||||
results should be the sum of increments made by ULP and by main CPU
|
||||
*/
|
||||
TEST_ASSERT_EQUAL(2*MUTEX_TEST_ITERATIONS, ulp_riscv_incrementer);
|
||||
}
|
||||
|
@ -9,22 +9,9 @@
|
||||
#include <stdbool.h>
|
||||
#include "ulp_riscv_utils.h"
|
||||
#include "ulp_riscv_gpio.h"
|
||||
#include "ulp_riscv_lock_ulp_core.h"
|
||||
#include "ulp_test_shared.h"
|
||||
|
||||
typedef enum{
|
||||
RISCV_READ_WRITE_TEST = 1,
|
||||
RISCV_DEEP_SLEEP_WAKEUP_TEST,
|
||||
RISCV_LIGHT_SLEEP_WAKEUP_TEST,
|
||||
RISCV_STOP_TEST,
|
||||
RISCV_NO_COMMAND,
|
||||
} riscv_test_commands_t;
|
||||
|
||||
typedef enum {
|
||||
RISCV_COMMAND_OK = 1,
|
||||
RISCV_COMMAND_NOK,
|
||||
RISCV_COMMAND_INVALID,
|
||||
} riscv_test_command_reply_t;
|
||||
|
||||
#define XOR_MASK 0xDEADBEEF
|
||||
|
||||
volatile riscv_test_commands_t main_cpu_command = RISCV_NO_COMMAND;
|
||||
volatile riscv_test_command_reply_t main_cpu_reply = RISCV_COMMAND_INVALID;
|
||||
@ -33,6 +20,9 @@ volatile uint32_t riscv_test_data_in = 0;
|
||||
volatile uint32_t riscv_test_data_out = 0;
|
||||
volatile uint32_t riscv_counter = 0;
|
||||
|
||||
volatile uint32_t riscv_incrementer = 0;
|
||||
ulp_riscv_lock_t lock;
|
||||
|
||||
void handle_commands(riscv_test_commands_t cmd)
|
||||
{
|
||||
riscv_counter++;
|
||||
@ -87,6 +77,21 @@ void handle_commands(riscv_test_commands_t cmd)
|
||||
|
||||
break;
|
||||
|
||||
case RISCV_MUTEX_TEST:
|
||||
/* Echo the command ID back to the main CPU */
|
||||
command_resp = RISCV_MUTEX_TEST;
|
||||
|
||||
for (int i = 0; i < MUTEX_TEST_ITERATIONS; i++) {
|
||||
ulp_riscv_lock_acquire(&lock);
|
||||
riscv_incrementer++;
|
||||
ulp_riscv_lock_release(&lock);
|
||||
}
|
||||
/* Set the command reply status */
|
||||
main_cpu_reply = RISCV_COMMAND_OK;
|
||||
main_cpu_command = RISCV_NO_COMMAND;
|
||||
|
||||
break;
|
||||
|
||||
case RISCV_NO_COMMAND:
|
||||
main_cpu_reply = RISCV_COMMAND_OK;
|
||||
break;
|
||||
@ -99,6 +104,7 @@ void handle_commands(riscv_test_commands_t cmd)
|
||||
|
||||
int main (void)
|
||||
{
|
||||
|
||||
while (1) {
|
||||
handle_commands(main_cpu_command);
|
||||
break;
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define MUTEX_TEST_ITERATIONS 100000
|
||||
#define XOR_MASK 0xDEADBEEF
|
||||
|
||||
typedef enum{
|
||||
RISCV_READ_WRITE_TEST = 1,
|
||||
RISCV_DEEP_SLEEP_WAKEUP_TEST,
|
||||
RISCV_LIGHT_SLEEP_WAKEUP_TEST,
|
||||
RISCV_STOP_TEST,
|
||||
RISCV_MUTEX_TEST,
|
||||
RISCV_NO_COMMAND,
|
||||
} riscv_test_commands_t;
|
||||
|
||||
typedef enum {
|
||||
RISCV_COMMAND_OK = 1,
|
||||
RISCV_COMMAND_NOK,
|
||||
RISCV_COMMAND_INVALID,
|
||||
} riscv_test_command_reply_t;
|
38
components/ulp/ulp_riscv/include/ulp_riscv_lock.h
Normal file
38
components/ulp/ulp_riscv/include/ulp_riscv_lock.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
/**
|
||||
* @brief Locks are based on the Peterson's algorithm, https://en.wikipedia.org/wiki/Peterson%27s_algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Acquire the lock, preventing the ULP from taking until released. Spins until lock is acquired.
|
||||
*
|
||||
* @note The lock is only designed for being used by a single thread on the main CPU,
|
||||
* it is not safe to try to acquire it from multiple threads.
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with ULP
|
||||
*/
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Release the lock
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with ULP
|
||||
*/
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enum representing which processor is allowed to enter the critical section
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ULP_RISCV_LOCK_TURN_ULP, /*!< ULP's turn to enter the critical section */
|
||||
ULP_RISCV_LOCK_TURN_MAIN_CPU, /*!< Main CPU's turn to enter the critical section */
|
||||
} ulp_riscv_lock_turn_t;
|
||||
|
||||
/**
|
||||
* @brief Structure representing a lock shared between ULP and main CPU
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
volatile bool critical_section_flag_ulp; /*!< ULP wants to enter the critical sections */
|
||||
volatile bool critical_section_flag_main_cpu; /*!< Main CPU wants to enter the critical sections */
|
||||
volatile ulp_riscv_lock_turn_t turn; /*!< Which CPU is allowed to enter the critical section */
|
||||
} ulp_riscv_lock_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Locks are based on the Peterson's algorithm, https://en.wikipedia.org/wiki/Peterson%27s_algorithm
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Acquire the lock, preventing the main CPU from taking until released. Spins until lock is acquired.
|
||||
*
|
||||
* @note The lock is only designed for being used by a single thread on the ULP,
|
||||
* it is not safe to try to acquire it from multiple threads.
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with main CPU
|
||||
*/
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock);
|
||||
|
||||
/**
|
||||
* @brief Release the lock
|
||||
*
|
||||
* @param lock Pointer to lock struct, shared with main CPU
|
||||
*/
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
21
components/ulp/ulp_riscv/ulp_core/ulp_riscv_lock.c
Normal file
21
components/ulp/ulp_riscv/ulp_core/ulp_riscv_lock.c
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ulp_riscv_lock.h"
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
lock->critical_section_flag_ulp = true;
|
||||
lock->turn = ULP_RISCV_LOCK_TURN_MAIN_CPU;
|
||||
|
||||
while (lock->critical_section_flag_main_cpu && (lock->turn == ULP_RISCV_LOCK_TURN_MAIN_CPU)) {
|
||||
}
|
||||
}
|
||||
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
lock->critical_section_flag_ulp = false;
|
||||
}
|
27
components/ulp/ulp_riscv/ulp_riscv_lock.c
Normal file
27
components/ulp/ulp_riscv/ulp_riscv_lock.c
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "ulp_riscv_lock.h"
|
||||
#include "ulp_riscv_lock_shared.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void ulp_riscv_lock_acquire(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
lock->critical_section_flag_main_cpu = true;
|
||||
lock->turn = ULP_RISCV_LOCK_TURN_ULP;
|
||||
|
||||
while (lock->critical_section_flag_ulp && (lock->turn == ULP_RISCV_LOCK_TURN_ULP)) {
|
||||
}
|
||||
}
|
||||
|
||||
void ulp_riscv_lock_release(ulp_riscv_lock_t *lock)
|
||||
{
|
||||
assert(lock);
|
||||
|
||||
lock->critical_section_flag_main_cpu = false;
|
||||
}
|
@ -25,6 +25,8 @@ INPUT += \
|
||||
$(PROJECT_PATH)/components/touch_element/include/touch_element/touch_slider.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_common/include/$(IDF_TARGET)/ulp_common_defs.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_fsm/include/$(IDF_TARGET)/ulp.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_riscv/include/ulp_riscv_lock.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_riscv/shared/include/ulp_riscv_lock_shared.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_types_ch9.h \
|
||||
|
@ -31,6 +31,8 @@ INPUT += \
|
||||
$(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/touch_sensor_channel.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_common/include/$(IDF_TARGET)/ulp_common_defs.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_fsm/include/$(IDF_TARGET)/ulp.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_riscv/include/ulp_riscv_lock.h \
|
||||
$(PROJECT_PATH)/components/ulp/ulp_riscv/shared/include/ulp_riscv_lock_shared.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
|
||||
$(PROJECT_PATH)/components/usb/include/usb/usb_types_ch9.h \
|
||||
|
@ -98,6 +98,18 @@ To access the ULP RISC-V program variables from the main program, the generated
|
||||
ulp_measurement_count = 64;
|
||||
}
|
||||
|
||||
Mutual Exclusion
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
If mutual exclusion is needed when accessing a variable shared between the main program and ULP then this can be achieved by using the ULP RISC-V lock API:
|
||||
|
||||
* :cpp:func:`ulp_riscv_lock_acquire`
|
||||
* :cpp:func:`ulp_riscv_lock_release`
|
||||
|
||||
The ULP does not have any hardware instructions to facilitate mutual exclusion so the lock API achieves this through a software algorithm (`Peterson's algorithm <https://en.wikipedia.org/wiki/Peterson%27s_algorithm>`_).
|
||||
|
||||
The locks are intended to only be called from a single thread in the main program, and will not provide mutual exclusion if used simultaneously from multiple threads.
|
||||
|
||||
Starting the ULP RISC-V Program
|
||||
-------------------------------
|
||||
|
||||
@ -152,7 +164,6 @@ Keeping this in mind, here are some ways that may help you debug you ULP RISC-V
|
||||
|
||||
* Trap signal: the ULP RISC-V has a hardware trap that will trigger under certain conditions, e.g., illegal instruction. This will cause the main CPU to be woken up with the wake-up cause :cpp:enumerator:`ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG`.
|
||||
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
@ -164,3 +175,5 @@ API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/ulp_riscv.inc
|
||||
.. include-build-file:: inc/ulp_riscv_lock_shared.inc
|
||||
.. include-build-file:: inc/ulp_riscv_lock.inc
|
||||
|
Loading…
Reference in New Issue
Block a user