mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
fix(spi_flash): Fix stuck during flash operation
When a task was not pinned to a certain CPU.
This commit is contained in:
parent
a41e037f0e
commit
955341db98
@ -43,7 +43,7 @@
|
|||||||
#include <soc/soc.h>
|
#include <soc/soc.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#ifndef CONFIG_FREERTOS_UNICORE
|
#ifndef CONFIG_FREERTOS_UNICORE
|
||||||
#include "esp_ipc.h"
|
#include "esp_private/esp_ipc.h"
|
||||||
#endif
|
#endif
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_memory_utils.h"
|
#include "esp_memory_utils.h"
|
||||||
@ -144,8 +144,8 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
|
|||||||
|
|
||||||
spi_flash_op_lock();
|
spi_flash_op_lock();
|
||||||
|
|
||||||
const int cpuid = xPortGetCoreID();
|
int cpuid = xPortGetCoreID();
|
||||||
const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
|
uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// For sanity check later: record the CPU which has started doing flash operation
|
// For sanity check later: record the CPU which has started doing flash operation
|
||||||
assert(s_flash_op_cpu == -1);
|
assert(s_flash_op_cpu == -1);
|
||||||
@ -160,33 +160,45 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
|
|||||||
// esp_intr_noniram_disable.
|
// esp_intr_noniram_disable.
|
||||||
assert(other_cpuid == 1);
|
assert(other_cpuid == 1);
|
||||||
} else {
|
} else {
|
||||||
// Temporarily raise current task priority to prevent a deadlock while
|
bool ipc_call_was_send_to_other_cpu;
|
||||||
// waiting for IPC task to start on the other CPU
|
do {
|
||||||
prvTaskSavedPriority_t SavedPriority;
|
#ifdef CONFIG_FREERTOS_SMP
|
||||||
prvTaskPriorityRaise(&SavedPriority, configMAX_PRIORITIES - 1);
|
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
|
||||||
|
vTaskPreemptionDisable(NULL);
|
||||||
|
#else
|
||||||
|
// Disable scheduler on the current CPU
|
||||||
|
vTaskSuspendAll();
|
||||||
|
#endif // CONFIG_FREERTOS_SMP
|
||||||
|
|
||||||
// Signal to the spi_flash_op_block_task on the other CPU that we need it to
|
cpuid = xPortGetCoreID();
|
||||||
// disable cache there and block other tasks from executing.
|
other_cpuid = (cpuid == 0) ? 1 : 0;
|
||||||
s_flash_op_can_start = false;
|
#ifndef NDEBUG
|
||||||
ESP_ERROR_CHECK(esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void *) other_cpuid));
|
s_flash_op_cpu = cpuid;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
s_flash_op_can_start = false;
|
||||||
|
|
||||||
|
ipc_call_was_send_to_other_cpu = esp_ipc_call_nonblocking(other_cpuid, &spi_flash_op_block_func, (void *) other_cpuid) == ESP_OK;
|
||||||
|
|
||||||
|
if (!ipc_call_was_send_to_other_cpu) {
|
||||||
|
// IPC call was not send to other cpu because another nonblocking API is running now.
|
||||||
|
// Enable the Scheduler again will not help the IPC to speed it up
|
||||||
|
// but there is a benefit to schedule to a higher priority task before the nonblocking running IPC call is done.
|
||||||
|
#ifdef CONFIG_FREERTOS_SMP
|
||||||
|
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
|
||||||
|
vTaskPreemptionEnable(NULL);
|
||||||
|
#else
|
||||||
|
xTaskResumeAll();
|
||||||
|
#endif // CONFIG_FREERTOS_SMP
|
||||||
|
}
|
||||||
|
} while (!ipc_call_was_send_to_other_cpu);
|
||||||
|
|
||||||
while (!s_flash_op_can_start) {
|
while (!s_flash_op_can_start) {
|
||||||
// Busy loop and wait for spi_flash_op_block_func to disable cache
|
// Busy loop and wait for spi_flash_op_block_func to disable cache
|
||||||
// on the other CPU
|
// on the other CPU
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_FREERTOS_SMP
|
|
||||||
//Note: Scheduler suspension behavior changed in FreeRTOS SMP
|
|
||||||
vTaskPreemptionDisable(NULL);
|
|
||||||
#else
|
|
||||||
// Disable scheduler on the current CPU
|
|
||||||
vTaskSuspendAll();
|
|
||||||
#endif // CONFIG_FREERTOS_SMP
|
|
||||||
// Can now set the priority back to the normal one
|
|
||||||
prvTaskPriorityRestore(&SavedPriority);
|
|
||||||
// This is guaranteed to run on CPU <cpuid> because the other CPU is now
|
|
||||||
// occupied by highest priority task
|
|
||||||
assert(xPortGetCoreID() == cpuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill interrupts that aren't located in IRAM
|
// Kill interrupts that aren't located in IRAM
|
||||||
esp_intr_noniram_disable();
|
esp_intr_noniram_disable();
|
||||||
// This CPU executes this routine, with non-IRAM interrupts and the scheduler
|
// This CPU executes this routine, with non-IRAM interrupts and the scheduler
|
||||||
|
Loading…
x
Reference in New Issue
Block a user