ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C++] 라즈베리파이 피코 기본입출력-USB Serial
    라즈베리파이 피코 2023. 2. 24. 11:52

    c 언어로된 예제에는 printf로 출력을 하였는데, c++의 cout으로도 출력이 될까?, stdio와 iostream의 동기화를 끊어 속도를 올려도 출력이 될까 궁금하여 실험해보았다.

     

    피코는 USB Serial로 PC와 통신하는데 uart0 를 사용한다는 것을 명심하자. 추가적으로 uart 장치(ex Bluetooth 모듈)를 연결하려면 uart1을 사용해야한다. 이 보다 많은 uart 장치를 연결하기 위해서는 아두이노의 softwareSerial을 구현해야 한다.(구현하는데 https://sidreco.tistory.com/12 여기서 핀 인터럽트 부분을 참고하면 될 듯하다.) 다만 uart 보다 속도도 빠르고 1:n 통신이 가능한 I2C와 SPI 통신 프로토콜을 사용하는 것을 추천한다.

     

     

    #src/CMakeLits.txt
    
    set(projname cout_test)
    
    file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS
            ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
    )
    
    add_executable(${projname} ${SRC_FILES})
    
    # pull in common dependencies
    target_link_libraries(${projname} pico_stdlib)
    
    # create map/bin/hex file etc.
    pico_add_extra_outputs(${projname})
    
    # add url via pico_set_program_url
    example_auto_set_url(${projname})
    
    #printf 출력이 USB CDC(USB Serial)로 되도록함
    pico_enable_stdio_usb(${projname} 1)
    #printf 출력이 UART로 되지 않도록 함
    pico_enable_stdio_uart(${projname} 0)

    add_excuteable 이 있는 CMakeLits.txt에서 pico_stdlib를 링크하고, pico_enable_stdio_~ 설정을 하는 것을 잊지 말아야 한다.

    cmake_minimum_required(VERSION 3.12)
    
    # Pull in SDK (must be before project)
    set(BToolDIR $ENV{PICO_SDK_PATH}/../pico-examples)
    include(${BToolDIR}/pico_sdk_import.cmake)
    
    include(${BToolDIR}/pico_extras_import_optional.cmake)
    
    project(pico_examples C CXX ASM)
    set(CMAKE_C_STANDARD 11)
    set(CMAKE_CXX_STANDARD 17)
    
    if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
        message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
    endif()
    
    set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR})
    
    # Initialize the SDK
    pico_sdk_init()
    
    include(${BToolDIR}/example_auto_set_url.cmake)
    
    #빌드할 코드가 담긴 폴더 이름 입력
    add_subdirectory(src)
    
    add_compile_options(-Wall
            -Wno-format          # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
            -Wno-unused-function # we have some for the docs that aren't called
            -Wno-maybe-uninitialized
            )

     

    기본 예제 - c 스타일

    #include <stdio.h>
    #include "pico/stdlib.h"
    
    int main() {
        gpio_init(PICO_DEFAULT_LED_PIN);
        gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
        gpio_put(PICO_DEFAULT_LED_PIN, 1);
    
        stdio_init_all();
    
        while(1) {
            printf("Hello\n");
            sleep_ms(2000);
        }
        return 0;
    }

    stdio_init_all 은 printf가 UART or USB Serial로 출력되도록 설정해주는 함수이다.

     

    iostream - c++ 스타일

    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include "pico/stdlib.h"
    
    int main() {
        gpio_init(PICO_DEFAULT_LED_PIN);
        gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
        gpio_put(PICO_DEFAULT_LED_PIN, 1);
    
        stdio_init_all();
    
        while(1) {
            cout << "Hello" << endl;
            sleep_ms(2000);
        }
        return 0;
    }

    이렇게 해도 문제없이 출력하는 것을 확인하였다.

    iostream -동기화 해제

    #include <iostream>
    using std::cout;
    using std::endl;
    
    #include "pico/stdlib.h"
    
    int main() {
        gpio_init(PICO_DEFAULT_LED_PIN);
        gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
        gpio_put(PICO_DEFAULT_LED_PIN, 1);
    
        std::ios_base::sync_with_stdio(false);
        stdio_init_all();
    
        while(1) {
            cout << "Hello" << endl;
            sleep_ms(2000);
        }
        return 0;
    }

    역시 문제없이 출력된다. 이 경우 iostream이 동기화 과정을 거치지 않고 자신만의 입출력 버퍼를 사용해서 속도가 비약적으로 향상된다. 그러나 prinf와 같이 사용했을 때

    printf("printf");
    cout << "cout" << endl;

    이렇게 사용하여도 cout이 먼저 출력될 수 있다. 

     

    그리고 남이 만든 라이브러리 안에 printf가 사용되고, 내가 main에서 cout을 사용한다면, 한 번 테스트를 해봐야 알 수 있다. 함수가 호출되고, 실행되고, 스택에 저장해둔 진행상황을 불러와 다시 main으로 돌아가는 과정이 조금 시간이 걸리기 때문에 이 경우에는 출력 순서가 뒤바뀌지 않을 가능성이 크다. 그러나 짧게 작성된 inline 함수라면 충분히 출력 순서가 뒤바뀔 수 있다.

    보율?

    getting started with raspberry pi pico 에서는 115200을 사용하였다.

    그런데 이렇게 해도 문제없이 작동하였고,

    아두이노 시리얼 모니터에서 보드 이름은 아무거나 선택하고 시리얼 포트를 열어 확인해보았을 때, 보율을 뭘 설정하든 제대로 출력이 되었다. (아두이노에서 이러면 안된다.) 컴퓨터와 시리얼 통신할 때는 동기모드를 사용하거나 uart 레지스터를 사용하지만 usb 프로토콜을 사용하는 것 같다.

     

    다만 uart 통신으로 다른 모듈/ic와 통신할 때는 보율을 지켜줘야 한다.(피코에서도 동기 모드가 있는지 모르겠다.)

    댓글

Designed by Tistory.