---
title: "grblhal-RP2040"
url: "https://maker.wiznet.io/TheoIm/projects/grblhal-rp2040-1/"
markdown_url: "https://maker.wiznet.io/TheoIm/projects/grblhal-rp2040-1/md"
type: "UCC: User Created Content"
author: "batman-ua"
author_url: "https://github.com/batman-ua/grblhal-RP2040"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "batman-ua"
original_url: "https://github.com/batman-ua/grblhal-RP2040"
published: "2026-03-20"
language: "en"
hardware: ["WIZnet W5500", "Raspberry Pi RP2040"]
likes: 0
views: 335
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# grblhal-RP2040

> Explains an RP2040-based CNC controller using W5500 to offload TCP/IP, enabling deterministic real-time control and stable network communication without jitter.

Original author: batman-ua (source: https://github.com/batman-ua/grblhal-RP2040)

## Components

- **WIZnet W5500** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))
- **Raspberry Pi RP2040** x 1 ([docs](https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html))

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Article

## What the Project Does

This is a **network-enabled CNC controller firmware** built on RP2040.

It allows a CNC machine to be controlled remotely through:

Telnet (command-line control)

WebSocket (real-time UI)

HTTP (web interface)

FTP (file transfer)

MQTT (optional integration)

### System Structure (Simplified)

![](https://maker.wiznet.io/upload/ckeditor5/578274999%5F1774020965%2Epng)

Generated By Gemini

```plaintext
Host PC / Web UI
        ↓
   TCP (Telnet / HTTP / WebSocket)
        ↓
        lwIP
        ↓
 ┌───────────────┬──────────────────┐
 │ Wi-Fi (CYW43) │ Ethernet (W5500)                                                                         │
 └───────────────┴──────────────────┘
        ↓
     RP2040
```

The key design decision:

> The networking layer is **modular and replaceable**, while the application layer remains unchanged.

---

## Where WIZnet Fits

The system explicitly supports **WIZnet W5500 / W5100S** as an alternative to Wi-Fi.

### Role of W5500 in this architecture

Acts as a **hardware TCP/IP engine over SPI**

Handles:

packet transmission

retransmission

checksum

socket buffering

Exposes a **register-based socket interface** to the MCU

### Why this matters for CNC

CNC control requires:

precise timing

no jitter

predictable loop execution

W5500 ensures:

networking does not interrupt motion control

CPU cycles remain dedicated to step generation and control logic

---

## Implementation Notes

### 1) Build-Time Network Selection (Critical Design)

**File**: `driver.h`

```plaintext
#if ETHERNET_ENABLE && WIFI_ENABLE
#error "WiFi and Ethernet cannot be enabled at the same time!"
#endif
```

**What this does:**

Prevents dual-stack conflicts

Forces a **clean architecture boundaryWhy it matters:**

Avoids runtime instability

Keeps memory usage predictable

---

### 2) WIZnet Driver Integration via CMake

**File**: `CMakeLists.txt`

```plaintext
if(ADD_ETHERNET)
    target_compile_definitions(grblHAL PUBLIC ETHERNET_ENABLE=1)
    target_compile_definitions(grblHAL PUBLIC CYW43_LWIP=0)
    include(networking/wiznet/CMakeLists.txt)
    target_sources(grblHAL PRIVATE w5x00_ll_driver.c)
endif()
```

**Key insight:**

Wi-Fi lwIP is explicitly disabled

WIZnet path uses its **own driver + lwIP instance**

---

### 3) Low-Level Driver (W5500 / W5100S Switch)

**File**: `w5x00_ll_driver.c`

```plaintext
#if _WIZCHIP_ == W5500
#include "W5500/w5500.h"
#elif _WIZCHIP_ == W5100S
#include "W5100S/w5100s.h"
#endif
```

**What this enables:**

Same codebase supports multiple WIZnet chips

Selection via compile-time macro

---

### 4) SPI Bus Control with Dynamic Frequency Switching

```plaintext
static void wizchip_select(void)
{
    if(spi_freq != WIZCHIP_SPI_FREQ)
        spi_set_speed(WIZCHIP_SPI_FREQ);

    DIGITAL_OUT(hw.cs, 0);
}
```

```plaintext
static void wizchip_deselect(void)
{
    DIGITAL_OUT(hw.cs, 1);

    if(spi_freq != WIZCHIP_SPI_FREQ)
        spi_set_speed(spi_freq);
}
```

**Why this exists:**

SPI bus is shared (e.g., SD card)

W5500 runs at ~33 MHz

Other devices may require slower speeds

**Result:**

Safe multi-device SPI architecture

---

### 5) Hardware Initialization + ioLibrary Pattern

reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
reg_wizchip_spi_cbfunc(spi_get_byte, spi_put_byte);

**What this means:**

Standard WIZnet ioLibrary integration

Abstracts hardware access cleanly

---

### 6) Socket Memory Allocation Strategy

```plaintext
uint8_t memsize[2][8] = {
    {8,0,0,0,0,0,0,0},
    {8,0,0,0,0,0,0,0}
};
```

**Interpretation:**

All 8KB assigned to socket 0

**Why:**

CNC controller uses **single dominant connection**

Prevents buffer fragmentation

Improves throughput stability

---

### 7) Interrupt-Based Packet Reception (Key Optimization)

```plaintext
ctlsocket(socket, CS_SET_INTMASK, (void *)&reg_val);
ctlwizchip(CW_SET_INTRMASK, (void *)&reg_val);
```

**What happens:**

W5500 asserts `/INT` pin on packet arrival

RP2040 IRQ handler processes it

**Why this is critical:**

No polling loops

No wasted CPU cycles

Deterministic behavior

---

### 8) DMA-Based SPI Transfers

**File**: `spi.c`

```plaintext
dma_channel_configure(dma_tx.channel, ...);
dma_channel_configure(dma_rx.channel, ...);
dma_start_channel_mask(...);
```

**Behavior:**

Large transfers use DMA

CPU is not involved during transfer

**Impact:**

CNC motion loop remains uninterrupted

High throughput without CPU penalty

---

### 9) lwIP Configuration (No RTOS)

**File**: `lwipopts.h`

```plaintext
#define NO_SYS 1
#define MEM_SIZE (32*1024)
#define TCP_WND (8 * TCP_MSS)
```

**Key design:**

No RTOS → polling-based main loop

Large TCP window → better file transfer performance

---

### 10) Service Layer Auto-Start

```plaintext
services.telnet = telnetd_init(network.telnet_port);
services.websocket = websocketd_init(network.websocket_port);
services.http = httpd_init(network.http_port);
```

**Meaning:**

When link is up → all services start automatically

Same stack reused across all protocols

---

## Practical Tips / Pitfalls

Do not enable Wi-Fi and Ethernet together (compile-time enforced)

Use **INT pin** for efficient packet handling (avoid polling)

Ensure SPI clock compatibility when sharing bus

Allocate socket memory based on actual connection pattern

Use DMA for large SPI transfers to avoid CPU blocking

Keep lwIP tuning aligned with application (e.g., TCP window size)

---

## FAQ

**Q: Why use W5500 instead of Wi-Fi in this system?**
A: CNC control requires deterministic timing. W5500 removes TCP/IP processing from the MCU, eliminating jitter caused by Wi-Fi stacks and interrupts.

---

**Q: How is W5500 connected to RP2040?**
A: Through SPI with optional interrupt pin. SPI can run up to ~33 MHz and supports DMA for high-throughput transfers.

---

**Q: What role does W5500 play in this project?**
A: It acts as the network transport engine, handling all Ethernet communication while exposing socket-level access to lwIP and application services.

---

**Q: Can beginners use this project?**
A: It is not beginner-level. You need understanding of embedded C, SPI, DMA, and networking stacks like lwIP.

---

**Q: How does this compare to using only lwIP with a software MAC/PHY?**
A: Software stacks consume CPU cycles and introduce jitter. W5500 offloads this work, making it better suited for real-time systems like CNC controllers.

---

## Source

Project: grblHAL RP2040 networking implementation

Key files:

`networking/wiznet/w5x00_ll_driver.c`

`networking/wiznet/CMakeLists.txt`

`driver.h`

`spi.c`

`lwipopts.h`

---

## Tags

#W5500 #W5100S #RP2040 #grblHAL #CNC #Ethernet #SPI #DMA #lwIP #EmbeddedSystems

---

Source: https://maker.wiznet.io/TheoIm/projects/grblhal-rp2040-1/
