Kağan Kayal
Kağan Kayal

Reputation: 2453

Why does printf work in the while loop, but not before on a raspberry pi pico?

I have installed the C/C++ SDK for the Raspberry PI Pico on a Raspberry pi 4. Then I have compiled and executed the hello world example via USB successfully. I monitor the output using minicom and so far everything works fine.

However, when I add a printf before the while loop, it has no effect.

Here is the SDK Example with my 1 line addition:

#include <stdio.h>
#include "pico/stdlib.h"

int main() {
    stdio_init_all();

    printf( "Let's start\n" ); // <-- This is my addition

    while (true) {
        printf("Hello, world!\n");
        sleep_ms(1000);
    }
    return 0;
}

I do see Hello World! in minicom once a second as desired, but no Let's start. What could be the reason and how can I overcome this?

UPDATE: Answers to some questions in the comments:

Upvotes: 1

Views: 2252

Answers (2)

Slion
Slion

Reputation: 3048

Same issue on Raspberry Pi Pico W connected to Windows PC over USB.

I've added the following to that picow_blink example CMakeLists.txt in order to get logs over USB.

pico_enable_stdio_usb(picow_blink 1)
pico_enable_stdio_uart(picow_blink 0)

To fix it I simply added a 2 seconds delay after the stdio init call:

int main() {    
    stdio_init_all();
    printf("wait\n");
    sleep_ms(2000);
    printf("ready\n");
    if (cyw43_arch_init()) {
        printf("Wi-Fi init failed");
        return -1;
    }
    
    while (true) {
        printf("on\n");
        cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);        
        sleep_ms(250);
        printf("off\n");
        cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
        sleep_ms(250);
    }
}

Then I get the following output:

11:24:30:282 -> ready
11:24:30:285 -> on
11:24:30:627 -> Version: 7.95.49 (2271bb6 CY) CRC: b7a28ef3 Date: Mon 2021-11-29 22:50:27 PST Ucode Ver: 1043.2162 FWID 01-c51d9400
11:24:30:862 -> cyw43 loaded ok, mac 28:cd:c1:0e:aa:15
11:24:31:113 -> off
11:24:31:369 -> on

Note that the cyw43 init logs were also lost before and now they turn up after the loop has started executing suggesting that init function is also asynchronous. I wonder if there is a way to properly wait for those init calls to complete rather just taking guesses with sleep calls.

Upvotes: 0

Ted Lyngmo
Ted Lyngmo

Reputation: 117148

The most likely cause is that the USB initialization isn't done when stdio_init_all() returns. The first print outs will then be lost.

Define PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS to make it wait for a certain amout of time. You must define it before including the pico headers, otherwise, pico/stdio_usb.h will define it to 0.

// this must be done before indirectly including "pico/stdio_usb.h":
#ifndef PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS
#define PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS (5000)
#endif

#include <stdio.h>
#include "pico/stdlib.h"

int main(void) {
    _Bool result = stdio_init_all(); // should now wait for up to 5 seconds

    printf( "Let's start.\n" );

    for(unsigned co = 0;; ++co) {
        printf("Hello, world! %u\n", co); // Aconcagua's suggestion. Do you see "0"?
        sleep_ms(1000);
    }
    return 0;
}

If 5 seconds isn't enough, try waiting indefinitely and instead initialize USB explicitly with stdio_usb_init() which, according to the documentation, "is useful if you don't want any initial stdout output to be discarded before the connection is established".

#ifndef PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS
#define PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS (-1)
#endif

#include <stdio.h>
#include "pico/stdlib.h"

int main(void) {
    _Bool result = stdio_usb_init(); // init USB explicitly

    printf( "Let's start.\n" );

    for(unsigned co = 0;; ++co) {
        printf("Hello, world!  Init: %d  id: %u\n", (int)result, co);
        sleep_ms(1000);
    }
    return 0;
}

Some USB drivers seems to still loose I/O directly after the connection has been established, so the pico library has a define for a "post connect" delay too. It's set to 50 (ms) by default, but you could increase it:

// this also needs to be done before including any pico headers:
#ifndef PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS
#define PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS (1500)
#endif

If defining both PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS (-1) and PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS (1500) doesn't help, then you'll have no other option than to sleep manually after stdio_usb_init returns:

_Bool result = stdio_usb_init();
sleep_ms(PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS);

Note: PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS was added in

commit 13be546dc393e6ae8154e127f2b5cc8f5ee8fd95
Author: Graham Sanderson <[email protected]>
Date:   Fri Oct 8 09:01:30 2021 -0500

and requires that you recompile the pico sdk. What happens in the library when a connection is established is actually just:

sleep_ms(PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS);

Upvotes: 2

Related Questions