-
Notifications
You must be signed in to change notification settings - Fork 1
디버깅을 위한 UART 파악
여타 디버깅용 장비나 환경을 이용한 방법도 있다. 예를들어 U-Link 같은 것들.
내가 자주 이용하는 방법은 주로 UART를 통해 값을 시리얼 터미널로 뿌리는 방법이다. 일단 UART관련 드라이버만 제대로 되어있다면 가장 사용하기 쉽다. Pixhawk에는 GDB를 이용하는 방법도 있다는데, 관심은 있기 때문에 한번은 봐 볼 수도 있겠다. 일단 UART의 사용법을 중점으로 정리해 둘 생각이다.
Pixhawk는 특이하게도 하드웨어적으로 구성된 시리얼 포트가 6개는 된다. 많아야 3개까지였던 나에게는 좀 충격적이었다. UART를 이용해야하는 다른 모듈들(GPS나 리시버/트렌시버 등등,,,)을 많이 이용해야 하는 보드인 만큼 UART 자원도 많았다.
아래는 APM쪽 문서를 바탕으로 필자가 보기 편하라고 만들어 둔 이미지다.
괄호 안의 알파뱃(A, B, C, D, E)는 포트 이름이다. 실제 하드웨어적 포트는 1, 2, 3과 같은 숫자로 되어있는 경우가 많은데, 굳이 알파벳으로 정한 이유는 MCU에 따라 숫자로 고정된 UART는 다소 위치적으로 배선하기 불편해서가 아닐까 생각해본다.
어쨋든 실제 APM 쪽 오픈소스를 이용해서 UART를 이용할 경우 UARTA, UARTB 와 같은 형식으로 사용하게 된다.
사용법에 대해서는 오픈소스 내부에 있는 library 예제에서 잘 나타나 있는데, 내부적으로 기본적인 설정은 다 되어있고 유저 입장에서 baudrate만 수정하는 형태는 아두이노에서 따온 방법인 듯 하다.
/*
simple test of UART interfaces
*/
#include <AP_HAL/AP_HAL.h>
#if HAL_OS_POSIX_IO
#include <stdio.h>
#endif
const AP_HAL::HAL& hal = AP_HAL::get_HAL();
/*
setup one UART at 57600
*/
static void setup_uart(AP_HAL::UARTDriver *uart, const char *name)
{
if (uart == NULL) {
// that UART doesn't exist on this platform
return;
}
uart->begin(57600);
}
void setup(void)
{
/*
start all UARTs at 57600 with default buffer sizes
*/
setup_uart(hal.uartA, "uartA"); // console
setup_uart(hal.uartB, "uartB"); // 1st GPS
setup_uart(hal.uartC, "uartC"); // telemetry 1
setup_uart(hal.uartD, "uartD"); // telemetry 2
setup_uart(hal.uartE, "uartE"); // 2nd GPS
}
static void test_uart(AP_HAL::UARTDriver *uart, const char *name)
{
if (uart == NULL) {
// that UART doesn't exist on this platform
return;
}
uart->printf("Hello on UART %s at %.3f seconds\n",
name, AP_HAL::millis()*0.001f);
}
void loop(void)
{
test_uart(hal.uartA, "uartA");
test_uart(hal.uartB, "uartB");
test_uart(hal.uartC, "uartC");
test_uart(hal.uartD, "uartD");
test_uart(hal.uartE, "uartE");
// also do a raw printf() on some platforms, which prints to the
// debug console
#if HAL_OS_POSIX_IO
::printf("Hello on debug console at %.3f seconds\n", AP_HAL::millis()*0.001f);
#endif
hal.scheduler->delay(1000);
}
AP_HAL_MAIN();
예제 또한 무지막지하게 간단하다.
void setup(void)
{
/*
start all UARTs at 57600 with default buffer sizes
*/
setup_uart(hal.uartA, "uartA"); // console
setup_uart(hal.uartB, "uartB"); // 1st GPS
setup_uart(hal.uartC, "uartC"); // telemetry 1
setup_uart(hal.uartD, "uartD"); // telemetry 2
setup_uart(hal.uartE, "uartE"); // 2nd GPS
}
hal 이라는 녀석은 이전에도 말했듯이 APM쪽에서 아랫단 드라이버와 어플리케이션 부분을 분리하기 위해 이용하는 방법이다. 아랫단 쪽은 hal로 몰아버리고 윗단은 독립적이라는 뜻. 하드웨어에 종속적일 부분은 hal로 감싸놨다고 생각해도 될 듯.
어쨋든 이 hal 내부에 uart* 꼴의 맴버들이 있고, 위는 그 것들을 초기설정 하는 부분이다.
setup_uart 함수 내부는 단순히 에러처리와 초기화 함수를 감싸놓은 형태
/*
setup one UART at 57600
*/
static void setup_uart(AP_HAL::UARTDriver *uart, const char *name)
{
if (uart == NULL) {
// that UART doesn't exist on this platform
return;
}
uart->begin(57600);
}
실제 초기화 되는 함수는 uart->begin(57600); 부분이다. 실제 이용은 다음과 같은 형태일 것이다.
hal.uartA->begin(57600);
void loop(void)
{
test_uart(hal.uartA, "uartA");
test_uart(hal.uartB, "uartB");
test_uart(hal.uartC, "uartC");
test_uart(hal.uartD, "uartD");
test_uart(hal.uartE, "uartE");
// also do a raw printf() on some platforms, which prints to the
// debug console
#if HAL_OS_POSIX_IO
::printf("Hello on debug console at %.3f seconds\n", AP_HAL::millis()*0.001f);
#endif
hal.scheduler->delay(1000);
}
test_uart 또한 에러처리와 print 함수의 레퍼다.
static void test_uart(AP_HAL::UARTDriver *uart, const char *name)
{
if (uart == NULL) {
// that UART doesn't exist on this platform
return;
}
uart->printf("Hello on UART %s at %.3f seconds\n",
name, AP_HAL::millis()*0.001f);
}
실제 용법은 다음과 같을 것이다.
hal.uartA->printf("Hello on UART %s at %.3f seconds\n",
"uartA", AP_HAL::millis()*0.001f);
그리고 HAL_OS_POSIX_IO 라는 정의가 있을때
::printf("Hello on debug console at %.3f seconds\n", AP_HAL::millis()*0.001f);
라는 녀석을 호출하는데, Pixhawk 의 경우 Serial5(앞선 이미지에서 debug쪽)를 통해 해당 문구를 볼 수 있었다. 해당 포트는 FTDI를 이용해 NSH 를 이용할 때 사용하는 포트다.
간략하게 다시 정리하면
uartA 를 기준으로
초기설정은
hal.uartA->begin(57600);
이용은
hal.uartA->printf("Hello on UART %s at %.3f seconds\n",
"uartA", AP_HAL::millis()*0.001f);
debug용 Serial5 포트의 경우 이용은
::printf("Hello on debug console at %.3f seconds\n", AP_HAL::millis()*0.001f);
이다. debug용 포트의 경우 별도로 setup 작업을 필요로 하지 않는 것 같다. APM쪽 문서에서도 ::printf 와 다른 printf 문은 위치가 다르다고 나와있는데, 별도로 관리하는 파트가 있는 것 같다.
HAL_OS_POSIX_IO 의 경우 libraries/AP_HAL/AP_HAL_Boards.h 에 다음과 같이 PX4 의 경우 정의되도록 되어있다.
#elif CONFIG_HAL_BOARD == HAL_BOARD_PX4
#define HAL_BOARD_NAME "PX4"
#define HAL_CPU_CLASS HAL_CPU_CLASS_150
#define HAL_OS_POSIX_IO 1
...
그래도 다른 보드들 처럼 UART 포트 이용이 크게 제한적인 것은 아닌 것 같아 다행인 점,,,
여차하면 debug 포트나 Serial4(GPS 2포트)를 이용해 다른 작업을 할 수도 있을 것 같다.