Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PicoW hang during init when using FreeRTOS #1394

Closed
earlephilhower opened this issue Apr 23, 2023 Discussed in #1390 · 2 comments · Fixed by #1395
Closed

PicoW hang during init when using FreeRTOS #1394

earlephilhower opened this issue Apr 23, 2023 Discussed in #1390 · 2 comments · Fixed by #1395
Labels
freertos FreeRTOS support

Comments

@earlephilhower
Copy link
Owner

Discussed in #1390

Originally posted by ruifig April 22, 2023
I'm experimenting with adding FreeRTOS tasks.
With a minimal application it works fine but with my actual project, it's freezing at startup with this callstack:

sleep_until@0x1003774a (\sleep_until.dbgasm:43)
capture_additional_rosc_samples@0x10045778 (Unknown Source:151)
initialise_rand@0x10045822 (Unknown Source:210)
get_rand_64@0x10045822 (\get_rand_64.dbgasm:66)
get_rand_32@0x100459c2 (\get_rand_32.dbgasm:3)
udp_init@0x10042196 (\udp_init.dbgasm:3)
lwip_init@0x1004794c (\lwip_init.dbgasm:7)
lwip_nosys_init@0x10045550 (\lwip_nosys_init.dbgasm:8)
cyw43_arch_init@0x1003d088 (\cyw43_arch_init.dbgasm:14)
cyw43_arch_init_with_country@0x1003ce82 (\cyw43_arch_init_with_country.dbgasm:5)
initVariant@0x100035cc (c:\Users\Rui\.platformio\packages\framework-arduinopico\variants\rpipicow\picow_init.cpp:65)
main@0x10034326 (c:\Users\Rui\.platformio\packages\framework-arduinopico\cores\rp2040\main.cpp:99)

Still investigating to see if I can pinpoint why it works with one and fails with another, but any tips are welcome if this rings any bells. :)

The only thing that crosses my mind is that maybe I have some global objects with non-trivial constructors that somehow messes things up before main is called, but don't think that's the case.

For context, what I'm trying to do is to make use of the rp2040 watchdog in my application, which works fine using Arduino-Pico's rp2040 object.
But as far I've noticed, there is no way to disable the watchdog once enabled, so if we call into any third-party code or Arduino-Pico's code that takes too long to complete, like for example connecting to Wifi, then there a good chance it will trigger a watchdog reboot.

The workaround I'm trying is to create a very simple FreeRTOS task that allows me to implement a watchdog pause of sorts.
For example, I created a task like this (stays suspended)

void autoResetTask(void* pvParameters)
{
	while(true)
	{
		rp2040.wdt_reset();
		delay(250);
	}
}

Under normal circumstances, my application calls rp2040.wtd_reset() periodically, then when I know I'm calling code that potentially can take longer than 8300ms, I wrap that code with a vTaskResume / vTasSuspend to enable/disable the watchdog auto reset.
This is all working fine with a minimal(ish) sample application I was playing around with, but with my actual application if freezes at startup as explained above.
I know this won't work with cooperative multitasking (I think Arduino-Pico's FreeRTOS uses cooperative, right?), but I'm not too bothered, since Wifi code does a few delays when connecting.

@earlephilhower
Copy link
Owner Author

From the discussion....

Seems like the other core is not doing anything yet:

image

Also, figured out why the sample application worked and my real application didn't.

extern "C" void initVariant() {
    __isPicoW = CheckPicoW();
    if (__isPicoW) {
        cyw43_arch_init_with_country(WIFICC);
    }
}

The sample application was setup to use a Pico while my real application uses a PicoW.
Once I change the sample application to use a PicoW, it also freezes.

Regarding pinging the WDT in a while loop in a separate task, that's just a workaround to avoid the WTD triggering while calling code that takes too long and I can't or don't want to change, like connecting to WiFi.
For example, calling WifiMulti::run can take longer than 8300ms, triggering the WTD.

So, back to the freeze, seems like the easiest way to repro this is to simply create a minimal application for PicoW and include the FreeRTOS.h header. It has nothing to do with using the WTD. That was just a coincidence.
This is enough to repro:

#include <Arduino.h>
#include <FreeRTOS.h> // << Just including this causes the freeze

void setup()
{
	Serial.begin(115200);
	Serial.println("Hello world");
}

void loop()
{
	Serial.println(millis());
	delay(1000);
}

My platformio.ini

[platformio]
default_envs = earlephilhower

;
; Custom data group
; can be use in [env:***] via ${common.***}
[common]
picoprobe_tools_path = B:/Utils/Picoprobe

[env:earlephilhower]
platform = https://github.com/maxgerhardt/platform-raspberrypi#5a533d6b36844183bb72794bc53091206165e921
board = rpipicow
framework = arduino
board_build.core = earlephilhower
build_type = debug
upload_protocol = custom
upload_command = ${common.picoprobe_tools_path}/upload_openocd.bat "$BUILD_DIR/${PROGNAME}.elf" "$PROJECT_DIR"
debug_tool = custom
debug_server = 
	${common.picoprobe_tools_path}/debug_openocd.bat
debug_port = localhost:3333
lib_ldf_mode=chain+

@earlephilhower
Copy link
Owner Author

Moved to an issue since we have a nice simple MCVE!

earlephilhower added a commit that referenced this issue Apr 23, 2023
Fixes #1394

The Pico_Rand SDK calls gather bits from the HW ROSC at precise intervals.
If there is jitter in the sleep_until() call then the ROSC bit collection
will always think it's failed to acquire the right bit and retry infintitely.

Avoid by wrapping the HW random number calls and the sleep_until() routine.
Only when in FreeRTOS set a flag to silently make sleep_until() into a
busy wait loop while in a random number generation step.  When not in the
random code, do the normal sleep_until call.
earlephilhower added a commit that referenced this issue Apr 23, 2023
Fixes #1394

The Pico_Rand SDK calls gather bits from the HW ROSC at precise intervals.
If there is jitter in the sleep_until() call then the ROSC bit collection
will always think it's failed to acquire the right bit and retry infintitely.

Avoid by wrapping the HW random number calls and the sleep_until() routine.
Only when in FreeRTOS set a flag to silently make sleep_until() into a
busy wait loop while in a random number generation step.  When not in the
random code, do the normal sleep_until call.
@earlephilhower earlephilhower added the freertos FreeRTOS support label Apr 27, 2023
earlephilhower added a commit that referenced this issue May 2, 2023
Fixes #1394

The Pico_Rand SDK calls gather bits from the HW ROSC at precise intervals.
If there is jitter in the sleep_until() call then the ROSC bit collection
will always think it's failed to acquire the right bit and retry infintitely.

Avoid by wrapping the HW random number calls and the sleep_until() routine.
Only when in FreeRTOS set a flag to silently make sleep_until() into a
busy wait loop while in a random number generation step.  When not in the
random code, do the normal sleep_until call.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
freertos FreeRTOS support
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant