Skip to content

Commit 86034ad

Browse files
committed
Merge branch 'feature/freertos_fpu_isr' into 'master'
feature/fpu: Enable usage of FPU inside of a ISR Closes IDF-100 See merge request espressif/esp-idf!7348
2 parents f8e7285 + 5cbb3f0 commit 86034ad

File tree

5 files changed

+116
-5
lines changed

5 files changed

+116
-5
lines changed

components/freertos/Kconfig

+8
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,12 @@ menu "FreeRTOS"
420420
help
421421
Hidden option, gets selected by CONFIG_ESPxx_DEBUG_OCDAWARE
422422

423+
config FREERTOS_FPU_IN_ISR
424+
bool "Allow use of float inside Level 1 ISR (EXPERIMENTAL)"
425+
depends on IDF_TARGET_ESP32
426+
default n
427+
help
428+
When enabled, the usage of float type is allowed inside Level 1
429+
ISRs.
430+
423431
endmenu
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <esp_types.h>
2+
#include <stdio.h>
3+
4+
#include "freertos/FreeRTOS.h"
5+
#include "freertos/task.h"
6+
#include "freertos/semphr.h"
7+
#include "freertos/queue.h"
8+
#include "freertos/xtensa_api.h"
9+
#include "esp_intr_alloc.h"
10+
#include "xtensa/hal.h"
11+
#include "unity.h"
12+
#include "soc/cpu.h"
13+
#include "test_utils.h"
14+
#include "math.h"
15+
16+
#define SW_ISR_LEVEL_1 7
17+
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
18+
19+
struct fp_test_context {
20+
SemaphoreHandle_t sync;
21+
float expected;
22+
};
23+
24+
static void software_isr(void *arg) {
25+
(void)arg;
26+
BaseType_t yield;
27+
xt_set_intclear(1 << SW_ISR_LEVEL_1);
28+
29+
struct fp_test_context *ctx = (struct fp_test_context *)arg;
30+
31+
for(int i = 0; i < 16; i++) {
32+
ctx->expected = ctx->expected * 2.0f * cosf(0.0f);
33+
}
34+
35+
xSemaphoreGiveFromISR(ctx->sync, &yield);
36+
if(yield) {
37+
portYIELD_FROM_ISR();
38+
}
39+
}
40+
41+
42+
TEST_CASE("Floating point usage in ISR test", "[freertos]" "[fp]")
43+
{
44+
struct fp_test_context ctx;
45+
float fp_math_operation_result = 0.0f;
46+
47+
intr_handle_t handle;
48+
esp_err_t err = esp_intr_alloc(ETS_INTERNAL_SW0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, &software_isr, &ctx, &handle);
49+
TEST_ASSERT_EQUAL_HEX32(ESP_OK, err);
50+
51+
ctx.sync = xSemaphoreCreateBinary();
52+
TEST_ASSERT(ctx.sync != NULL);
53+
ctx.expected = 1.0f;
54+
55+
fp_math_operation_result = cosf(0.0f);
56+
57+
xt_set_intset(1 << SW_ISR_LEVEL_1);
58+
xSemaphoreTake(ctx.sync, portMAX_DELAY);
59+
60+
esp_intr_free(handle);
61+
vSemaphoreDelete(ctx.sync);
62+
63+
printf("FP math isr result: %f \n", ctx.expected);
64+
TEST_ASSERT_FLOAT_WITHIN(0.1f, ctx.expected, fp_math_operation_result * 65536.0f);
65+
}
66+
67+
#endif

components/freertos/xtensa/portasm.S

+25-1
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,24 @@ _frxt_int_enter:
138138
mull a2, a4, a2
139139
add a1, a1, a2 /* for current proc */
140140

141+
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
142+
#if XCHAL_CP_NUM > 0
143+
rsr a3, CPENABLE /* Restore thread scope CPENABLE */
144+
addi sp, sp,-4 /* ISR will manage FPU coprocessor by forcing */
145+
s32i a3, a1, 0 /* its trigger */
146+
#endif
147+
#endif
148+
141149
.Lnested:
142150
1:
151+
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
152+
#if XCHAL_CP_NUM > 0
153+
movi a3, 0 /* whilst ISRs pending keep CPENABLE exception active */
154+
wsr a3, CPENABLE
155+
rsync
156+
#endif
157+
#endif
158+
143159
mov a0, a12 /* restore return addr and return */
144160
ret
145161

@@ -176,6 +192,15 @@ _frxt_int_exit:
176192
s32i a2, a3, 0 /* save nesting count */
177193
bnez a2, .Lnesting /* !=0 after decr so still nested */
178194

195+
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
196+
#if XCHAL_CP_NUM > 0
197+
l32i a3, sp, 0 /* Grab last CPENABLE before leave ISR */
198+
addi sp, sp, 4
199+
wsr a3, CPENABLE
200+
rsync /* ensure CPENABLE was modified */
201+
#endif
202+
#endif
203+
179204
movi a2, pxCurrentTCB
180205
addx4 a2, a4, a2
181206
l32i a2, a2, 0 /* a2 = current TCB */
@@ -642,7 +667,6 @@ _frxt_task_coproc_state:
642667
addx4 a15, a3, a15
643668
l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
644669

645-
646670
beqz a15, 2f
647671
l32i a15, a15, CP_TOPOFSTACK_OFFS
648672
ret

components/freertos/xtensa/xtensa_vectors.S

+13-2
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,12 @@ _xt_coproc_exc:
955955

956956
/* Get co-processor state save area of new owner thread. */
957957
call0 XT_RTOS_CP_STATE /* a15 = new owner's save area */
958-
beqz a15, .L_goto_invalid /* not in a thread (invalid) */
958+
959+
#ifndef CONFIG_FREERTOS_FPU_IN_ISR
960+
beqz a15, .L_goto_invalid
961+
#endif
962+
963+
/*When FPU in ISR is enabled we could deal with zeroed a15 */
959964

960965
/* Enable the co-processor's bit in CPENABLE. */
961966
movi a0, _xt_coproc_mask
@@ -997,7 +1002,13 @@ locking.
9971002
rsync /* ensure wsr.CPENABLE is complete */
9981003

9991004
/* Only need to context switch if new owner != old owner. */
1005+
/* If float is necessary on ISR, we need to remove this check */
1006+
/* below, because on restoring from ISR we may have new == old condition used
1007+
* to force cp restore to next thread
1008+
*/
1009+
#ifndef CONFIG_FREERTOS_FPU_IN_ISR
10001010
beq a15, a2, .L_goto_done /* new owner == old, we're done */
1011+
#endif
10011012

10021013
/* If no old owner then nothing to save. */
10031014
beqz a2, .L_check_new
@@ -1039,6 +1050,7 @@ locking.
10391050
.L_check_new:
10401051
/* Check if any state has to be restored for new owner. */
10411052
/* NOTE: a15 = new owner's save area, cannot be zero when we get here. */
1053+
beqz a15, .L_xt_coproc_done
10421054

10431055
l16ui a3, a15, XT_CPSTORED /* a3 = new owner's CPSTORED */
10441056
movi a4, _xt_coproc_sa_offset
@@ -1133,7 +1145,6 @@ _xt_lowint1:
11331145
#endif
11341146
#endif
11351147

1136-
11371148
/* Save rest of interrupt context and enter RTOS. */
11381149
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
11391150

docs/en/api-guides/freertos-smp.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,9 @@ the state of a core's FPU registers are not immediately saved when a context
409409
switch occurs. Therefore, tasks that utilize ``float`` must be pinned to a
410410
particular core upon creation. If not, ESP-IDF FreeRTOS will automatically pin
411411
the task in question to whichever core the task was running on upon the task's
412-
first use of ``float``. Likewise due to Lazy Context Switching, interrupt service
413-
routines must also not use ``float``.
412+
first use of ``float``. Likewise due to Lazy Context Switching, only interrupt
413+
service routines of lowest priority (that is it the Level 1) can use ``float``,
414+
higher priority interrupts do not support FPU usage.
414415

415416
ESP32 does not support hardware acceleration for double precision floating point
416417
arithmetic (``double``). Instead ``double`` is implemented via software hence the

0 commit comments

Comments
 (0)