Sfoglia il codice sorgente

Merge branch 'feature/freertos_dual_portYIELD_support' into 'master'

feature/freertos: enable support for portYIELD_FROM_ISR that takes an argument or not

Closes IDF-1962

See merge request espressif/esp-idf!9927
Angus Gratton 5 anni fa
parent
commit
4535fa03b0

+ 43 - 11
components/freertos/test/test_isr_latency.c

@@ -21,7 +21,20 @@ static uint32_t cycle_before_exit;
 static uint32_t delta_enter_cycles = 0;
 static uint32_t delta_exit_cycles = 0;
 
-static void software_isr(void *arg) {
+static void software_isr_using_parameter_vportyield(void *arg) {
+    (void)arg;
+    BaseType_t yield;
+    delta_enter_cycles += portGET_RUN_TIME_COUNTER_VALUE() - cycle_before_trigger;
+    
+    xt_set_intclear(1 << SW_ISR_LEVEL_1);
+
+    xSemaphoreGiveFromISR(sync, &yield);
+    portYIELD_FROM_ISR(yield);
+
+    cycle_before_exit = portGET_RUN_TIME_COUNTER_VALUE();
+}
+
+static void software_isr_using_no_argument_vportyield(void *arg) {
     (void)arg;
     BaseType_t yield;
     delta_enter_cycles += portGET_RUN_TIME_COUNTER_VALUE() - cycle_before_trigger;
@@ -32,17 +45,11 @@ static void software_isr(void *arg) {
     if(yield) {
         portYIELD_FROM_ISR();
     }
-
     cycle_before_exit = portGET_RUN_TIME_COUNTER_VALUE();
 }
 
 static void test_task(void *arg) {
-    (void)arg;
-    
-    intr_handle_t handle;
- 
-    esp_err_t err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, &software_isr, NULL, &handle);
-    TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
+    (void) arg;
 
     for(int i = 0;i < 10000; i++) {
         cycle_before_trigger = portGET_RUN_TIME_COUNTER_VALUE();
@@ -54,13 +61,36 @@ static void test_task(void *arg) {
     delta_enter_cycles /= 10000;
     delta_exit_cycles /= 10000;
 
-    esp_intr_free(handle);
     xSemaphoreGive(end_sema);
     vTaskDelete(NULL);
 }
 
-TEST_CASE("isr latency test", "[freertos] [ignore]")
+TEST_CASE("isr latency test vport-yield-from-isr with no parameter", "[freertos] [ignore]")
+{
+    intr_handle_t handle;
+    esp_err_t err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, &software_isr_using_no_argument_vportyield, NULL, &handle);
+    TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
+
+    sync = xSemaphoreCreateBinary();
+    TEST_ASSERT(sync != NULL);
+    end_sema = xSemaphoreCreateBinary();
+    TEST_ASSERT(end_sema != NULL);
+    xTaskCreatePinnedToCore(test_task, "tst" , 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
+    vTaskDelay(100);
+    BaseType_t result = xSemaphoreTake(end_sema, portMAX_DELAY);    
+    TEST_ASSERT_EQUAL_HEX32(pdTRUE, result);
+    TEST_PERFORMANCE_LESS_THAN(ISR_ENTER_CYCLES, "%d cycles" ,delta_enter_cycles);
+    TEST_PERFORMANCE_LESS_THAN(ISR_EXIT_CYCLES, "%d cycles" ,delta_exit_cycles);
+
+    esp_intr_free(handle);
+}
+
+TEST_CASE("isr latency test vport-yield-from-isr with parameter", "[freertos][ignore]")
 {
+    intr_handle_t handle;
+    esp_err_t err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, &software_isr_using_parameter_vportyield, NULL, &handle);
+    TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
+
     sync = xSemaphoreCreateBinary();
     TEST_ASSERT(sync != NULL);
     end_sema = xSemaphoreCreateBinary();
@@ -70,4 +100,6 @@ TEST_CASE("isr latency test", "[freertos] [ignore]")
     TEST_ASSERT_EQUAL_HEX32(pdTRUE, result);
     TEST_PERFORMANCE_LESS_THAN(ISR_ENTER_CYCLES, "%d cycles" ,delta_enter_cycles);
     TEST_PERFORMANCE_LESS_THAN(ISR_EXIT_CYCLES, "%d cycles" ,delta_exit_cycles);
-}
+
+    esp_intr_free(handle);
+}

+ 20 - 6
components/freertos/xtensa/include/freertos/portmacro.h

@@ -75,7 +75,7 @@ extern "C" {
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdbool.h>
-
+#include <stdarg.h>
 #include <xtensa/hal.h>
 #include <xtensa/config/core.h>
 #include <xtensa/config/system.h>	/* required for XSHAL_CLIB */
@@ -321,13 +321,27 @@ static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint
 #define portALT_GET_RUN_TIME_COUNTER_VALUE(x)    x = (uint32_t)esp_timer_get_time()
 #endif
 
-
-/* Kernel utilities. */
 void vPortYield( void );
+void vPortEvaluateYieldFromISR(int argc, ...);
 void _frxt_setup_switch( void );
-#define portYIELD()					vPortYield()
-#define portYIELD_FROM_ISR()        {traceISR_EXIT_TO_SCHEDULER(); _frxt_setup_switch();}
-
+/**
+ * Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with, 
+ * or without arguments.
+ */ 
+#define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER(0, ##__VA_ARGS__,1,0)
+#define portGET_ARGUMENT_COUNT_INNER(zero, one, count, ...) count
+
+_Static_assert(portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments");
+_Static_assert(portGET_ARGUMENT_COUNT(1) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument");
+
+#define portYIELD()	vPortYield()
+
+/**
+ * @note    The macro below could be used when passing a single argument, or without any argument, 
+ *          it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
+ *          might result in undesired behaviour
+ */
+#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR(portGET_ARGUMENT_COUNT(__VA_ARGS__), ##__VA_ARGS__)
 
 /* Yielding within an API call (when interrupts are off), means the yield should be delayed
    until interrupts are re-enabled.

+ 24 - 0
components/freertos/xtensa/port.c

@@ -387,6 +387,30 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
 	return (port_interruptNesting[xPortGetCoreID()] != 0);
 }
 
+void IRAM_ATTR vPortEvaluateYieldFromISR(int argc, ...)
+{
+    BaseType_t xYield; 
+    va_list ap;
+    va_start(ap, argc);
+
+    if(argc) {
+        xYield = (BaseType_t)va_arg(ap, int);
+        va_end(ap);  
+    } else {
+        //it is a empty parameter vPortYieldFromISR macro call:
+        va_end(ap);
+        traceISR_EXIT_TO_SCHEDULER();   
+        _frxt_setup_switch();
+        return;
+    }
+
+    //Yield exists, so need evaluate it first then switch:
+    if(xYield == pdTRUE) {
+        traceISR_EXIT_TO_SCHEDULER();   
+        _frxt_setup_switch();
+    } 
+}
+
 void vPortAssertIfInISR(void)
 {
 	configASSERT(xPortInIsrContext());

+ 1 - 3
components/freertos/xtensa/portmacro_priv.h

@@ -75,6 +75,4 @@
 #define portVALID_STACK_MEM(ptr) esp_ptr_byte_accessible(ptr)
 #else
 #define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr))
-#endif
-
-
+#endif