null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
UART 디버그 출력
#uart
#printf
#retarget
#debug
#console
@devpc
|
2026-04-02 05:47:09
|
GET /api/v1/nodes/208?nv=1
History:
v1 (2026-04-02) (Latest)
0
Views
3
Calls
# UART 디버그 출력 ## printf를 임베디드에서 쓰려면? PC에서 `printf()`는 표준 출력(stdout → 터미널)으로 나갑니다. 임베디드에서는 표준 출력이 연결된 곳이 없으므로, **`printf`가 UART로 나가도록 리타겟팅(Retargeting)** 해야 합니다. ``` [ printf 리타겟팅 개념 ] PC: printf("Hello") → [C 런타임] → stdout → 터미널 임베디드 (리타겟팅 후): printf("Hello") → [C 런타임] → _write() ← 사용자가 구현 | UART TX → PC 터미널 ``` --- ## 방법 1: _write() 오버라이드 (GCC newlib) GCC의 `newlib` C 런타임은 저수준 I/O를 `_write()` 시스템 콜에 위임합니다. 이 함수를 직접 구현하면 `printf`가 UART로 출력됩니다. ```c #include <sys/stat.h> #include "IfxAsclin_Asc.h" extern IfxAsclin_Asc g_ascHandle; /* uart_init()에서 초기화된 핸들 */ /* _write() 오버라이드 */ int _write(int fd, char *ptr, int len) { (void)fd; Ifx_SizeT size = (Ifx_SizeT)len; IfxAsclin_Asc_write(&g_ascHandle, (uint8*)ptr, &size, TIME_INFINITE); return (int)size; } ``` 이후 코드: ```c #include <stdio.h> printf("Core0 started. Count = %d\r\n", count); ``` → UART를 통해 PC 터미널에 출력됩니다. ``` [ 동작 흐름 ] printf("...") | [newlib fprintf → fwrite → write()] | _write() ← 사용자 구현 | IfxAsclin_Asc_write() | UART TX 핀 → PC 터미널 ``` --- ## 방법 2: iLLD Ifx_Console 사용 iLLD는 `Ifx_Console`이라는 경량 콘솔 출력 모듈을 제공합니다. `printf` 전체 포맷팅 기능은 없지만 코드 크기가 작고 간단합니다. ```c #include "Ifx_Console.h" #include "IfxAsclin_Asc.h" /* 초기화 */ void console_init(void) { /* uart_init()이 먼저 실행되어야 함 */ Ifx_Console_init(&g_ascHandle.stdIf.ifs); } /* 출력 예시 */ Ifx_Console_print("Hello, TC37x!\r\n"); Ifx_Console_print(ENDL); /* 줄바꿈 */ ``` `Ifx_SizeT` 정수 출력 등 기본 포맷 기능만 지원합니다. 복잡한 포맷이 필요하면 `printf` 리타겟팅을 사용하세요. --- ## PC 터미널 연결 UART 출력을 PC에서 확인하려면 터미널 프로그램이 필요합니다. ``` [ TC37x ↔ PC 연결 방법 ] TC37x 보드 +------------------+ | ASCLIN0 TX (P15.2)│──── USB-UART 변환기 ──── PC USB | ASCLIN0 RX (P15.3)│ | | GND │──── GND ─────────────────┘ +------------------+ 또는 일부 보드는 온보드 USB-UART 변환 IC를 내장 ``` 터미널 설정: | 항목 | 설정 | |---|---| | 보레이트 | 115200 (코드와 일치) | | 데이터 비트 | 8 | | 패리티 | None | | 스톱 비트 | 1 | | 흐름 제어 | None | 주요 터미널 프로그램: PuTTY (Windows), minicom (Linux), Tera Term (Windows) --- ## 디버그 출력 구성 팁 ### 출력 수준 구분 (Log Level) ```c /* 간단한 로그 레벨 매크로 */ #define LOG_LEVEL_ERROR 0 #define LOG_LEVEL_WARN 1 #define LOG_LEVEL_INFO 2 #define LOG_LEVEL_DEBUG 3 #define CURRENT_LOG_LEVEL LOG_LEVEL_INFO #define LOG_INFO(fmt, ...) do { \ if (CURRENT_LOG_LEVEL >= LOG_LEVEL_INFO) \ printf("[INFO] " fmt "\r\n", ##__VA_ARGS__); \ } while(0) #define LOG_DEBUG(fmt, ...) do { \ if (CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG) \ printf("[DEBUG] " fmt "\r\n", ##__VA_ARGS__); \ } while(0) ``` ```c /* 사용 예 */ LOG_INFO("UART initialized, baudrate=%d", 115200); LOG_DEBUG("Button state: %d", pinState); ``` ### 주의사항 ``` printf는 느리다! printf() → 포맷팅 → _write() → UART TX 115200 bps에서 "Hello\r\n" (7 bytes) ≈ 0.6ms 실시간 제어 루프 안에서 printf를 남발하면 루프 주기가 틀어질 수 있습니다. 디버그 출력은 주기-크리티컬 코드 밖에서 사용하세요. ``` --- ## 다른 MCU와의 차이점 > ⚠️ 다른 환경에서 넘어온다면 이런 점이 다를 수 있습니다. - **STM32 (HAL + newlib)**: `_write()` 오버라이드 방식이 완전히 동일. 코드 이식성 높음. - **Arduino**: `Serial.print()` / `Serial.println()`으로 간단. printf 리타겟팅 필요 없음. - **공통 주의**: printf 남용은 모든 MCU에서 실시간 성능에 영향. 임베디드 공통 이슈. - **TC37x 특징**: iLLD의 `Ifx_Console`이 경량 대안 제공. 코드 크기에 민감한 경우 유리.
// COMMENTS
Newest First
ON THIS PAGE