Wiznet makers

Benjamin

Published June 17, 2026 ©

121 UCC

11 WCC

10 VAR

0 Contests

0 Followers

2 Following

Original Link

How to Build an Interrupt-Driven W5500 UDP Server on STM32F4 with FreeRTOS and ioLibrary

An STM32F407 and WIZnet W5500 UDP echo server on FreeRTOS, using the ioLibrary hardware sockets with interrupt-driven receive over SPI.

COMPONENTS Hardware components

WIZnet - W5500

x 1

Hardware TCP/IP Ethernet controller on SPI1 (UDP sockets)


PROJECT DESCRIPTION

📌 Overview

This project is a compact, code-complete reference for running a WIZnet W5500 as a UDP server on an STM32F407 under FreeRTOS. The STM32 talks to the W5500 over SPI, the W5500 handles the TCP/IP stack in hardware, and a FreeRTOS task waits on a hardware receive interrupt. When a UDP datagram arrives, the firmware reads it and replies "answer_OK". A second task blinks status LEDs. It is a clean starting point for anyone wiring the W5500 ioLibrary into an RTOS application rather than a finished product.

STM32F407 and WIZnet W5500 UDP server: PC client over Ethernet to the W5500 hardware sockets and over SPI to the STM32F407 running FreeRTOS Generated technical diagram: PC to Ethernet to W5500 hardware sockets to SPI to STM32F407.

System Configuration

The firmware targets an STM32F407 (STM32CubeMX project, 168 MHz clock) and a WIZnet W5500 Ethernet controller on SPI1. SPI1 runs as master in mode 0 (CPOL low, CPHA first edge) with software chip select and a /4 prescaler. The network settings are static (IP, MAC, gateway, mask), the UDP service port is 1111, and a single hardware socket is used in non-blocking mode. The build is Makefile based and splits the standard library, the W5500 library, and FreeRTOS into separate include files. Two Python helpers in scripts/udp act as test peers.

The networking code uses the WIZnet ioLibrary_Driver; FreeRTOS and the ST STM32F4 HAL are bundled as middleware and drivers. The W5500 parts are listed in the Hardware Components panel.

System Architecture and Data Flow

The data path is short and deterministic. A PC sends a UDP datagram to the board's static IP on port 1111. The packet reaches the W5500 over Ethernet, where the hardware TCP/IP stack stores it in the socket receive buffer and raises a receive interrupt. The STM32F407 reads the datagram over SPI with recvfrom, then answers with sendto("answer_OK"). Because the W5500 owns the protocol stack, the STM32 only moves bytes over SPI and runs application logic.

Data flow: PC UDP client over Ethernet to the WIZnet W5500 hardware socket, then SPI1 to the STM32F407 plus FreeRTOS which echoes a reply Generated technical diagram: the UDP echo path from PC to W5500 to STM32F407.

Software Stack on STM32F407

The firmware is layered cleanly. The application has two FreeRTOS tasks: udp_task for the echo service and led_task for a status LED. FreeRTOS provides the scheduler and non-blocking timing. The WIZnet ioLibrary_Driver exposes the socket API (socket, sendto, recvfrom, ctlsocket, getSn_SR). A thin W5500 SPI driver binds the chip select, single-byte, and burst callbacks to STM32 SPI through reg_wizchip_cs_cbfunc, reg_wizchip_spi_cbfunc, and reg_wizchip_spiburst_cbfunc. At the bottom is the W5500 itself, with eight hardware sockets, MAC and PHY, and a receive interrupt line.

Software stack: application tasks over FreeRTOS over the WIZnet ioLibrary over the W5500 SPI driver over the W5500 hardware TCP/IP chip Generated technical diagram: the five layers from application down to the W5500.

⚙️ Role of the WIZnet Chip

The W5500 is the reason the firmware stays small. It is a hardwired TCP/IP controller, so the protocol stack runs inside the chip and the STM32F407 only drives it over SPI. The MCU never spends cycles or RAM on a software stack such as lwIP or Mongoose, which leaves more room for application tasks and keeps timing predictable. That hardware offload is what makes this a TCP/IP offload (TOE) design. The project also uses the W5500 the way it is meant to be used in an RTOS: the chip raises a receive interrupt, so the udp_task only does work when a datagram actually arrives instead of polling, which is friendlier to the FreeRTOS scheduler.

Interrupt-Driven Receive Loop

The receive path is interrupt gated. The socket interrupt mask is set with setSIMR and setSn_IMR, and INT_RECV_ON arms the receive interrupt. When the W5500 receives a datagram it sets the socket interrupt, the udp_task reads it with recvfrom, sends the "answer_OK" reply, and re-arms the interrupt. The socket is opened in non-blocking mode, so the task yields with vTaskDelay between events rather than spinning.

Interrupt receive loop: W5500 receive interrupt, socket interrupt flag, task wake, recvfrom, sendto answer_OK, re-arm interrupt Generated technical diagram: the non-blocking, interrupt-gated UDP echo handled inside a FreeRTOS task.

Where It Fits: Value and Limits

This is a good reference for the first milestone of many STM32 Ethernet projects: get the W5500 linked, open a socket, and exchange packets reliably under an RTOS. The interrupt-driven pattern and the clean SPI callback wiring are reusable in larger designs that add DHCP, TCP services, or MQTT later.

It is fair to note the limits. The repository has no README or project-level license, the address is static only (no DHCP), and the UDP echo is a demonstration rather than a full application; the TCP branch is guarded by a build flag and is not the default. A socket buffer sizing call is left commented out, so default sizes apply. Verify your own pin map, SPI speed, and network settings before reusing it.

Related WIZnet Maker Projects

This project sits among several STM32 plus W5500 examples on the Maker site. Three are close enough to compare directly.

STM32 W5500 TCP Server with FreeRTOS (Non-Blocking Multi-Tasking Setup) (Grade A) is the closest sibling: a non-blocking W5500 server on STM32 under FreeRTOS using the ioLibrary socket API. Both projects share the STM32 + W5500 + FreeRTOS + ioLibrary combination and a non-blocking socket design. The transport and event trigger differ: that project uses TCP and a polled accept() loop to handle connection requests; this one uses UDP (connectionless, no handshake overhead) and arms the W5500 receive interrupt so the udp_task wakes only when a datagram arrives. The interrupt-driven path avoids polling the SPI bus between packets and is friendlier to the FreeRTOS scheduler.

STM32F446_W5500__FREERTOS (Grade A) runs the same STM32F4 + W5500 + FreeRTOS + ioLibrary combination on an F446 instead of an F407, and adds DHCP for dynamic address assignment. Both projects are useful starting points for the ioLibrary-on-RTOS integration; the side-by-side shows the same pattern working across STM32F4 variants. The concrete differences are the MCU part (F446 vs F407), the address mode (DHCP vs static-only here), and the transport (TCP there; UDP with interrupt here).

How to Implement Mongoose Networking Library on STM32F4 using W5500 (Grade A) layers the Mongoose software networking library over the W5500 on an STM32F4, adding HTTP, WebSocket, and MQTT support above the hardware socket level. Both projects use STM32F4 + W5500 for embedded Ethernet. The design philosophy differs: Mongoose trades RAM and code size for protocol richness; this project drives the W5500 ioLibrary hardware sockets directly, keeping the firmware small and timing predictable. Comparing the two shows the concrete trade-off between a feature-rich software stack and a lean TOE design.

The shared thread is the WIZnet W5500 as a hardwired TCP/IP controller for STM32F4. This project is the minimal, interrupt-driven UDP reference of the group - the one that shows setSIMR / setSn_IMR / INT_RECV_ON wired into a FreeRTOS task with the fewest moving parts.

❓ FAQ

Q. What does this project do? It runs a WIZnet W5500 as a UDP echo server on an STM32F407 under FreeRTOS. When a UDP datagram arrives on port 1111, the firmware reads it and replies "answer_OK".

Q. What is the role of the WIZnet chip? The W5500 is a hardwired TCP/IP controller. It runs the network stack in hardware and the STM32 only drives it over SPI, so the MCU stays free for application tasks (a TCP/IP offload design).

Q. How is the receive handled? It is interrupt driven. The W5500 raises a socket receive interrupt, a FreeRTOS task wakes, reads the datagram with recvfrom, replies with sendto, and re-arms the interrupt, so there is no busy polling.

Q. What is the hardest part to replicate? Getting the SPI callback wiring and the socket interrupt mask right. The W5500 chip-select, byte, and burst callbacks must match your SPI setup, and the static IP must suit your network.

Q. How does it compare to a software stack like Mongoose or lwIP? Here the W5500 owns the TCP/IP stack, so RAM and CPU use stay low and timing is predictable. A software stack adds features but costs MCU resources; this project favors the lean hardware-socket path.


한국어 (Korean)

개요

이 프로젝트는 STM32F407에서 FreeRTOS 위에 WIZnet W5500을 UDP 서버로 구동하는, 코드까지 완성된 간결한 참고 예제입니다. STM32는 SPI로 W5500과 통신하고, W5500이 TCP/IP 스택을 하드웨어로 처리하며, FreeRTOS 태스크가 하드웨어 수신 인터럽트를 기다립니다. UDP 데이터그램이 도착하면 펌웨어가 이를 읽고 "answer_OK"로 응답합니다. 두 번째 태스크는 상태 LED를 깜빡입니다. 완성품이라기보다, W5500 ioLibrary를 RTOS 애플리케이션에 붙이는 깔끔한 출발점입니다.

STM32F407과 WIZnet W5500 UDP 서버: PC 클라이언트가 이더넷으로 W5500 하드웨어 소켓에, SPI로 FreeRTOS 구동 STM32F407에 연결 생성 다이어그램: PC → 이더넷 → W5500 하드웨어 소켓 → SPI → STM32F407.

시스템 구성

펌웨어는 STM32F407(STM32CubeMX 프로젝트, 168MHz)과 SPI1에 연결된 WIZnet W5500을 대상으로 합니다. SPI1은 마스터, 모드 0(CPOL low, CPHA 1edge), 소프트웨어 CS, /4 분주로 동작합니다. 네트워크 설정은 정적(IP·MAC·게이트웨이·마스크), UDP 서비스 포트는 1111, 단일 하드웨어 소켓을 논블로킹으로 사용합니다. 빌드는 Makefile 기반으로 표준 라이브러리·W5500 라이브러리·FreeRTOS를 분리합니다. scripts/udp의 파이썬 두 개가 테스트 피어 역할을 합니다. 네트워킹 코드는 WIZnet ioLibrary_Driver를 쓰고, FreeRTOS와 ST STM32F4 HAL이 함께 포함됩니다. W5500 부품은 Hardware Components 패널에 정리되어 있습니다.

시스템 구조와 데이터 흐름

데이터 경로는 짧고 결정적입니다. PC가 보드의 정적 IP, 포트 1111로 UDP 데이터그램을 보냅니다. 패킷은 이더넷으로 W5500에 도달하고, 하드웨어 TCP/IP 스택이 소켓 수신 버퍼에 저장한 뒤 수신 인터럽트를 올립니다. STM32F407은 SPI로 recvfrom을 통해 데이터그램을 읽고 sendto("answer_OK")로 응답합니다. W5500이 프로토콜 스택을 담당하므로 STM32는 SPI로 바이트만 옮기고 애플리케이션 로직만 돌립니다.

데이터 흐름: PC UDP 클라이언트 → 이더넷 → WIZnet W5500 하드웨어 소켓 → SPI1 → STM32F407+FreeRTOS가 응답 생성 다이어그램: PC에서 W5500을 거쳐 STM32F407로 가는 UDP 에코 경로.

STM32F407의 소프트웨어 스택

펌웨어는 계층이 명확합니다. 애플리케이션에는 두 FreeRTOS 태스크가 있습니다: 에코 서비스용 udp_task, 상태 LED용 led_task. FreeRTOS가 스케줄러와 논블로킹 타이밍을 제공합니다. WIZnet ioLibrary_Driver가 소켓 API(socket, sendto, recvfrom, ctlsocket, getSn_SR)를 제공하고, 얇은 W5500 SPI 드라이버가 CS·단일바이트·버스트 콜백을 reg_wizchip_*_cbfunc로 STM32 SPI에 연결합니다. 맨 아래는 8개 하드웨어 소켓·MAC·PHY·수신 인터럽트를 갖춘 W5500입니다.

소프트웨어 스택: 애플리케이션 태스크 → FreeRTOS → WIZnet ioLibrary → W5500 SPI 드라이버 → W5500 하드웨어 TCP/IP 칩 생성 다이어그램: 애플리케이션부터 W5500까지 다섯 계층.

WIZnet 칩의 역할

W5500 덕분에 펌웨어가 작게 유지됩니다. 하드와이어드 TCP/IP 컨트롤러라서 프로토콜 스택이 칩 내부에서 돌고 STM32F407은 SPI로 구동만 합니다. MCU가 lwIP나 Mongoose 같은 소프트웨어 스택에 사이클·RAM을 쓰지 않으니 애플리케이션 태스크에 여유가 생기고 타이밍이 예측 가능합니다. 이 하드웨어 오프로드가 이 설계를 TOE(TCP/IP 오프로드)로 만듭니다. 또한 RTOS에 맞게 칩이 수신 인터럽트를 올려, udp_task는 폴링 대신 실제 데이터그램이 올 때만 동작하므로 FreeRTOS 스케줄러에 친화적입니다.

인터럽트 기반 수신 루프

수신 경로는 인터럽트로 게이팅됩니다. setSIMRsetSn_IMR로 소켓 인터럽트 마스크를 설정하고 INT_RECV_ON으로 수신 인터럽트를 켭니다. W5500이 데이터그램을 받으면 소켓 인터럽트를 올리고, udp_taskrecvfrom으로 읽어 "answer_OK"를 보낸 뒤 인터럽트를 다시 켭니다. 소켓은 논블로킹으로 열려 있어, 태스크는 이벤트 사이에 vTaskDelay로 양보합니다.

인터럽트 수신 루프: W5500 수신 인터럽트 → 소켓 인터럽트 플래그 → 태스크 깨어남 → recvfrom → sendto answer_OK → 인터럽트 재무장 생성 다이어그램: FreeRTOS 태스크 안에서 처리되는 논블로킹·인터럽트 기반 UDP 에코.

활용 가치와 한계

많은 STM32 이더넷 프로젝트의 첫 마일스톤, 즉 W5500 링크를 올리고 소켓을 열어 RTOS에서 안정적으로 패킷을 주고받는 단계에 좋은 참고입니다. 인터럽트 기반 패턴과 깔끔한 SPI 콜백 배선은 이후 DHCP·TCP 서비스·MQTT를 더하는 더 큰 설계에서도 재사용할 수 있습니다. 다만 한계도 분명합니다. 저장소에 README와 프로젝트 라이선스가 없고, 주소는 정적(DHCP 없음)이며, UDP 에코는 완성 애플리케이션이 아니라 데모입니다. TCP 분기는 빌드 플래그로 가드되어 기본값이 아니고, 소켓 버퍼 크기 설정 호출은 주석 처리되어 기본 크기가 적용됩니다. 재사용 전에 핀맵·SPI 속도·네트워크 설정을 확인하세요.

관련 WIZnet 메이커 프로젝트

메이커 사이트에 있는 여러 STM32+W5500 예제 중 직접 비교하기 좋은 세 가지입니다.

STM32 W5500 TCP Server with FreeRTOS (논블로킹 멀티태스킹) (Grade A) - 가장 가까운 형제로, STM32 + W5500 + FreeRTOS + ioLibrary 조합과 논블로킹 소켓 설계를 공유합니다. 전송 방식과 이벤트 트리거가 다릅니다. 그 프로젝트는 TCP를 쓰고 폴링형 accept() 루프로 연결을 처리합니다. 이 프로젝트는 UDP(연결 없음, 핸드셰이크 오버헤드 없음)를 쓰고 W5500 수신 인터럽트를 설정해 데이터그램이 실제로 도착할 때만 udp_task가 깨어납니다. 인터럽트 방식은 패킷 사이에 SPI 버스를 폴링하지 않아 FreeRTOS 스케줄러에 더 친화적입니다.

STM32F446_W5500__FREERTOS (Grade A) - 동일한 STM32F4 + W5500 + FreeRTOS + ioLibrary 조합을 F407 대신 F446에서 구동하며 DHCP로 동적 주소 할당을 더합니다. 두 프로젝트는 ioLibrary+RTOS 통합의 좋은 출발점으로, 나란히 보면 같은 패턴이 STM32F4 계열 전반에서 동작한다는 것을 알 수 있습니다. 구체적인 차이: MCU 부품(F446 vs F407), 주소 방식(DHCP vs 이 프로젝트의 정적), 전송 방식(TCP vs 여기서 인터럽트 기반 UDP).

How to Implement Mongoose Networking Library on STM32F4 using W5500 (Grade A) - STM32F4 + W5500 위에 Mongoose 소프트웨어 네트워킹 라이브러리를 올려 HTTP·WebSocket·MQTT 지원을 추가합니다. 두 프로젝트 모두 STM32F4 + W5500으로 임베디드 이더넷을 구현합니다. 설계 철학이 다릅니다. Mongoose는 RAM·코드 크기를 프로토콜 풍부함과 맞바꾸고, 이 프로젝트는 W5500 ioLibrary 하드웨어 소켓을 직접 구동해 펌웨어를 작고 타이밍을 예측 가능하게 유지합니다. 둘을 비교하면 기능 풍부한 소프트웨어 스택과 가벼운 TOE 설계의 절충이 명확히 보입니다.

공통점은 STM32F4용 하드웨어 TCP/IP 컨트롤러로서의 WIZnet W5500입니다. 이 프로젝트는 그중 가장 미니멀한 인터럽트 기반 UDP 참고 예제로, setSIMR / setSn_IMR / INT_RECV_ON을 FreeRTOS 태스크에 연결하는 과정을 가장 적은 부품으로 보여줍니다.

자주 묻는 질문 (FAQ)

Q. 이 프로젝트는 무엇을 하나요? STM32F407에서 FreeRTOS 위에 WIZnet W5500을 UDP 에코 서버로 구동합니다. 포트 1111로 UDP 데이터그램이 오면 읽고 "answer_OK"로 응답합니다.

Q. WIZnet 칩의 역할은? W5500은 하드와이어드 TCP/IP 컨트롤러로, 네트워크 스택을 하드웨어에서 처리하고 STM32는 SPI로 구동만 하므로 MCU는 애플리케이션에 집중합니다(TOE 설계).

Q. 수신은 어떻게 처리하나요? 인터럽트 기반입니다. W5500이 소켓 수신 인터럽트를 올리면 FreeRTOS 태스크가 깨어 recvfrom으로 읽고 sendto로 응답한 뒤 인터럽트를 다시 켭니다. 바쁜 폴링이 없습니다.

Q. 재현이 가장 어려운 부분은? SPI 콜백 배선과 소켓 인터럽트 마스크 설정입니다. W5500 CS·바이트·버스트 콜백이 SPI 설정과 맞아야 하고, 정적 IP가 네트워크에 맞아야 합니다.

Q. Mongoose나 lwIP 같은 소프트웨어 스택과 비교하면? 여기서는 W5500이 TCP/IP 스택을 담당해 RAM·CPU 사용이 낮고 타이밍이 예측 가능합니다. 소프트웨어 스택은 기능이 많지만 MCU 자원을 쓰며, 이 프로젝트는 가벼운 하드웨어 소켓 경로를 택합니다.

Documents
  • Project repository

    STM32F407 + W5500 + FreeRTOS UDP server (source, Makefile, scripts)

  • UDP server source (net.c)

    W5500 socket init, interrupt-driven recvfrom/sendto, udp_task

  • WIZnet ioLibrary_Driver

    WIZnet socket API and W5500 driver used by the project

  • WIZnet W5500

    Hardwired TCP/IP Ethernet controller product page

  • FreeRTOS

    Real-time kernel running the udp_task and led_task

Comments Write