From 71a79ac0b1cb8529ba4f8a438a1324a2a98d903d Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 6 Mar 2025 13:00:00 +0100 Subject: [PATCH] feat(freertos): Add config to move additional functions into Flash This commit adds a new Kconfig option, viz., CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH, which places additional FreeRTOS functions, such as those which can be called from and ISR context, into Flash memory. This feature utilizes the Flash auto suspend/resume feature of the Flash chip. --- components/freertos/Kconfig | 14 ++ components/freertos/linker.lf | 160 ++++++++++++++++-- components/freertos/linker_common.lf | 22 ++- .../event_groups/test_freertos_eventgroups.c | 2 +- .../test_apps/freertos/pytest_freertos.py | 13 ++ .../freertos/sdkconfig.ci.flash_auto_suspend | 7 + ...dkconfig.flash_auto_suspend_iram_reduction | 1 + 7 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 components/freertos/test_apps/freertos/sdkconfig.ci.flash_auto_suspend diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index dec261a93c..1836dce9db 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -563,6 +563,15 @@ menu "FreeRTOS" When enabled the selected Non-ISR FreeRTOS functions will be placed into Flash memory instead of IRAM. This saves up to 8KB of IRAM depending on which functions are used. + config FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH + bool "Place FreeRTOS functions called from ISR context into Flash" + depends on SPI_FLASH_AUTO_SUSPEND && FREERTOS_PLACE_FUNCTIONS_INTO_FLASH + default n + help + When enabled additional FreeRTOS functions which maybe called from an ISR context are + also placed in Flash, thus freeing up more IRAM. + This option is only applicable when the SPI_FLASH_AUTO_SUSPEND feature is supported. + config FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE # Todo: Check if we still need this (IDF-4986) bool "Tests compliance with Vanilla FreeRTOS port*_CRITICAL calls" @@ -650,4 +659,9 @@ menu "FreeRTOS" default 1 if FREERTOS_UNICORE default 2 if !FREERTOS_UNICORE + config FREERTOS_IN_IRAM + # Invisible option enabled by default to place all freertos functions in internal RAM + # Todo: See linker.lf (IDF-12695) + bool + default y endmenu # FreeRTOS diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index 7351856f6f..22c547d8e6 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -7,12 +7,31 @@ # - CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH: # - Place functions in flash if they are never called from an ISR context (directly or indirectly). # - Some functions that are called often (such as critical sections) are placed in internal RAM for speed. +# - CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH: +# - Place additional functions such as the FromISR() variants in flash as well. +# +# TODO: In IDF 6.0, evaluate the possibility of (IDF-12695): +# 1. Default behavior: All FreeRTOS functions should be placed in flash by default, except for: +# - FromISR() functions +# - Performance-critical functions, such as critical section APIs and code related to context switching +# 2. Deprecate the FREERTOS_PLACE_FUNCTIONS_INTO_FLASH Kconfig option and unhide the FREERTOS_IN_IRAM Kconfig +# option. Present FREERTOS_IN_IRAM config option to users as a performance optimization feature, with the +# trade-off of reduced internal RAM availability. This option would be disabled by default. +# 3. FREERTOS_IN_IRAM config option should be user-configurable only if SPI_FLASH_AUTO_SUSPEND is supported. +# If not supported, it should be enabled by default and follow the placement rules stated above. +# 4. If SPI_FLASH_AUTO_SUSPEND is supported, place additional FreeRTOS functions - including FromISR() +# variants, in Flash. Control this behavior using the FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH +# config option. # ---------------------------------------------------------------------------------------------------------------------- [mapping:freertos_idf] archive: libfreertos.a entries: - * (noflash_text) # Default all FreeRTOS functions to IRAM + if FREERTOS_IN_IRAM = y: + * (noflash_text) # All FreeRTOS functions to IRAM + #else + # TODO: Enable in IDF 6.0 + # * (default) # All FreeRTOS functions to Flash if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y: # -------------------------------------------------------------------------------------------------------------- # event_groups.c @@ -25,26 +44,41 @@ entries: event_groups:xEventGroupClearBits (default) event_groups:xEventGroupSetBits (default) event_groups:vEventGroupDelete (default) + event_groups: xEventGroupGetStaticBuffer (default) event_groups:vEventGroupSetBitsCallback (default) event_groups:vEventGroupClearBitsCallback (default) event_groups:prvTestWaitCondition (default) if FREERTOS_USE_TRACE_FACILITY = y: event_groups: uxEventGroupGetNumber (default) event_groups: vEventGroupSetNumber (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + event_groups: xEventGroupClearBitsFromISR (default) + event_groups: xEventGroupGetBitsFromISR (default) + event_groups: xEventGroupSetBitsFromISR (default) # -------------------------------------------------------------------------------------------------------------- # list.c # - List/List Item initialization functions are never called from ISR + # - vListInsert is never called from an ISR context + # - Remaining List insertion/removal functions can be called from an ISR context and hence place them in flash + # only when CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled # -------------------------------------------------------------------------------------------------------------- list:vListInitialise (default) list:vListInitialiseItem (default) + list:vListInsert (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + list:vListInsertEnd (default) + list:uxListRemove (default) # -------------------------------------------------------------------------------------------------------------- # queue.c # - Keep all ...FromISR() functions (and their prv... calls) in internal RAM # - All other functions can be moved to flash # - Queue lock related functions are only used in single core builds + # - If CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled, place all FromISR() functions and their + # dependents in flash as well # -------------------------------------------------------------------------------------------------------------- queue:xQueueGenericReset (default) queue:xQueueGenericCreateStatic (default) + queue:xQueueGenericGetStaticBuffers (default) queue:xQueueGenericCreate (default) queue:prvInitialiseNewQueue (default) queue:prvInitialiseMutex (default) @@ -80,14 +114,31 @@ entries: queue:xQueueAddToSet (default) queue:xQueueRemoveFromSet (default) queue:xQueueSelectFromSet (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + queue:xQueueGetMutexHolderFromISR (default) + queue:xQueueGenericSendFromISR (default) + queue:prvCopyDataToQueue (default) + queue:prvNotifyQueueSetContainer (default) + queue:xQueueGiveFromISR (default) + queue:xQueueReceiveFromISR (default) + queue:prvCopyDataFromQueue (default) + queue:xQueuePeekFromISR (default) + queue:uxQueueMessagesWaitingFromISR (default) + queue:xQueueIsQueueEmptyFromISR (default) + queue:xQueueIsQueueFullFromISR (default) + queue:xQueueSelectFromSetFromISR (default) # -------------------------------------------------------------------------------------------------------------- # stream_buffer.c + # - If CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled, place all FromISR() functions and their + # dependents in flash as well # -------------------------------------------------------------------------------------------------------------- stream_buffer:xStreamBufferGenericCreate (default) stream_buffer:xStreamBufferGenericCreateStatic (default) + stream_buffer:xStreamBufferGetStaticBuffers (default) stream_buffer:vStreamBufferDelete (default) stream_buffer:xStreamBufferReset (default) stream_buffer:xStreamBufferSetTriggerLevel (default) + stream_buffer:xStreamBufferSpacesAvailable (default) stream_buffer:xStreamBufferBytesAvailable (default) stream_buffer:xStreamBufferSend (default) stream_buffer:xStreamBufferReceive (default) @@ -101,14 +152,31 @@ entries: stream_buffer:uxStreamBufferGetStreamBufferNumber (default) stream_buffer:vStreamBufferSetStreamBufferNumber (default) stream_buffer:ucStreamBufferGetStreamBufferType (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + stream_buffer:xStreamBufferSendFromISR (default) + stream_buffer:prvWriteMessageToBuffer (default) + stream_buffer:xStreamBufferReceiveFromISR (default) + stream_buffer:prvReadMessageFromBuffer (default) + stream_buffer:xStreamBufferSendCompletedFromISR (default) + stream_buffer:xStreamBufferReceiveCompletedFromISR (default) + stream_buffer:prvBytesInBuffer (default) # -------------------------------------------------------------------------------------------------------------- # tasks.c - # - Tickless idle functions (i.e., step tick) are left in internal RAM for speed + # - The following functions are always kept in internal RAM as they are frequently called during context switches + # - xTaskIncrementTick + # - prvSelectHighestPriorityTaskSMP + # - vTaskSwitchContext + # - Tickless idle functions (i.e., step tick) are left in internal RAM for speed unless + # CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled + # - Place all functions that are called from an ISR context into Flash if + # CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled # - The following functions are called when the cache is disabled, thus they are excluded from the list below # (i.e., called after "spi_flash_disable_interrupts_caches_and_other_cpu()" is called). # - "xTaskGetSchedulerState" # - "xTaskGetTickCount" # -------------------------------------------------------------------------------------------------------------- + tasks:xTaskCreateRestrictedStatic (default) + tasks:xTaskCreateRestricted (default) tasks:prvInitialiseNewTask (default) tasks:prvAddNewTaskToReadyList (default) tasks:vTaskDelete (default) @@ -119,22 +187,26 @@ entries: tasks:vTaskPrioritySet (default) tasks:vTaskSuspend (default) tasks:vTaskResume (default) + tasks:prvCreateIdleTasks (default) tasks:vTaskStartScheduler (default) tasks:vTaskEndScheduler (default) tasks:vTaskSuspendAll (default) - if CONFIG_FREERTOS_USE_TICKLESS_IDLE = y: + if FREERTOS_USE_TICKLESS_IDLE = y: tasks:prvGetExpectedIdleTime (default) + tasks:eTaskConfirmSleepModeStatus (default) tasks:xTaskResumeAll (default) tasks:uxTaskGetNumberOfTasks (default) tasks:pcTaskGetName (default) tasks:prvSearchForNameWithinSingleList (default) tasks:xTaskGetHandle (default) + tasks:xTaskGetStaticBuffers (default) tasks:xTaskGetIdleTaskHandle (default) + tasks:xTaskCatchUpTicks (default) tasks:xTaskAbortDelay (default) - # IDF-6410 Application tags not supported yet - #tasks:vTaskSetApplicationTaskTag (default) - #tasks:xTaskGetApplicationTaskTag (default) - #tasks:xTaskCallApplicationTaskHook (default) + if FREERTOS_USE_APPLICATION_TASK_TAG = y: + tasks:vTaskSetApplicationTaskTag (default) + tasks:xTaskGetApplicationTaskTag (default) + tasks:xTaskCallApplicationTaskHook (default) tasks:vTaskPlaceOnEventList (default) tasks:vTaskPlaceOnUnorderedEventList (default) tasks:vTaskPlaceOnEventListRestricted (default) @@ -179,20 +251,36 @@ entries: tasks:vTaskSetTaskNumber (default) tasks:vTaskGetInfo (default) tasks:prvListTasksWithinSingleList (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + tasks:prvIsYieldRequiredSMP (default) + tasks:prvCheckTaskCanBeScheduledSMP (default) + tasks:uxTaskPriorityGetFromISR (default) + tasks:prvTaskIsTaskSuspended (default) + tasks:xTaskResumeFromISR (default) + tasks:xTaskGetTickCountFromISR (default) + tasks:xTaskGetApplicationTaskTagFromISR (default) + tasks:xTaskRemoveFromEventList (default) + tasks:prvResetNextTaskUnblockTime (default) + tasks:xTaskGenericNotifyFromISR (default) + tasks:vTaskGenericNotifyGiveFromISR (default) + if FREERTOS_USE_TICKLESS_IDLE = y: + tasks:vTaskStepTick (default) # -------------------------------------------------------------------------------------------------------------- # timers.c # - xTimerGenericCommand() is used for ISR calls as well. Thus leave it (and its dependents) in internal RAM + # unless CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled # -------------------------------------------------------------------------------------------------------------- timers:xTimerCreateTimerTask (default) timers:xTimerCreate (default) timers:xTimerCreateStatic (default) timers:prvInitialiseNewTimer (default) - timers:xTimerGenericCommand (default) timers:xTimerGetTimerDaemonTaskHandle (default) timers:xTimerGetPeriod (default) timers:vTimerSetReloadMode (default) + timers:xTimerGetReloadMode (default) timers:uxTimerGetReloadMode (default) timers:xTimerGetExpiryTime (default) + timers:xTimerGetStaticBuffer (default) timers:pcTimerGetName (default) timers:prvReloadTimer (default) timers:prvProcessExpiredTimer (default) @@ -211,30 +299,78 @@ entries: if FREERTOS_USE_TRACE_FACILITY = y: timers:uxTimerGetTimerNumber (default) timers:vTimerSetTimerNumber (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + timers:xTimerGenericCommand (default) + timers:xTimerPendFunctionCallFromISR (default) # -------------------------------------------------------------------------------------------------------------- # portable/xtensa/port.c - # - Most functions are called from an ISR context, except for scheduler/task init/deinit functions - # - MPU/Coproc currently only exists on ESP32/S3 + # - Most functions are called from an ISR context, except for scheduler/task init/deinit functions. Functions + # called from ISR context are placed in flash only when CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH + # is enabled + # - Critical sections functions are always placed in internal RAM for better performance + # - The following functions are also placed in internal RAM as they are called from vTaskSwitchContext, which is + # also always placed in internal RAM + # - vApplicationStackOverflowHook + # - vPortSetStackWatchpoint # -------------------------------------------------------------------------------------------------------------- if IDF_TARGET_ARCH_XTENSA = y: port:xPortStartScheduler (default) port:vPortEndScheduler (default) + if FREERTOS_TASK_FUNCTION_WRAPPER = y: + port:vPortTaskWrapper (default) + if SOC_CPU_COPROC_NUM > 0: + port:uxInitialiseStackCPSA (default) + port:uxInitialiseStackTLS (default) + port:uxInitialiseStackFrame (default) port:pxPortInitialiseStack (default) port:xPortGetTickRateHz (default) if FREERTOS_TLSP_DELETION_CALLBACKS = y: port:vPortTLSPointersDelCb (default) - if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S3 = y : + if SOC_CPU_COPROC_NUM > 0: port:vPortCleanUpCoprocArea (default) port:vPortTCBPreDeleteHook (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + port:xPortInIsrContext (default) + port:vPortAssertIfInISR (default) + port:xPortInterruptedFromISRContext (default) + port:vPortYieldOtherCore (default) # -------------------------------------------------------------------------------------------------------------- # portable/riscv/port.c - # - Most functions are called from an ISR context, except for scheduler/task init/deinit functions + # - Most functions are called from an ISR context, except for scheduler/task init/deinit functions. Functions + # called from ISR context are placed in flash only when CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH + # is enabled + # - Critical sections functions are always placed in internal RAM for better performance + # - The following functions are also placed in internal RAM as they are called from vTaskSwitchContext, which is + # also always placed in internal RAM + # - vApplicationStackOverflowHook + # - vPortSetStackWatchpoint + # - vPortCoprocUsedInISR is directly called from RISC-V assembly code with a direct branch instruction which + # may be too far when placed in Flash. Hence, it is always placed in internal RAM # -------------------------------------------------------------------------------------------------------------- if IDF_TARGET_ARCH_RISCV = y: port:xPortStartScheduler (default) port:vPortEndScheduler (default) + port:uxInitialiseStackTLS (default) + if FREERTOS_TASK_FUNCTION_WRAPPER = y: + port:vPortTaskWrapper (default) + if SOC_CPU_COPROC_NUM > 0: + port:pxRetrieveCoprocSaveAreaFromStackPointer (default) + port:uxInitialiseCoprocSaveArea (default) + port:vPortCleanUpCoprocArea (default) + port:pxPortGetCoprocArea (default) + port:pxPortUpdateCoprocOwner (default) + if FREERTOS_UNICORE = n: + port:vPortTaskPinToCore (default) + port:uxInitialiseStackFrame (default) port:pxPortInitialiseStack (default) + port:vPortYield (default) port:xPortGetTickRateHz (default) if FREERTOS_TLSP_DELETION_CALLBACKS = y: port:vPortTLSPointersDelCb (default) port:vPortTCBPreDeleteHook (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + port:xPortInIsrContext (default) + port:vPortAssertIfInISR (default) + port:xPortInterruptedFromISRContext (default) + port:vPortYieldFromISR (default) + port:vPortYieldOtherCore (default) diff --git a/components/freertos/linker_common.lf b/components/freertos/linker_common.lf index 8e3f63030b..a1fbd96beb 100644 --- a/components/freertos/linker_common.lf +++ b/components/freertos/linker_common.lf @@ -10,11 +10,14 @@ entries: # - Default: Place all functions in internal RAM. # - CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH: Place functions in flash if they are never called from an ISR # context (directly or indirectly). + # - xTaskIncrementTickOtherCores is always placed in internal RAM for better performance # Placement Rules (Task Snapshot): # - Default: Place all functions in internal RAM. # - CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH: Place functions in flash # - vTaskGetSnapshot is omitted on purpose as it is used to by the Task Watchdog (TWDT) interrupt handler, we want - # to always keep it in IRAM + # to always keep it in IRAM unless CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH is enabled in which case + # we can place it in flash. + # # ------------------------------------------------------------------------------------------------------------------ if FREERTOS_PLACE_FUNCTIONS_INTO_FLASH = y: # Kernel Control @@ -37,11 +40,21 @@ entries: # TLSP Deletion Callbacks if FREERTOS_TLSP_DELETION_CALLBACKS = y: tasks:vTaskSetThreadLocalStoragePointerAndDelCallback (default) + # Newlib re-entrancy + tasks:__getreent (default) + # Miscellaneous + tasks:pvTaskGetCurrentTCBForCore (default) + if SPIRAM = y: + # PSRAM + tasks:prvTaskCreateDynamicPinnedToCoreWithCaps (default) # Task Snapshot if FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH = y: tasks:pxGetTaskListByIndex (default) tasks:xTaskGetNext (default) tasks:uxTaskGetSnapshotAll (default) + if FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH = y: + tasks:vTaskGetSnapshot (default) + # ------------------------------------------------------------------------------------------------------------------ # freertos_compatibility.c @@ -55,6 +68,12 @@ entries: # ------------------------------------------------------------------------------------------------------------------ idf_additions (default) + # ------------------------------------------------------------------------------------------------------------------ + # idf_additions_event_groups.c + # Placement Rules: Functions always in flash as they are never called from an ISR + # ------------------------------------------------------------------------------------------------------------------ + idf_additions_event_groups (default) + # ------------------------------------------------------------------------------------------------------------------ # app_startup.c # Placement Rules: Functions always in flash as they are never called from an ISR @@ -74,6 +93,7 @@ entries: heap_idf:vPortFree (default) heap_idf:xPortGetFreeHeapSize (default) heap_idf:xPortGetMinimumEverFreeHeapSize (default) + heap_idf:xPortCheckValidListMem (default) if FREERTOS_SMP = n: heap_idf:xPortCheckValidTCBMem (default) heap_idf:xPortcheckValidStackMem (default) diff --git a/components/freertos/test_apps/freertos/kernel/event_groups/test_freertos_eventgroups.c b/components/freertos/test_apps/freertos/kernel/event_groups/test_freertos_eventgroups.c index f1101360b2..638664b7e2 100644 --- a/components/freertos/test_apps/freertos/kernel/event_groups/test_freertos_eventgroups.c +++ b/components/freertos/test_apps/freertos/kernel/event_groups/test_freertos_eventgroups.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/freertos/test_apps/freertos/pytest_freertos.py b/components/freertos/test_apps/freertos/pytest_freertos.py index 6ea7c3cf78..1c2d49fc46 100644 --- a/components/freertos/test_apps/freertos/pytest_freertos.py +++ b/components/freertos/test_apps/freertos/pytest_freertos.py @@ -56,6 +56,19 @@ def test_freertos(dut: Dut) -> None: dut.run_all_single_board_cases() +@pytest.mark.generic +@pytest.mark.flash_suspend +@idf_parametrize( + 'config,target', + [ + ('flash_auto_suspend', 'esp32c3'), + ], + indirect=['config', 'target'], +) +def test_freertos_flash_auto_suspend(dut: Dut) -> None: + dut.run_all_single_board_cases() + + @pytest.mark.generic @pytest.mark.parametrize('config', ['freertos_options'], indirect=True) @idf_parametrize('target', ['supported_targets'], indirect=['target']) diff --git a/components/freertos/test_apps/freertos/sdkconfig.ci.flash_auto_suspend b/components/freertos/test_apps/freertos/sdkconfig.ci.flash_auto_suspend new file mode 100644 index 0000000000..598542daa8 --- /dev/null +++ b/components/freertos/test_apps/freertos/sdkconfig.ci.flash_auto_suspend @@ -0,0 +1,7 @@ +# Enable Flash auto suspend/resume feature +CONFIG_SPI_FLASH_AUTO_SUSPEND=y +CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND=y + +# Enable FreeRTOS in Flash feature +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH=y diff --git a/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction b/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction index 2ef0931158..7655415294 100644 --- a/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction +++ b/tools/test_apps/configs/sdkconfig.flash_auto_suspend_iram_reduction @@ -9,6 +9,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y # Options that will enable IRAM reduction option that are not necessarily safe for all use-cases CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y +CONFIG_FREERTOS_PLACE_ISR_FUNCTIONS_INTO_FLASH=y # Options that will enable IRAM reduction option that are only usable together with flash auto-suspend CONFIG_SPI_FLASH_AUTO_SUSPEND=y