W5500 网络接口
引脚定义:
| 序号 | 名称 | 引脚号 |
|---|---|---|
| 1 | MISO | 2 |
| 2 | MOSI | 7 |
| 3 | CLK | 6 |
| 4 | CS | 10 |
| 5 | INT | 4 |
| 6 | RST | -1 |
ESP32_W5500 驱动示例
以下代码在使用时,要注意以下几点:
- 使用的 IDF版本是: 5.5.0 版本, 其他版本可能会有问题.
- 必须配置 idf.py menuconfig 配置 :
Component config > Ethernet -> Supper SPI to Ethernet Module > Use W5500.
驱动代码的步骤:
- 配置
SPI总线(这是启用硬件SPI)-->spi_bus_initialize SPI设备配置(这是为驱动w5500,设置SPI) -->ETH_W5500_DEFAULT_CONFIG- 创建
驱动实例,指定使用w5500作为驱动网络的设备 -->esp_eth_mac_new_w5500,esp_eth_phy_new_w5500 - 安装
以太网驱动-->esp_eth_driver_install - 配置mac地址
- 生成一个本地地址
- 设置以太网驱动实例的MAC地址 -->
esp_eth_ioctl
- 初始化
网络堆栈(这一步很关键) -->esp_netif_init,esp_netif_new,esp_netif_attach- 设置静态IP地址.
- 启动DHCP服务器()
注册事件处理器 -->esp_event_handler_register启动以太网 -->esp_eth_start获取IP地址-->esp_netif_get_ip_info
具体驱动代码(无静态IP版)
c
#include <stdio.h>
#include "esp_log.h"
#include "driver/spi_master.h"
#include "esp_eth.h"
#include "esp_mac.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_eth_mac_spi.h"
static const char *TAG = "W5500_Demo";
// SPI接口配置
#define SPI_HOST SPI2_HOST
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 7
#define PIN_NUM_CLK 6
// W5500配置
#define ETH_PIN_NUM_CS 10 // 片选引脚
#define ETH_PIN_NUM_RST -1 // 复位引脚
#define ETH_PIN_NUM_INT -1 // 中断引脚 4 禁用就设置为 -1
#define ETH_PHY_ADDR 1 // PHY地址,W5500固定为1
/* 事件处理函数 */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
switch (event_id)
{
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "Ethernet Link Up");
ESP_LOGI(TAG, "MAC: %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5]);
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "Ethernet Started");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "Ethernet Stopped");
break;
default:
break;
}
}
void app_main(void)
{
// 1. 配置SPI总线(这是启用硬件SPI)
spi_bus_config_t buscfg = {
.miso_io_num = PIN_NUM_MISO,
.mosi_io_num = PIN_NUM_MOSI,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4096 // 必须大于等于ETH_MAX_PACKET_SIZE
spi_bus_initialize(SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
// 2. SPI设备配置(这是为驱动w5500,设置SPI)
spi_device_interface_config_t devcfg = {
.mode = 0,
.clock_speed_hz = 16 * 1000 * 1000, // 必须≤20MHz
.spics_io_num = ETH_PIN_NUM_CS,
.queue_size = 20};
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(SPI_HOST, &devcfg);
w5500_config.int_gpio_num = ETH_PIN_NUM_INT; // 禁用中断
w5500_config.poll_period_ms = 100; // 每次轮询间隔
// 3. MAC配置,PHY配置(关键修改点)
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = ETH_PHY_ADDR; // 必须=1
phy_config.reset_gpio_num = ETH_PIN_NUM_RST; // 硬件复位
// 4. 创建驱动实例,指定使用w5500作为驱动网络的设备
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
// 5. 安装以太网驱动
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
esp_eth_driver_install(ð_config, ð_handle);
// 6.配置mac地址
uint8_t base_mac_addr[ETH_ADDR_LEN];
esp_efuse_mac_get_default(base_mac_addr);
uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr);
// 这里是生成一个本地mac地址
esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, local_mac_1);
// 7. 初始化网络堆栈(这一步很关键)
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&cfg);
esp_eth_netif_glue_handle_t eth_netif_glue = esp_eth_new_netif_glue(eth_handle);
esp_netif_attach(eth_netif, eth_netif_glue);
// 8.注册事件处理器
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL));//这二层的网络事件
// 9.启动以太网
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
// 10. 获取IP地址(DHCP),以下代码也可以不用写,因为操作系统内置了循环
// esp_netif_ip_info_t ip_info;
// while (1)
// {
// if (esp_netif_get_ip_info(eth_netif, &ip_info) == ESP_OK)
// {
// if (ip_info.ip.addr != 0)
// {
// ESP_LOGI(TAG, "IP Address: " IPSTR, IP2STR(&ip_info.ip));
// break;
// }
// }
// vTaskDelay(pdMS_TO_TICKS(1000));
// }
}如果要指定IP地址,需要修改的地方:
- 定义静态IP地址
- 在 eth_event_handler中的
ETHERNET_EVENT_CONNECTED事件中,指定静态IP地址 - 只要不在这里设置静态IP地址,则会自动获取DHCP分配的IP地址.
具体驱动代码(允许静态IP版)
c
#include <stdio.h>
#include "esp_log.h"
#include "driver/spi_master.h"
#include "esp_eth.h"
#include "esp_mac.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_eth_mac_spi.h"
static const char *TAG = "W5500_Demo";
// SPI接口配置
#define SPI_HOST SPI2_HOST
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 7
#define PIN_NUM_CLK 6
// W5500配置
#define ETH_PIN_NUM_CS 10 // 片选引脚
#define ETH_PIN_NUM_RST -1 // 复位引脚
#define ETH_PIN_NUM_INT -1 // 中断引脚 4 禁用就设置为 -1
#define ETH_PHY_ADDR 1 // PHY地址,W5500固定为1
// +++ 静态IP地址 +++
#define SET_STATIC_IP true
#define STATIC_IP ESP_IP4TOADDR(192, 168, 101, 100)
#define STATIC_NETMASK ESP_IP4TOADDR(255, 255, 255, 0)
#define STATIC_GW ESP_IP4TOADDR(192, 168, 101, 1)
/** 以太网事件的事件处理函数 */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
uint8_t mac_addr[6] = {0};
/* 我们可以从事件数据中获取以太网驱动句柄 */
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
esp_netif_t *eth_netif = esp_netif_get_handle_from_ifkey("ETH_DEF");
switch (event_id)
{
case ETHERNET_EVENT_CONNECTED:
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
ESP_LOGI(TAG, "以太网链路已连接");
ESP_LOGI(TAG, "以太网硬件地址 %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
// 如果设置静态IP,如果关闭静态IP,则会自动获取DHCP分配的IP
if (SET_STATIC_IP)
{
// +++ 新增静态IP配置 +++
esp_netif_dhcpc_stop(eth_netif); // 关闭DHCP客户端
esp_netif_ip_info_t ipv4_info = {
.ip.addr = STATIC_IP, // 设置IP地址
.netmask.addr = STATIC_NETMASK, // 子网掩码
.gw.addr = STATIC_GW // 网关
};
ESP_ERROR_CHECK(esp_netif_set_ip_info(eth_netif, &ipv4_info));
}
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "以太网链路已断开");
break;
case ETHERNET_EVENT_START:
ESP_LOGI(TAG, "以太网已启动");
break;
case ETHERNET_EVENT_STOP:
ESP_LOGI(TAG, "以太网已停止");
break;
default:
break;
}
}
/** IP_EVENT_ETH_GOT_IP事件的事件处理函数 */
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
const esp_netif_ip_info_t *ip_info = &event->ip_info;
ESP_LOGI(TAG, "以太网已获取IP地址");
ESP_LOGI(TAG, "~~~~~~~~~~~");
ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip));
ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw));
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
void app_main(void)
{
// 1. 配置SPI总线(这是启用硬件SPI)
spi_bus_config_t buscfg = {
.miso_io_num = PIN_NUM_MISO,
.mosi_io_num = PIN_NUM_MOSI,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4096 // 必须大于等于ETH_MAX_PACKET_SIZE
};
spi_bus_initialize(SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
// 2. SPI设备配置(这是为驱动w5500,设置SPI)
spi_device_interface_config_t devcfg = {
.mode = 0,
.clock_speed_hz = 16 * 1000 * 1000, // 必须≤20MHz
.spics_io_num = ETH_PIN_NUM_CS,
.queue_size = 20};
// 3. W5500驱动专用配置
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(SPI_HOST, &devcfg);
w5500_config.int_gpio_num = ETH_PIN_NUM_INT; // 禁用中断
w5500_config.poll_period_ms = 100; // 每次轮询间隔
// 4. MAC配置,PHY配置(关键修改点)
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = ETH_PHY_ADDR; // 必须=1
phy_config.reset_gpio_num = ETH_PIN_NUM_RST; // 硬件复位
// 5. 创建驱动实例,指定使用w5500作为驱动网络的设备
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
// 6. 安装以太网驱动
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy);
esp_eth_handle_t eth_handle = NULL;
esp_eth_driver_install(ð_config, ð_handle);
// 7.配置mac地址
uint8_t base_mac_addr[ETH_ADDR_LEN];
esp_efuse_mac_get_default(base_mac_addr);
uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr);
// 这里是生成一个本地mac地址
esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, local_mac_1);
// 8. 初始化网络堆栈(这一步很关键)
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&cfg);
esp_eth_netif_glue_handle_t eth_netif_glue = esp_eth_new_netif_glue(eth_handle);
esp_netif_attach(eth_netif, eth_netif_glue);
// 9.注册事件处理器
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL));
// 10.启动以太网
ESP_ERROR_CHECK(esp_eth_start(eth_handle));
// 11. 获取IP地址,以下代码也可以不用写,因为操作系统内置了循环
// esp_netif_ip_info_t ip_info;
// while (1)
// {
// if (esp_netif_get_ip_info(eth_netif, &ip_info) == ESP_OK)
// {
// if (ip_info.ip.addr != 0)
// {
// ESP_LOGI(TAG, "IP Address: " IPSTR, IP2STR(&ip_info.ip));
// break;
// }
// }
// vTaskDelay(pdMS_TO_TICKS(1000));
// }
}