raspberrypi / pico-sdk

BSD 3-Clause "New" or "Revised" License
3.66k stars 909 forks source link

pico_cyw43_arch_sys_freertos: hardfault in async_context under certain conditions #1962

Open Misaka0x2730 opened 1 day ago

Misaka0x2730 commented 1 day ago

Hello, I am working on firmware for a device that needs to run on the Pico, Pico W, and another custom board I designed (RP2040 + W25Q16).

The firmware runs under FreeRTOS and I have encountered a strange issue on the Pico W. Since I need to use the onboard LED, I am trying to initialize cyw43 (I only need the LED functionality, no Wi-Fi or Bluetooth).

When I call cyw43_arch_init from a task with a priority HIGHER than CYW43_TASK_PRIORITY, I consistently encounter a hard fault 100% of the time in async_context. It appears that the issue is caused by an invalid pointer value in the context structure (see the screenshots).

If I call cyw43_arch_init from a task with a priority EQUAL TO or LOWER than CYW43_TASK_PRIORITY, everything works correctly.

For example, if the priority of the task that calls cyw43_arch_init is 2 and CYW43_TASK_PRIORITY is 1, a hard fault occurs 100% of the time. However, if the priority of the task that calls cyw43_arch_init is 1 and CYW43_TASK_PRIORITY is also 1, everything works correctly.

The issue occurs on the debug build with optimization disabled, the release build with optimization has not been tested.

Call stack: image

Incorrect pointer (self->when_pending_list->next address is incorrect): image

I use latest FreeRTOS-Kernel from main branch. The firmware runs on a single core (core 0).

I attached FreeRTOSConfig.h and CMakeLists.txt below. PICO_BOARD is set to none because the firmware is designed to work on my custom board as well.

FreeRTOSConfig.h #define configUSE_PREEMPTION 1 #define configUSE_TICKLESS_IDLE 0 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 1 #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES 5 #define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 128 #define configCPU_CLOCK_HZ (250000000) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 0 /* Synchronization Related */ #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_APPLICATION_TASK_TAG 0 #define configUSE_COUNTING_SEMAPHORES 1 #define configQUEUE_REGISTRY_SIZE 8 #define configUSE_QUEUE_SETS 0 #define configUSE_TIME_SLICING 1 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 1 #define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 /* System */ #define configSTACK_DEPTH_TYPE uint32_t #define configMESSAGE_BUFFER_LENGTH_TYPE size_t /* Memory allocation related definitions. */ #define configSUPPORT_STATIC_ALLOCATION 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configTOTAL_HEAP_SIZE (40 * 1024) #define configAPPLICATION_ALLOCATED_HEAP 0 #define configMAX_TASK_NAME_LEN (16) /* Hook function related definitions. */ #define configCHECK_FOR_STACK_OVERFLOW 2 #define configUSE_MALLOC_FAILED_HOOK 0 #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 0 #define configUSE_TRACE_FACILITY 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 0 #define configRECORD_STACK_HIGH_ADDRESS 1 /* Co-routine related definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES 1 /* Software timer related definitions. */ #define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH 128 /* Interrupt nesting behaviour configuration. */ /* #define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] #define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] #define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] */ /* SMP port only */ #define configNUMBER_OF_CORES 1 #define configTICK_CORE 0 #define configRUN_MULTIPLE_PRIORITIES 1 #define configUSE_PASSIVE_IDLE_HOOK 0 #if (configNUMBER_OF_CORES > 1) /* RP2040 specific */ #define configSUPPORT_PICO_SYNC_INTEROP 1 #define configSUPPORT_PICO_TIME_INTEROP 1 #define configUSE_CORE_AFFINITY 1 #else #define configUSE_CORE_AFFINITY 0 #endif //extern void System_Assert(const char* file, const int line); /* Define to trap errors during development. */ #define configASSERT assert /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskSuspend 0 #define INCLUDE_vTaskDelayUntil 0 #define INCLUDE_vTaskDelay 1 #define INCLUDE_xTaskGetSchedulerState 0 #define INCLUDE_xTaskGetCurrentTaskHandle 1 #define INCLUDE_uxTaskGetStackHighWaterMark 0 #define INCLUDE_xTaskGetIdleTaskHandle 0 #define INCLUDE_eTaskGetState 0 #define INCLUDE_xTimerPendFunctionCall 1 #define INCLUDE_xTaskAbortDelay 0 #define INCLUDE_xTaskGetHandle 1 #define INCLUDE_xTaskResumeFromISR 0 #define INCLUDE_xQueueGetMutexHolder 1 #if ENABLE_SYSVIEW_TRACE #include "SEGGER_SYSVIEW_FreeRTOS.h" #endif
CMakeLists.txt cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0169 OLD) set(PICOTOOL_FETCH_FROM_GIT_PATH "../firmware/thirdParty/picotool") set(PICO_SDK_FETCH_FROM_GIT ON) set(PICO_CYW43_SUPPORTED ON) set(PICO_BOARD none) set(PICO_PLATFORM rp2040) string(TOLOWER ${CMAKE_BUILD_TYPE} build_type) if (build_type STREQUAL debug) set(PICO_DEOPTIMIZED_DEBUG 1) set(LOG 3) else() set(PICO_DEOPTIMIZED_DEBUG 0) set(LOG 0) endif() include(pico_sdk_import.cmake) include(pico_extras_import_optional.cmake) set(FREERTOS_KERNEL_PATH "../thirdParty/FreeRTOS-Kernel") include(FreeRTOS_Kernel_import.cmake) project(MioLink C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) # Use FreeRTOS support in tinyusb set(TINYUSB_OPT_OS OPT_OS_FREERTOS) set(PICO_TINYUSB_PATH ${CMAKE_CURRENT_LIST_DIR}/thirdParty/tinyusb) # Don't use Pico SDK stdio set(PICO_STDIO_UART OFF) # initialize the Raspberry Pi Pico SDK pico_sdk_init() add_executable(MioLink) # Raspberry Pi Pico SDK parameters target_compile_definitions(MioLink PUBLIC PICO_FLASH_SIZE_BYTES=2097152) target_compile_definitions(MioLink PUBLIC PICO_BOOT_STAGE2_CHOOSE_W25Q080=1) target_compile_definitions(MioLink PUBLIC PICO_FLASH_SPI_CLKDIV=2) target_compile_definitions(MioLink PUBLIC PICO_RP2040_B0_SUPPORTED=0) target_compile_definitions(MioLink PUBLIC PICO_STDIO_SHORT_CIRCUIT_CLIB_FUNCS=0) target_compile_definitions(MioLink PUBLIC CYW43_PIN_WL_HOST_WAKE=24) target_compile_definitions(MioLink PUBLIC CYW43_PIN_WL_REG_ON=23) target_compile_definitions(MioLink PUBLIC CYW43_WL_GPIO_COUNT=3) target_compile_definitions(MioLink PUBLIC CYW43_WL_GPIO_LED_PIN=0) target_compile_definitions(MioLink PUBLIC CYW43_LWIP=0) target_compile_definitions(MioLink PUBLIC CYW43_TASK_PRIORITY=1) pico_set_printf_implementation(MioLink "compiler") # MioLink headers target_include_directories(MioLink PUBLIC include) target_include_directories(MioLink PUBLIC include/bmp) target_include_directories(MioLink PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) ... # Raspberry Pi Pico SDK libraries target_link_libraries(MioLink PUBLIC hardware_pio hardware_uart hardware_dma hardware_timer hardware_adc hardware_i2c) target_link_libraries(MioLink PUBLIC pico_stdlib pico_unique_id pico_bootrom tinyusb_device tinyusb_board tinyusb_additions pico_cyw43_arch_sys_freertos) target_link_libraries(MioLink PUBLIC FreeRTOS-Kernel FreeRTOS-Kernel-Heap4) # Add MioLink output pico_add_extra_outputs(MioLink)
Misaka0x2730 commented 4 hours ago

I have prepared a clean repository where you can test this issue: https://github.com/Misaka0x2730/pico_cyw43_freertos_hardfault

To reproduce the issue, uncomment #define ENABLE_CYW43_INIT_ISSUE (line 7) in main.c. To "fix" the issue, comment out this line.

P.S. I noticed another interesting point: if the priority of the task calling cyw43_arch_init and CYW43_TASK_PRIORITY are equal, then calling cyw43_arch_gpio_put after cyw43_arch_init also causes a hardfault.

However, if the priority of the task calling cyw43_arch_init is lower than CYW43_TASK_PRIORITY, then I do not observe this issue; the LED on my Pico W turns on.

This is taken into account in the test repository.