null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
lwIP 실전 적용 — 메모리 계산, 패딩, 초기화 버그
#lwip
#실전
#메모리계산
#eth_pad_size
#memp_init
@devpc
|
2026-05-06 05:26:57
|
GET /api/v1/nodes/642?nv=1
History:
v1 (2026-05-06) (Latest)
0
Views
1
Calls
# lwIP 실전 적용 — 메모리 계산, 패딩, 초기화 버그 ## ETH_PAD_SIZE — 왜 2를 넣는가 lwIP 설정 파일(`lwipopts.h`)에서 자주 만나는 옵션 중 하나가 `ETH_PAD_SIZE`다. **정의**: 이더넷 헤더 앞에 추가하는 패딩 바이트 수. **왜 필요한가?** 이더넷 헤더의 크기는 14바이트다. - 목적지 MAC: 6바이트 - 출발지 MAC: 6바이트 - 타입/길이 필드: 2바이트 문제는 14바이트가 4바이트 경계(32비트 정렬)에 맞지 않는다는 점이다. 14 = 4×3 + 2 이므로 IP 헤더는 4바이트 경계에서 2바이트 어긋난 주소에 위치하게 된다. 32비트 MCU에서 비정렬 메모리 접근은 성능 저하 또는 하드폴트를 유발할 수 있다. ``` ETH_PAD_SIZE = 2 설정 시: [2바이트 패딩] + [14바이트 이더넷 헤더] = 16바이트 → 이후 IP 헤더가 16바이트(4의 배수) 경계에 정렬됨 ✅ ``` 대부분의 STM32 기반 프로젝트에서 `ETH_PAD_SIZE=2`로 설정하는 이유가 여기 있다. 참조: [lwIP ARP 옵션 문서](https://www.nongnu.org/lwip/2_0_x/group__lwip__opts__arp.html#gad7fa3b356ca7e603e848b069c4cc6276) ## 최대 메모리 사용량 계산 lwIP가 이론적으로 소비하는 최대 힙 메모리는 공식으로 계산할 수 있다: ``` lwip_dynamic_peak_memory = (lwip_udp_con_num × lwip_udp_conn) + (lwip_tcp_con_num × (lwip_tcp_tx_win_size + lwip_tcp_rx_win_size + lwip_tcp_conn)) ``` | 변수 | 의미 | |------|------| | `lwip_udp_con_num` | 동시 UDP 연결 수 | | `lwip_udp_conn` | UDP 연결 하나당 메모리 | | `lwip_tcp_con_num` | 동시 TCP 연결 수 | | `lwip_tcp_tx_win_size` | TCP 송신 윈도우 크기 | | `lwip_tcp_rx_win_size` | TCP 수신 윈도우 크기 | | `lwip_tcp_conn` | TCP 연결 하나당 메모리 | 주의: 이 수치는 **이론상 최댓값**이다. 실제 소비량은 CPU 처리속도, 발열, lwIP 외부 로직의 메모리 사용 등에 따라 달라진다. MCU에 RAM이 빡빡한 경우 이 계산을 미리 해두고 `lwipopts.h`의 버퍼 크기를 조정해야 한다. ## memp_init() 무한루프 버그 lwIP를 MCU에 포팅해서 처음 초기화할 때 가끔 Init 단계에서 빠져나오지 못하는 현상이 발생한다. 디버거로 확인해보면 `memp_init()` 함수 내부에서 루프가 걸린다. 문제의 코드: ```c /* 수정 전 */ #if MEMP_SEPARATE_POOLS memp = (struct memp*)memp_bases[i]; #endif ``` 수정 후: ```c /* 수정 후 — 정렬 보장 */ #if MEMP_SEPARATE_POOLS memp = (struct memp*)LWIP_MEM_ALIGN(memp_bases[i]); #endif ``` 원인은 링크 과정에서 정렬이 어긋났거나 메모리 레이아웃이 일부 꼬인 것으로 추정된다. `LWIP_MEM_ALIGN()` 매크로를 추가해 정렬을 명시적으로 보장하면 문제가 해결된다. 이런 버그가 존재한다는 것, 그리고 커뮤니티에서 이미 비슷한 증상을 겪은 사람들이 많다는 것을 미리 알고 있으면 디버깅 시간을 크게 줄일 수 있다. ## ST 제공 lwIP 자료 활용 STM32를 사용 중이라면 ST에서 제공하는 lwIP 포팅 가이드와 예제를 먼저 참고하는 것이 빠르다. ST의 CubeMX는 lwIP 설정을 GUI로 지원하며, 생성된 코드에 `ethernetif.c`와 `lwipopts.h` 기본 설정이 포함되어 있다. 단, CubeMX가 생성한 기본 설정이 모든 프로젝트에 최적은 아니다. 버퍼 크기, 연결 수, 태스크 우선순위 등은 실제 요구사항에 맞게 조정해야 한다. ## pbuf — lwIP의 메모리 관리 구조 lwIP의 핵심 자료구조 중 하나가 **pbuf(packet buffer)**다. 패킷 데이터를 담는 연결 리스트 구조로, 실제 송수신하는 거의 모든 데이터가 pbuf로 관리된다. ``` pbuf 구조 (단순화): ┌───────────────────────────────┐ │ next → 다음 pbuf (연결 리스트) │ │ payload → 실제 데이터 포인터 │ │ len → 이 pbuf의 데이터 길이 │ │ tot_len → 전체 체인의 총 길이 │ │ type → 메모리 타입 │ │ ref → 참조 카운트 │ └───────────────────────────────┘ ``` pbuf는 용도에 따라 세 가지 타입이 있다: | 타입 | 설명 | 사용 시점 | |------|------|----------| | `PBUF_RAM` | 힙에서 할당. 유연하지만 단편화 위험 | 임시 데이터 버퍼 | | `PBUF_POOL` | 메모리 풀에서 고정 크기 블록 할당 | 수신 패킷 | | `PBUF_ROM` / `PBUF_REF` | 외부 데이터 참조 (복사 없음) | 정적 데이터 전송 | 수신 흐름에서 `PBUF_POOL`을 쓰는 이유: 고정 크기 블록이라 단편화가 없고 할당/해제가 빠르다. 반면 풀이 고갈되면 패킷을 드롭한다. pbuf 사용 후 `pbuf_free()` 호출을 빠뜨리면 메모리 풀이 고갈되어 나중에 패킷 수신이 막힌다. 이 버그는 처음에는 잘 작동하다가 일정 시간이 지나면 통신이 끊기는 패턴으로 나타난다. ## lwipopts.h 실전 설정값 예시 STM32H743 (RAM 1MB 이상) 기준 중간 부하 TCP 서버: ```c /* lwipopts.h */ #define NO_SYS 0 /* FreeRTOS 사용 */ #define LWIP_NETCONN 1 #define LWIP_SOCKET 0 /* Socket API 미사용으로 크기 절약 */ /* 메모리 */ #define MEM_SIZE (16 * 1024) #define MEMP_NUM_PBUF 24 #define MEMP_NUM_TCP_PCB 8 #define MEMP_NUM_TCP_PCB_LISTEN 2 #define MEMP_NUM_UDP_PCB 4 #define PBUF_POOL_SIZE 24 /* TCP 성능 */ #define TCP_MSS 1460 #define TCP_WND (4 * TCP_MSS) #define TCP_SND_BUF (4 * TCP_MSS) /* 체크섬 HW 오프로드 (STM32 ETH MAC 지원 시) */ #define CHECKSUM_BY_HARDWARE 1 ``` 작은 MCU(RAM 128KB 이하)라면: ```c #define MEM_SIZE (4 * 1024) #define MEMP_NUM_PBUF 8 #define MEMP_NUM_TCP_PCB 2 #define PBUF_POOL_SIZE 8 #define TCP_WND (2 * TCP_MSS) #define TCP_SND_BUF (2 * TCP_MSS) ``` ## 통합 디버깅 팁 문제가 생겼을 때 어디부터 볼지 순서: 1. **`LWIP_STATS=1` 활성화** → `lwip_stats` 구조체로 각 레이어 패킷 카운트와 에러 수 확인 2. **`LWIP_DEBUG=1` + `TCP_DEBUG=LWIP_DBG_ON`** → UART로 TCP 상태 변화 로그 출력 3. **Wireshark** → 실제로 어떤 패킷이 오가는지 확인 4. **pbuf 고갈 확인**: `MEMP_STATS=1` + 디버그 빌드에서 `lwip_stats.memp[MEMP_PBUF].err` 값이 계속 증가하면 pbuf 풀 크기를 늘린다 다음 챕터에서는 RTOS 환경에서의 lwIP 통합 전략과 동기/비동기 설계를 다룬다. OS 없이 lwIP를 쓰는 방법부터 FreeRTOS와의 통합까지 — 선택지마다 트레이드오프가 다르다.
// COMMENTS
Newest First
ON THIS PAGE