raspberrypi / pico-sdk

BSD 3-Clause "New" or "Revised" License
3.63k stars 902 forks source link

stdio: when using UART1 with GPIO4 and 5, printf also sends data to GPIO0 #1896

Closed jancumps closed 1 week ago

jancumps commented 1 week ago

When I create a new project with the new VSCode plugin, and base it on the blinky example, it will use UART1 at 9600 baud, with GPIO 4 and 5.

At the same time, GPIO0 is also entertained, with the same data, at 115.200 baud.

replication: create a project with the VSCode plugin. Select SDK 2.0.0, Gcc 13.2.1. Based on blinky. Output: UART.

Check what happens at UART1 TX: the data is there, at 9600 baud. also check what happens at pin GPIO0: the data is there, at 115200 baud.

Device used: Raspberry Pico, with RP2040

peterharperuk commented 1 week ago

The blinky program doesn't use uarts? What code are you using exactly? What changes have you made?

jancumps commented 1 week ago

I will check when I have access to a development computer. I got the example by starting the VSCode plug-in, -> create a new project from example -> select blinky

jancumps commented 1 week ago

Looks like that code is generated by this script:

https://github.com/raspberrypi/pico-project-generator/blob/fcde2c2d33395b2ba4a39aad3b16c19a4026612f/pico_project.py#L103

will-v-pi commented 1 week ago

The Pico VS Code extension doesn't use that script - it has a heavily modified version which it uses here

What exact steps did you take to create your project - because as @peterharperuk mentioned the blinky example has no UART output, and when using "New Project from Example" in the VS Code Extension there is no option to select the output

jancumps commented 1 week ago

I used the VS Code extension to create a new project from example.

Can't recall the exact options I enabled / disabled, but I got a project named blinky, with a source file blinky.c, with these contents:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"
#include "hardware/divider.h"

// UART defines
// By default the stdout UART is `uart0`, so we will use the second one
#define UART_ID uart1
#define BAUD_RATE 9600

// Use pins 4 and 5 for UART1
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define UART_TX_PIN 4
#define UART_RX_PIN 5

// GPIO defines
// Example uses GPIO 2
#define GPIO 2

int main()
{
    stdio_init_all();

    // Set up our UART
    uart_init(UART_ID, BAUD_RATE);
    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
    // For more examples of UART use see https://github.com/raspberrypi/pico-examples/tree/master/uart

    // GPIO initialisation.
    // We will make this GPIO an input, and pull it up by default
    gpio_init(GPIO);
    gpio_set_dir(GPIO, GPIO_IN);
    gpio_pull_up(GPIO);
    // See https://github.com/raspberrypi/pico-examples/tree/master/gpio for other gpio examples, including using interrupts

    // Example of using the HW divider. The pico_divider library provides a more user friendly set of APIs 
    // over the divider (and support for 64 bit divides), and of course by default regular C language integer
    // divisions are redirected thru that library, meaning you can just use C level `/` and `%` operators and
    // gain the benefits of the fast hardware divider.
    int32_t dividend = 123456;
    int32_t divisor = -321;
    // This is the recommended signed fast divider for general use.
    divmod_result_t result = hw_divider_divmod_s32(dividend, divisor);
    printf("%d/%d = %d remainder %d\n", dividend, divisor, to_quotient_s32(result), to_remainder_s32(result));
    // This is the recommended unsigned fast divider for general use.
    int32_t udividend = 123456;
    int32_t udivisor = 321;
    divmod_result_t uresult = hw_divider_divmod_u32(udividend, udivisor);
    printf("%d/%d = %d remainder %d\n", udividend, udivisor, to_quotient_u32(uresult), to_remainder_u32(uresult));
    // See https://github.com/raspberrypi/pico-examples/tree/master/divider for more complex use

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

and a CMakeList.txt file:

# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

# == DO NEVER EDIT THE NEXT LINES for Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.0.0)
set(toolchainVersion 13_2_Rel1)
set(picotoolVersion 2.0.0)
include(${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
# ====================================================================================
set(PICO_BOARD pico CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

project(blinky C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(blinky blinky.c )

pico_set_program_name(blinky "blinky")
pico_set_program_version(blinky "0.1")

# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(blinky 1)
pico_enable_stdio_usb(blinky 0)

# Add the standard library to the build
target_link_libraries(blinky
        pico_stdlib)

# Add the standard include files to the build
target_include_directories(blinky PRIVATE
  ${CMAKE_CURRENT_LIST_DIR}
  ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

pico_add_extra_outputs(blinky)
will-v-pi commented 1 week ago

Ok, so what you've done is created a "New Project" (not "New Project From Example"), named it blinky, and selected the "Add examples from Pico library" option as well as "Console over UART". This adds some example code which initialises UART1 at baud rate 9600 on GPIOs 4 & 5, in addition to demonstrating use of the hardware divider and a GPIO pull-up. It also prints the normal stdout over UART0 at 115200

Therefore what you're seeing is exactly what is expected - although I think this makes a good case to remove that "Add examples from Pico library" option, as it isn't really useful and just creates confusion.

If you want to create a project based on the blinky example, then you can use "New Project From Example", select the blinky example, and that should work for you.

jancumps commented 1 week ago

That is very well possible (that this is how I created this project). What I created this issue for, was related to something else:

When I use this code, it outputs all printf() on GPIO 4 at 9600 baud as expected. But it also outputs that same data (the same strings) to GPIO 0, at 115200 baud. On a Pico H board with a RP2040. I was not expecting that.

I will create an "as small as possible" c file that shows this, and post it here.

will-v-pi commented 1 week ago

outputs all printf() on GPIO 4 at 9600 baud as expected

The printf call should just output data over UART0, and this sample code you've provided shouldn't be printing anything over UART1. In order to print over UART1 you'l need to use uart_puts(UART_ID, "Hello world from UART1\n"), or change the default UART configuration by setting the PICO_DEFAULT_UART and related variables (see section 5 of the Pico C/C++SDK PDF)

jancumps commented 1 week ago

closing, because I can't reproduce. Thank you for supporting me.

This is the minimal example that I used, and what I thought I noticed, does not occur:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/gpio.h"

// UART defines
// By default the stdout UART is `uart0`, so we will use the second one
#define UART_ID uart1
#define BAUD_RATE 9600

// Use pins 4 and 5 for UART1
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define UART_TX_PIN 4
#define UART_RX_PIN 5

int main()
{
    stdio_init_all();

    // Set up our UART
    uart_init(UART_ID, BAUD_RATE);
    // Set the TX and RX pins by using the function select on the GPIO
    // Set datasheet for more information on function select
    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
    while (true) {
        printf("Hello, world!\n");
        sleep_ms(1000);
    }
}