TDA3x EVM에서 Vision SDK의 NDK(Network Development Kit)를 활용하여 네트워크 통신을 구성하는 방법을 정리한다. NullSource에서 생성한 YUV 프레임을 NetworkTx로 PC에 전송하는 과정을 예제로 다룬다.
테스트 환경
- Ubuntu 22.04
- TDA3XEVM
- PROCESSOR_SDK_VISION_03_08_00_00
NDK란?
TI-RTOS(SYS/BIOS) 환경에서 동작하는 경량 TCP/IP 네트워크 스택이다. TDA3x의 GMAC Switch 이더넷 하드웨어를 통해 보드와 PC 간 비디오 프레임, 제어 명령 등을 주고받을 수 있다.
| 기능 | 설명 |
|---|---|
| TCP/IP 통신 | NetworkTx/Rx 링크로 비디오 데이터 송수신 |
| DHCP / Static IP | 동적, 정적 IP 모두 지원 |
| Telnet | 원격 콘솔 접속 (기본 활성화) |
| Dual MAC Port | TDA3xx EVM에서 이더넷 포트 2개 동시 사용 가능 |
전체 구조
+------------------+ TCP (Port 29172) +------------------+
| TDA3x Board | ============================== | PC (Host) |
| | Ethernet (RGMII) | |
| NullSrc Link | | network_rx tool |
| | | | 또는 nc 명령 |
| NetworkTx Link | <-- PC가 접속하면 전송 시작 --> | |
| | | | |
| NDK Stack | | |
| | | | |
| GMAC SW Driver | | |
+------------------+ +------------------+
핵심 포인트: NetworkTx는 서버 모드다. 보드가 먼저 데이터를 쏘는 게 아니라, PC가 보드의 포트에 TCP 접속해야 전송이 시작된다.
주요 포트 번호:
- 5000 - NetworkCtrl (제어 명령)
- 29171 - NetworkRx (보드가 수신)
- 29172 - NetworkTx (보드가 송신)
1단계: 빌드 설정
NDK를 쓰려면 세 곳의 설정 파일을 건드려야 한다.
플랫폼 cfg.mk에서 NDK 활성화
apps/configs/tda3xx_evm_bios_all/cfg.mk에서 NDK를 실행할 프로세서를 지정한다.
# NDK를 실행할 프로세서 (ipu1_0 | ipu1_1 | none)
NDK_PROC_TO_USE=ipu1_0
# IPv6 지원 여부
NDK_ENABLE_IPV6=no
# TFDTP 고속 전송 프로토콜
NSP_TFDTP_INCLUDE=no
TDA3x에서는 A15를 NDK 프로세서로 사용할 수 없다. ipu1_0 또는 ipu1_1만 가능하다.
uc_cfg.mk에서 Use-Case 켜기
apps/configs/tda3xx_evm_bios_all/uc_cfg.mk에 use-case를 활성화한다.
UC_null_src_ndk=yes
UC_LIST에 등록 (이걸 빼먹으면 메뉴에 안 나온다)
apps/configs/cfg.mk의 UC_LIST에 추가한다.
UC_LIST = \
...
UC_null_src_mpeg4enc_null \
UC_null_src_ndk \
UC_tfdtprx_display \
...
이게 빠지면 system_cfg.h에 #define UC_null_src_ndk가 생성되지 않고, #ifdef로 감싸진 메뉴 코드가 컴파일에서 빠진다. uc_cfg.mk에서 yes로 해놔도 소용없다. 실제로 이것 때문에 한참 헤맸다.
빌드:
cd vision_sdk
make -s
# 변경이 반영 안 되면 클린 빌드
make clean && make -s
빌드 후 확인:
grep UC_null_src_ndk links_fw/include/config/apps/tda3xx_evm_bios_all/system_cfg.h
# 출력: #define UC_null_src_ndk
2단계: IP 주소 설정
설정 파일: links_fw/src/rtos/bios_app_common/tda3xx/cfg/NDK_config.cfg
DHCP (기본값)
별도 설정 없이 DHCP 서버가 있으면 자동으로 IP가 할당된다.
var enableStaticIpEth0 = 0; // 0 = DHCP
정적 IP로 변경하기
DHCP 서버가 없는 환경이라면 정적 IP를 설정한다.
var enableStaticIpEth0 = 1; // Static IP 활성화
파일 하단에서 IP를 수정한다:
Ip.address = "192.168.1.200";
Ip.mask = "255.255.255.0";
Ip.gatewayIpAddr = "192.168.1.1";
수정 후 재빌드 필요.
MAC 주소
별도 설정 불필요. SoC EFuse에서 자동으로 읽어온다.
3단계: 예제 코드 분석 (null_src_ndk)
apps/src/rtos/usecases/null_src_ndk/ 디렉토리의 예제를 살펴보자.
체인 구조
NullSource (YUV420SP, 1280x720, 30fps) --> NetworkTx (TCP, Port 29172)
NullSrc 설정
// chains_nullSrcNetworkTx.c
pNullSrcPrm->timerPeriodMilliSecs = 33; // 30fps
pNullSrcPrm->outQueInfo.numCh = 1;
pNullSrcPrm->channelParams[0].numBuffers = 4;
pChInfo->width = 1280;
pChInfo->height = 720;
// 데이터 포맷: YUV420SP (NV12)
pChInfo->flags = System_Link_Ch_Info_Set_Flag_Data_Format(
pChInfo->flags, SYSTEM_DF_YUV420SP_UV);
NetworkTx 설정
pObj->NetworkTxPrm.networkServerPort = NETWORK_TX_SERVER_PORT; // 29172
ChainsCommon_networkTxSetMode(&pObj->NetworkTxPrm);
소스 버퍼 초기화
NullSource는 빈 버퍼를 생성하므로, 테스트용으로 흰색 프레임을 채워 넣는다.
// Y plane: 흰색 (0xFF)
memset(pVideoFrame->bufAddr[0], 0xFF, (1280 * 720));
// UV plane: 무채색 (0x80)
memset(pVideoFrame->bufAddr[1], 0x80, (1280 * 720 / 2));
// 중요: Cache writeback을 해줘야 실제 메모리에 반영된다
Cache_wb(pVideoFrame->bufAddr[0], ...);
Cache_wb(pVideoFrame->bufAddr[1], ...);
실행 흐름
Chains_nullSrcNetworkTx()
+-> Create (체인 생성)
+-> fillSrcBuf (버퍼에 흰색 프레임 채우기)
+-> Start (NullSrc 30fps 생성 시작, NetworkTx listen 시작)
+-> Runtime Menu (0: Stop, p: Print Stats)
+-> Stop / Delete
4단계: PC에서 수신 테스트
보드 실행
UART 콘솔에서:
- 메인 메뉴에서
a(Miscellaneous test's) 선택 4(NullSrc (YUV) + NDK NetworkTx) 선택- 보드 IP 확인 (부팅 시 UART에 출력됨)
PC에서 접속
방법 1: Vision SDK Network Tools
cd vision_sdk/apps/tools/network_tools
make
./bin/network_rx --host 192.168.1.200 --port 29172
방법 2: netcat으로 간단 테스트
nc 192.168.1.200 29172 > received_data.bin
# 수신된 데이터 크기 확인
# YUV420SP 1프레임 = 1280 * 720 * 1.5 = 1,382,400 bytes
ls -l received_data.bin
방법 3: tcpdump로 패킷 확인
# 먼저 nc로 접속한 후, 다른 터미널에서 확인
sudo tcpdump -i eth0 host 192.168.1.200 and port 29172 -c 10
주의: tcpdump만 켜놓고 기다리면 아무것도 안 잡힌다. PC에서 먼저 보드에 TCP 접속해야 한다.
새로운 NDK Use-Case 만들기
기존 null_src_ndk를 참고해서 자신만의 use-case를 등록하는 절차:
1) cfg.mk 작성 - apps/src/rtos/usecases/my_usecase/cfg.mk
ifeq ($(NDK_PROC_TO_USE), none)
$(error NDK_PROC_TO_USE should be enabled)
endif
ifeq ($(NDK_PROC_TO_USE), ipu1_0)
NEED_PROC_IPU1_0=yes
endif
2) UC_LIST에 추가 - apps/configs/cfg.mk
3) uc_cfg.mk에서 활성화 - apps/configs/tda3xx_evm_bios_all/uc_cfg.mk
4) 메뉴 등록 - apps/src/rtos/common/chains_main_bios_misc.c
// 메뉴 문자열
#ifdef UC_my_usecase
"\r\n N: My NDK Usecase"
#endif
// 핸들러
#ifdef UC_my_usecase
case 'N':
Chains_myUsecase(&gChains_usecaseCfg);
break;
#endif
5) 빌드 후 system_cfg.h에서 define 확인
주요 파일 경로
vision_sdk/
├── apps/configs/
│ ├── cfg.mk # UC_LIST (마스터 목록)
│ └── tda3xx_evm_bios_all/
│ ├── cfg.mk # NDK_PROC_TO_USE 설정
│ └── uc_cfg.mk # UC 활성화 on/off
├── apps/src/rtos/
│ ├── common/chains_main_bios_misc.c # 메뉴 등록
│ └── usecases/null_src_ndk/ # 예제 use-case
├── apps/tools/network_tools/ # PC측 수신 도구
├── links_fw/
│ ├── include/link_api/
│ │ ├── networkCtrl_if.h # 포트 번호, 헤더 구조체
│ │ ├── networkTxLink.h # NetworkTx API
│ │ └── networkRxLink.h # NetworkRx API
│ └── src/rtos/bios_app_common/
│ └── tda3xx/cfg/NDK_config.cfg # IP, 버퍼, 인터럽트 설정
'TI > TDA3' 카테고리의 다른 글
| UART2 추가 가이드 (0) | 2026.02.19 |
|---|---|
| Draw2D를 이용해 한글 표시 (0) | 2025.12.31 |
| I2C SLAVE MODE (0) | 2025.06.03 |
| Vision SDK Usecase 사용 방법 (0) | 2025.04.16 |
| CSL Example 프로그램 사용 방법 (0) | 2025.04.12 |