Wiznet makers

ronpang

Published May 29, 2026 ©

190 UCC

93 WCC

34 VAR

0 Contests

1 Followers

0 Following

Original Link

How to Prevent Receive Data Loss with WIZnet W5500 on MCU Web Servers?

This commercial MCU web-server debugging case analyzes intermittent receive-data loss when using the WIZnet W5500 Ethernet controller.

COMPONENTS
PROJECT DESCRIPTION

How to Prevent Receive Data Loss with WIZnet W5500 on MCU Web Servers?

Summary

This commercial MCU web-server debugging case analyzes intermittent receive-data loss when using the WIZnet W5500 Ethernet controller. The observed issue appeared during HTTP POST testing: an expected 667-byte request was sometimes read as only 536 bytes. The fix investigated the W5500 socket receive-size register path, especially getSn_RX_RSR(), and added a short stabilization delay before the second register read. W5500’s role is the Ethernet MAC/PHY, hardwired TCP/IP socket engine, and packet buffer interface used by the MCU firmware.

What the Project Does

The source article is a W5500 receive-path debugging note, not a basic networking tutorial. The author found the problem while testing a web server: an HTTP POST request was occasionally truncated after the Accept- header, producing Receive_Len=536, while the correct receive length was 667 and included the remaining HTTP headers plus the form body Relay1=1&Relay2=1....

The investigation focused on the W5500 driver function that reads socket n’s receive-size register, Sn_RX_RSR. The original function reads the two-byte register twice and repeats until both reads match. The author’s modification inserts delay_ms(1) between the first and second read when the first value is nonzero, then applies the same pattern to getSn_TX_FSR() for transmit free-size checking.

For a commercial web server, this issue matters because HTTP requests are not always small single-packet messages. POST headers and body data can arrive in multiple Ethernet frames, and the MCU firmware must avoid reading the receive buffer while the W5500 receive-size value is still changing. A rare truncation bug can become a field failure when configuration forms, relay-control pages, firmware upload flows, or device-management pages rely on complete HTTP payloads.

Where WIZnet Fits

The exact WIZnet product is W5500. In this architecture, W5500 sits between the MCU firmware and the wired Ethernet network. It provides the 10/100 Ethernet MAC/PHY, hardwired TCP/IP stack, 8 independent sockets, and 32 KB internal Tx/Rx buffer memory. The MCU accesses W5500 through SPI and reads socket registers such as Sn_RX_RSR and Sn_TX_FSR to decide when data can be received or transmitted.

The W5500 receive path is register-driven. Sn_RX_RSR tells the MCU how many bytes are currently available in the socket receive buffer. After the MCU copies received data from the W5500 RX buffer, it must update the read pointer and issue the receive command so W5500 can release that buffer space. If firmware reads too early, drains too slowly, or handles HTTP payload length incorrectly, the application can see partial data even though the Ethernet link itself is working.

Performance is the practical constraint. W5500 supports SPI up to 80 MHz and offloads TCP/IP processing, but application throughput still depends on how quickly the MCU services sockets, how it checks receive-size registers, how it manages HTTP Content-Length, and how it avoids long blocking sections. Adding delay_ms(1) can stabilize a specific register-read race observed by the author, but in a commercial firmware review it should be evaluated against latency, throughput, and socket-service timing.

Implementation Notes

File: Ethernet/W5500/w5500.c
What it configures: stable reading of the socket receive-size register, Sn_RX_RSR.
Why it matters: the MCU uses this value to decide how many bytes to read from W5500’s RX buffer. A wrong or premature value can make the application process an incomplete HTTP request.

 
uint16_t getSn_RX_RSR(uint8_t sn)
{
    uint16_t val = 0, val1 = 0;

    do {
        val1 = WIZCHIP_READ(Sn_RX_RSR(sn));
        val1 = (val1 << 8) +
               WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));

        if (val1 != 0) {
            delay_ms(1);
            val = WIZCHIP_READ(Sn_RX_RSR(sn));
            val = (val << 8) +
                  WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));
        }
    } while (val != val1);

    return val;
}
 

The official ioLibrary version reads Sn_RX_RSR twice until the value is stable. The CSDN article keeps that structure but inserts a 1 ms delay before the second read after observing intermittent POST truncation in a web-server test. This is an observed project fix, not a universal replacement for every W5500 design.

File: Ethernet/W5500/w5500.c
What it configures: stable reading of the socket transmit free-size register, Sn_TX_FSR.
Why it matters: the MCU must not write more data into the W5500 TX buffer than the free space reported by the chip.

 
uint16_t getSn_TX_FSR(uint8_t sn)
{
    uint16_t val = 0, val1 = 0;

    do {
        val1 = WIZCHIP_READ(Sn_TX_FSR(sn));
        val1 = (val1 << 8) +
               WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));

        if (val1 != 0) {
            delay_ms(1);
            val = WIZCHIP_READ(Sn_TX_FSR(sn));
            val = (val << 8) +
                  WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));
        }
    } while (val != val1);

    return val;
}
 

The author applies the same stabilization idea to getSn_TX_FSR() because receive-size and transmit-free-size reads use the same two-read consistency pattern. In a commercial design, this change should be tested with real traffic patterns, because a fixed 1 ms delay inside a frequently called driver function can reduce responsiveness if it is used in a tight loop.

Practical Tips / Pitfalls

  • Do not treat Sn_RX_RSR as a complete application message length. It is only the number of bytes currently available in the W5500 socket RX buffer.
  • For HTTP POST, parse Content-Length and keep reading until the full body is received. A single socket read may not contain the full request.
  • Avoid long blocking delays in high-frequency socket loops. If a 1 ms delay is added for stability, measure its impact on latency and throughput.
  • Read Sn_TX_FSR before sending and split large responses if the W5500 TX buffer does not have enough free space.
  • Keep SPI access atomic around W5500 register reads. Interrupts or shared SPI devices can corrupt timing if chip select and transfers are not controlled carefully.
  • Add counters for truncated requests, RX size snapshots, HTTP parse failures, socket close events, and timeout paths. Commercial web servers need diagnostics for rare receive bugs.
  • Test with real browsers, not only small TCP echo tools. Browser HTTP headers, keep-alive behavior, and POST bodies expose receive-path bugs that simple tests often miss.

FAQ

Q: Why use WIZnet W5500 in this commercial web-server receive path?
A: W5500 provides the wired Ethernet MAC/PHY, hardwired TCP/IP stack, socket state machine, and internal Tx/Rx buffers. This lets the MCU focus on the web-server logic while W5500 handles Ethernet transport and socket buffering. The receive-data issue in this project occurs at the boundary between W5500 socket registers and MCU firmware, not because W5500 lacks TCP/IP offload.

Q: How does W5500 connect to the MCU platform?
A: W5500 connects to the MCU through SPI. The MCU reads and writes W5500 registers and buffers using SPI transactions, then uses socket registers such as Sn_RX_RSR, Sn_TX_FSR, Sn_RX_RD, and Sn_TX_WR to move data between the MCU application and W5500’s internal socket memory.

Q: What role does W5500 play in this debugging case?
A: W5500 is the TCP socket engine for the embedded web server. It receives browser HTTP data into its RX buffer and exposes the available byte count through Sn_RX_RSR; the MCU firmware then decides how much data to copy, how to parse HTTP headers and body, and when to release the consumed receive buffer.

Q: Can beginners follow this project?
A: It is better for developers who already understand W5500 socket programming, SPI register access, HTTP request structure, and embedded C debugging. The article is valuable because it shows a real intermittent failure: the network link worked, the web server mostly worked, but the receive-size handling caused rare truncated HTTP data.

Q: How does this compare with an LwIP-based web server?
A: With W5500, TCP/IP processing and socket buffers live inside the Ethernet controller, so the MCU mainly manages SPI register access and application parsing. With LwIP, the MCU runs a software TCP/IP stack; lwIP is designed to reduce RAM usage while still providing a full TCP stack for embedded systems, but the firmware owns more of the packet-buffer, driver, and protocol timing behavior. W5500 simplifies the stack boundary, while LwIP gives deeper software control.

Source

Original article: CSDN, “W5500接收丢数据,” first published on 2025-10-10 and modified on 2025-10-10. The article is marked CC 4.0 BY-SA.

WIZnet product reference: W5500 documentation.

WIZnet driver reference: Ethernet/W5500/w5500.c in ioLibrary Driver.

Alternative reference for comparison: lwIP 2.1.0 overview.

Tags

#W5500 #WIZnet #Sn_RX_RSR #Sn_TX_FSR #SocketRegisters #EmbeddedWebServer #TCP #SPI #Commercial #Performance #ReceiveBuffer #ioLibrary #NetworkStack

MCU 웹 서버에서 WIZnet W5500 수신 데이터 손실을 방지하는 방법은?

요약

이 상용 MCU 웹 서버 디버깅 사례는 WIZnet W5500 이더넷 컨트롤러를 사용할 때 간헐적으로 발생한 수신 데이터 손실 문제를 분석합니다. 문제는 HTTP POST 테스트 중 나타났습니다. 정상적으로는 667바이트 요청이 수신되어야 하지만, 가끔 536바이트만 읽히는 현상이 발생했습니다. 해결 과정에서는 W5500 소켓 수신 크기 레지스터 경로, 특히 getSn_RX_RSR()를 점검했고, 두 번째 레지스터 읽기 전에 짧은 안정화 지연을 추가했습니다. W5500은 MCU 펌웨어가 사용하는 Ethernet MAC/PHY, 하드웨어 TCP/IP 소켓 엔진, 패킷 버퍼 인터페이스 역할을 합니다.

프로젝트가 하는 일

원문은 기본 네트워크 튜토리얼이 아니라 W5500 수신 경로 디버깅 기록입니다. 작성자는 웹 서버 테스트 중 문제를 발견했습니다. HTTP POST 요청이 간헐적으로 Accept- 헤더 이후에서 잘려 Receive_Len=536으로 표시되었고, 정상적인 수신 길이는 나머지 HTTP 헤더와 form body Relay1=1&Relay2=1...까지 포함한 667바이트였습니다.

조사는 W5500 드라이버 함수가 소켓 n의 수신 크기 레지스터인 Sn_RX_RSR를 읽는 방식에 집중했습니다. 기존 함수는 2바이트 레지스터를 두 번 읽고, 두 값이 일치할 때까지 반복합니다. 작성자의 수정은 첫 번째 값이 0이 아닐 때 첫 번째 읽기와 두 번째 읽기 사이에 delay_ms(1)을 추가하는 방식입니다. 이후 같은 패턴을 송신 가능 크기를 확인하는 getSn_TX_FSR()에도 적용했습니다.

상용 웹 서버에서는 이 문제가 중요합니다. HTTP 요청은 항상 작은 단일 패킷 메시지로 오지 않습니다. POST 헤더와 body 데이터는 여러 Ethernet frame으로 나뉘어 도착할 수 있고, MCU 펌웨어는 W5500 수신 크기 값이 아직 변하는 중일 때 RX 버퍼를 읽지 않도록 처리해야 합니다. 드물게 발생하는 잘림 현상도 설정 form, 릴레이 제어 페이지, 펌웨어 업로드, 장치 관리 페이지에서 필드 장애로 이어질 수 있습니다.

WIZnet이 들어가는 위치

이 프로젝트에서 사용되는 WIZnet 제품은 W5500입니다. 이 구조에서 W5500은 MCU 펌웨어와 유선 Ethernet 네트워크 사이에 위치합니다. W5500은 10/100 Ethernet MAC/PHY, 하드웨어 TCP/IP 스택, 8개 독립 소켓, 32 KB 내부 Tx/Rx 버퍼 메모리를 제공합니다. MCU는 SPI를 통해 W5500에 접근하고, Sn_RX_RSR, Sn_TX_FSR 같은 소켓 레지스터를 읽어 데이터를 수신하거나 송신할 수 있는지 판단합니다.

W5500 수신 경로는 레지스터 기반입니다. Sn_RX_RSR는 현재 소켓 RX 버퍼에서 MCU가 읽을 수 있는 바이트 수를 알려줍니다. MCU가 W5500 RX 버퍼에서 수신 데이터를 복사한 뒤에는 read pointer를 갱신하고 receive command를 실행해야 W5500이 해당 버퍼 공간을 해제할 수 있습니다. 펌웨어가 너무 이르게 읽거나, RX 버퍼를 충분히 빠르게 비우지 못하거나, HTTP payload length 처리를 잘못하면 Ethernet link 자체는 정상이어도 애플리케이션에서는 부분 데이터만 보일 수 있습니다.

성능이 실제 제약입니다. W5500은 최대 80 MHz SPI를 지원하고 TCP/IP 처리를 오프로딩하지만, 애플리케이션 처리량은 MCU가 얼마나 빠르게 소켓을 서비스하는지, 수신 크기 레지스터를 어떻게 확인하는지, HTTP Content-Length를 어떻게 관리하는지, 긴 blocking 구간을 어떻게 피하는지에 의해 결정됩니다. delay_ms(1) 추가는 작성자가 관찰한 특정 레지스터 읽기 race를 안정화할 수 있지만, 상용 펌웨어에서는 latency, throughput, socket service timing에 미치는 영향을 함께 평가해야 합니다.

구현 참고 사항

파일: Ethernet/W5500/w5500.c
설정 내용: 소켓 수신 크기 레지스터 Sn_RX_RSR의 안정적인 읽기
중요한 이유: MCU는 이 값을 기준으로 W5500 RX 버퍼에서 몇 바이트를 읽을지 결정합니다. 잘못되었거나 너무 이른 값은 애플리케이션이 불완전한 HTTP 요청을 처리하게 만들 수 있습니다.

 
uint16_t getSn_RX_RSR(uint8_t sn)
{
    uint16_t val = 0, val1 = 0;

    do {
        val1 = WIZCHIP_READ(Sn_RX_RSR(sn));
        val1 = (val1 << 8) +
               WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));

        if (val1 != 0) {
            delay_ms(1);
            val = WIZCHIP_READ(Sn_RX_RSR(sn));
            val = (val << 8) +
                  WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_RX_RSR(sn), 1));
        }
    } while (val != val1);

    return val;
}
 

공식 ioLibrary 버전은 Sn_RX_RSR를 두 번 읽고 값이 안정될 때까지 반복합니다. CSDN 원문은 이 구조를 유지하면서, 웹 서버 테스트에서 간헐적인 POST 잘림 현상을 관찰한 뒤 두 번째 읽기 전에 1 ms 지연을 추가했습니다. 이는 관찰된 프로젝트 수정이며, 모든 W5500 설계에 보편적으로 적용해야 하는 대체 구현은 아닙니다.

파일: Ethernet/W5500/w5500.c
설정 내용: 소켓 송신 가능 크기 레지스터 Sn_TX_FSR의 안정적인 읽기
중요한 이유: MCU는 W5500 TX 버퍼에 기록 가능한 공간보다 더 많은 데이터를 쓰면 안 됩니다.

 
uint16_t getSn_TX_FSR(uint8_t sn)
{
    uint16_t val = 0, val1 = 0;

    do {
        val1 = WIZCHIP_READ(Sn_TX_FSR(sn));
        val1 = (val1 << 8) +
               WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));

        if (val1 != 0) {
            delay_ms(1);
            val = WIZCHIP_READ(Sn_TX_FSR(sn));
            val = (val << 8) +
                  WIZCHIP_READ(WIZCHIP_OFFSET_INC(Sn_TX_FSR(sn), 1));
        }
    } while (val != val1);

    return val;
}
 

작성자는 receive-size와 transmit-free-size 읽기가 같은 두 번 읽기 안정화 패턴을 사용하므로, 같은 안정화 아이디어를 getSn_TX_FSR()에도 적용했습니다. 상용 설계에서는 이 변경을 실제 트래픽 패턴으로 검증해야 합니다. 자주 호출되는 드라이버 함수 안에 고정 1 ms 지연이 들어가면 tight loop에서 응답성이 떨어질 수 있기 때문입니다.

실무 팁 / 주의점

  • Sn_RX_RSR를 완전한 애플리케이션 메시지 길이로 취급하면 안 됩니다. 이 값은 W5500 소켓 RX 버퍼에서 현재 읽을 수 있는 바이트 수일 뿐입니다.
  • HTTP POST에서는 Content-Length를 파싱하고 body 전체가 수신될 때까지 계속 읽어야 합니다. 단일 socket read에 전체 요청이 들어온다고 가정하면 안 됩니다.
  • 고빈도 소켓 루프 안에서 긴 blocking delay를 피해야 합니다. 안정화를 위해 1 ms 지연을 추가했다면 latency와 throughput 영향을 측정해야 합니다.
  • 송신 전에는 Sn_TX_FSR를 읽고, W5500 TX 버퍼에 충분한 여유 공간이 없으면 큰 response를 나누어 보내야 합니다.
  • W5500 레지스터 읽기 중 SPI 접근을 atomic하게 유지해야 합니다. 인터럽트나 공유 SPI 장치가 chip select와 전송 타이밍을 깨뜨리면 문제가 생길 수 있습니다.
  • 잘린 요청 수, RX size snapshot, HTTP parse failure, socket close event, timeout path 카운터를 추가해야 합니다. 상용 웹 서버에는 드문 수신 버그를 추적할 수 있는 진단 기능이 필요합니다.
  • 작은 TCP echo 도구만으로 테스트하지 말고 실제 브라우저로 테스트해야 합니다. 브라우저의 HTTP header, keep-alive 동작, POST body는 단순 테스트에서 드러나지 않는 수신 경로 문제를 노출합니다.

FAQ

Q: 상용 웹 서버 수신 경로에서 왜 WIZnet W5500을 사용하나요?
A: W5500은 유선 Ethernet MAC/PHY, 하드웨어 TCP/IP 스택, 소켓 상태 머신, 내부 Tx/Rx 버퍼를 제공합니다. MCU는 웹 서버 로직에 집중하고, W5500은 Ethernet 전송과 소켓 버퍼링을 담당합니다. 이 프로젝트의 수신 데이터 문제는 W5500에 TCP/IP 오프로딩이 없어서가 아니라, W5500 소켓 레지스터와 MCU 펌웨어 사이의 경계에서 발생한 처리 문제입니다.

Q: W5500은 MCU 플랫폼에 어떻게 연결되나요?
A: W5500은 SPI를 통해 MCU에 연결됩니다. MCU는 SPI transaction으로 W5500 레지스터와 버퍼를 읽고 쓰며, Sn_RX_RSR, Sn_TX_FSR, Sn_RX_RD, Sn_TX_WR 같은 소켓 레지스터를 사용해 MCU 애플리케이션과 W5500 내부 소켓 메모리 사이에서 데이터를 이동합니다.

Q: 이 디버깅 사례에서 W5500은 어떤 역할을 하나요?
A: W5500은 임베디드 웹 서버의 TCP 소켓 엔진입니다. 브라우저의 HTTP 데이터를 RX 버퍼에 수신하고, Sn_RX_RSR를 통해 읽을 수 있는 바이트 수를 MCU에 제공합니다. MCU 펌웨어는 이후 얼마나 복사할지, HTTP header와 body를 어떻게 파싱할지, 소비한 receive buffer를 언제 해제할지 결정합니다.

Q: 초보자도 이 프로젝트를 따라갈 수 있나요?
A: W5500 소켓 프로그래밍, SPI 레지스터 접근, HTTP 요청 구조, 임베디드 C 디버깅을 이미 이해한 개발자에게 더 적합합니다. 이 글의 가치는 실제 간헐 장애를 보여준다는 점입니다. 네트워크 링크도 정상이고 웹 서버도 대부분 정상 동작했지만, receive-size 처리 때문에 드물게 HTTP 데이터가 잘렸습니다.

Q: LwIP 기반 웹 서버와 비교하면 어떤 차이가 있나요?
A: W5500을 사용하면 TCP/IP 처리와 소켓 버퍼가 Ethernet 컨트롤러 내부에 있으므로 MCU는 주로 SPI 레지스터 접근과 애플리케이션 파싱을 관리합니다. LwIP를 사용하면 MCU가 소프트웨어 TCP/IP 스택을 실행합니다. LwIP는 임베디드 시스템에서 RAM 사용량을 줄이면서 full TCP stack을 제공하도록 설계되었지만, 펌웨어가 packet buffer, driver, protocol timing 동작을 더 많이 소유합니다. W5500은 stack boundary를 단순화하고, LwIP는 software control을 더 깊게 제공합니다.

출처

Original article: CSDN, “W5500接收丢数据,” 2025-10-10 게시, 2025-10-10 수정, CC 4.0 BY-SA로 표시됨.
https://blog.csdn.net/weixin_42550185/article/details/152927525?spm=1001.2014.3001.5502

WIZnet product reference: W5500 documentation.
https://docs.wiznet.io/Product/Chip/Ethernet/W5500

WIZnet driver reference: Ethernet/W5500/w5500.c in ioLibrary Driver.
https://github.com/Wiznet/ioLibrary_Driver/blob/master/Ethernet/W5500/w5500.c

Alternative reference for comparison: lwIP 2.1.0 overview.
https://www.nongnu.org/lwip/2_1_x/index.html

태그

#W5500 #WIZnet #Sn_RX_RSR #Sn_TX_FSR #SocketRegisters #EmbeddedWebServer #TCP #SPI #Commercial #Performance #ReceiveBuffer #ioLibrary #NetworkStack

 

Documents
Comments Write