---
title: "[ESP32-S3] Geekble Nano W6300 QSPI Porting"
url: "https://maker.wiznet.io/Lihan__/projects/esp32-s3-geekble-nano-w6300-qspi-porting/"
markdown_url: "https://maker.wiznet.io/Lihan__/projects/esp32-s3-geekble-nano-w6300-qspi-porting/md"
type: "WCC: WIZnet Created Content"
author: "Lihan__"
author_url: "https://maker.wiznet.io/Lihan__/"
original_author: "Lihan"
published: "2025-11-14"
language: "en"
hardware: ["Espressif ESP32S"]
likes: 1
views: 984
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# [ESP32-S3] Geekble Nano W6300 QSPI Porting

> This content summarizes the process of configuring QSPI between the ESP32-S3 and W6300, analyzing waveforms, reading registers, and completing a loopback test.

Original author: Lihan

## Components

- **Espressif ESP32S** x 1 ([docs](https://www.espressif.com/en/products/socs/esp32))

## Documents and links

- [ESP32-W6300-Ethernet](https://github.com/seok930927/ESP32-W6300-Ethernet) (code)

## Article

## Overview

We aim to port the W6300 to the ESP32, provide a reference implementation for ESP32 users, and evaluate performance running on an RTOS.

## Hardware Description

- **Geekble nano**

![Geekble nano Pin...](https://i.namu.wiki/i/7b082FI7HNb9yVaJj8X84SmG-FUH1NjRkYMvxWuKBv4YQZ1vcXC_Hq6yzAj9tF_ajwlxBM1jZ-a-yqIwxLD2LR7PmzpxuD9aqsE-5ZA1Ikj_2CI4RzNt0awZYLjeZvZXlR6Z9b3-zs_jtAXx1OQeDw.webp)

The Geekble Nano is a compact ESP32-S3 development board designed for easy prototyping.
It provides dual-core performance, built-in USB, plenty of GPIO pins, and support for Arduino, MicroPython, and ESP-IDF.
It’s small, powerful, and ideal for IoT projects.

- **WIZ630io**

![](https://docs.wiznet.io/img/products/wiz630io/WIZ630io_Front_side_view.png)

The WIZ630io is an Ethernet module based on the W6300 hardware TCP/IP chipset.
It offers stable 10/100Mbps Ethernet, built-in RJ45, and supports SPI/QSPI for fast communication with MCUs.
It makes adding wired networking simple and reliable.

## PIN config

```plaintext
#define SPI_D0_PIN      47   // DATA0 (기존 MOSI)
#define SPI_D1_PIN      38   // DATA1 (기존 MISO)  
#define SPI_D2_PIN      21   // DATA2 (WP) - 새로 추가
#define SPI_D3_PIN      18   // DATA3 (HD) - 새로 추가

#define SPI_CLK_PIN     17   // CLK
#define SPI_CS_PIN      10   // CS
```

## QSPI config

```plaintext
 spi_device_handle_t spi_dev2;

    // SPI 버스 설정
    spi_bus_config_t buscfg = {
        .sclk_io_num = SPI_CLK_PIN,      // CLK
        
        .data0_io_num = SPI_D0_PIN,      // DATA0 (MOSI와 동일)
        .data1_io_num = SPI_D1_PIN,      // DATA1 (MISO와 동일)
        .data2_io_num = SPI_D2_PIN,      // DATA2 (WP)
        .data3_io_num = SPI_D3_PIN,      // DATA3 (HD)
        .data4_io_num = -1,              // OCTAL 모드용 (사용 안함)
        .data5_io_num = -1,              // OCTAL 모드용 (사용 안함)
        .data6_io_num = -1,              // OCTAL 모드용 (사용 안함)
        .data7_io_num = -1,              // OCTAL 모드용 (사용 안함)
        .max_transfer_sz = 4096,
        .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_QUAD,  // QUAD 모드 활성화
  
    };
    
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 10000000,      // 10MHz (QSPI는 더 빠르게 가능)
        .mode = 0,                       // SPI mode 0
        .spics_io_num = SPI_CS_PIN,
        .queue_size = 1,
        .flags = SPI_DEVICE_HALFDUPLEX,  // QSPI는 일반적으로 half-duplex
    };

  // SPI 버스 초기화 (DMA 비활성화로 시작)
    ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_DISABLED);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPI bus init failed: %s", esp_err_to_name(ret));
        return;
    }
    
    ESP_LOGI(TAG, "QSPI bus initialized successfully");
    
    // SPI 디바이스 추가
    ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi_dev2);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "SPI device add failed: %s", esp_err_to_name(ret));
        return;
    }
```

### How to write data via SPI instance

```plaintext
 void qspi_write_data(uint8_t cmd , uint16_t addr, uint8_t *data, size_t len){
    esp_err_t ret;

    static uint8_t full_buffer[16];
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));
    t.length =  len * 8 ;
    t.addr = addr;
    t.cmd = cmd | 0x20;
    t.tx_buffer = data ;
    t.rx_buffer = NULL;
    t.rxlength = 0;
    t.flags = SPI_TRANS_MODE_QIO  | SPI_TRANS_MULTILINE_ADDR    ;
    
     ret = spi_device_transmit(spi_dev, &t);
}

void qspi_read_data(uint8_t cmd , uint16_t addr, uint8_t *data, size_t len){
    esp_err_t ret;

    static uint8_t full_buffer[16];
    spi_transaction_t t;

    memset(&t, 0, sizeof(t));
    t.length = 0 ;
    t.addr = addr;
    t.cmd = cmd;
    t.tx_buffer = NULL ;
    t.rx_buffer = data ;
    t.rxlength = len * 8;
    t.flags = SPI_TRANS_MODE_QIO  | SPI_TRANS_MULTILINE_ADDR    ;
    ret = spi_device_transmit(spi_dev, &t);
}
```

The transaction is constructed by declaring a `spi_transaction_t` structure, setting the required `cmd` and `address` fields, and sending it using `spi_device_transmit()`.

## TEST signal

![image](https://private-user-images.githubusercontent.com/34390400/507943632-735e9567-f754-4a15-b9d4-a34d0c97e189.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjMxMDEzMjUsIm5iZiI6MTc2MzEwMTAyNSwicGF0aCI6Ii8zNDM5MDQwMC81MDc5NDM2MzItNzM1ZTk1NjctZjc1NC00YTE1LWI5ZDQtYTM0ZDBjOTdlMTg5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTExMTQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUxMTE0VDA2MTcwNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWJiZGU3MTM5NzdlN2ZhZDAwYTU5Yzk3YjQyODE3OTU4MTA3MGFlNDRhNTg1MjU3MGJhZWY3MjE0ZDYyYjc1MDUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.FuJLccQi-NRZHQAfY3N3nRJ3Jgm20qV1ceBLns1RCUg)

## QSPI Read at Address 0x0000 – Waveform Analysis

This is the QSPI waveform for reading from address **0x0000**.
The first section shows the **CMD 0x80**, which issues a Quad-Read command.
The next section is the **address phase**, where **0x0000** is sent.
After the address, **dummy clocks** follow, and in the final section, the actual data **0x61** is output.

In short: **CMD (0x80) → ADDR (0x0000) → Dummy → DATA (0x61)**.

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

## setup Network info

![image](https://private-user-images.githubusercontent.com/34390400/509857461-3fbc7269-d391-41b6-99ef-f55dc420c126.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjMxMDE5MzYsIm5iZiI6MTc2MzEwMTYzNiwicGF0aCI6Ii8zNDM5MDQwMC81MDk4NTc0NjEtM2ZiYzcyNjktZDM5MS00MWI2LTk5ZWYtZjU1ZGM0MjBjMTI2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTExMTQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUxMTE0VDA2MjcxNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTdlYzM0ODFmOTJhNzE5ZjkzYmMxN2I5ZGY4YjJkZTM5NWQ1YzZiZjg5MTgzNGZmNGFkNmMzMDNmMTRjYTEwOWYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.IclgGUJncbMpDAZ9g08TIG8ApEJpwZcZvAvJK6mygvM)

### loopback TEST (qspi CLK - 50Mhz)

<https://github.com/seok930927/ESP32-W6300-Ethernet/blob/main/README.md#loopback-test-qspi-clk---50mhz>

![image](https://private-user-images.githubusercontent.com/34390400/509858490-8d2f05c9-7ad0-4593-9ffe-725ef8428f54.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NjMxMDE5MzYsIm5iZiI6MTc2MzEwMTYzNiwicGF0aCI6Ii8zNDM5MDQwMC81MDk4NTg0OTAtOGQyZjA1YzktN2FkMC00NTkzLTlmZmUtNzI1ZWY4NDI4ZjU0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTExMTQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUxMTE0VDA2MjcxNlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWYwMzJkZTlkMWZlYzhiMDY5YmRiNTQyMTMwMTViMmUxZGI5M2YwZGNlY2M0NmZiYTM3ZmJkZDFmMmNlMWZjOTYmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.Zu99_R0IIiPC4VYPiXE5wI51QYOnpvcBcVob3aFAYDA)

---

Source: https://maker.wiznet.io/Lihan__/projects/esp32-s3-geekble-nano-w6300-qspi-porting/
