这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【瑞萨RA8D1测评】4、基于zephyr以太网(LAN8720A,RMII)Z

共2条 1/1 1 跳转至

【瑞萨RA8D1测评】4、基于zephyr以太网(LAN8720A,RMII)Zephyr移植

高工
2026-09-18 12:00:30     打赏

以太网(LAN8720A,RMII)Zephyr 移植记录

目标平台:CPKCOR-RA8D1B + CPKEXP-EKRA8X1,Zephyr 4.4.0。

 成果:DHCP 自动获取 IP(实测 192.168.3.4),RTT shell 可 net ping 通网关,IP 同步显示在 LCD 上。

网络链路

应用(socket / net shell)
  → Zephyr 原生 TCP/IP 栈(net_if / IPv4 / DHCPv4)
  → ETHERC + EDMAC(eth,renesas,ra-ethernet)     老式控制器,非 RA8x2 的 RMAC
  → MDIO/PHY 子系统(mdio,renesas,ra-mdio + ethernet-phy)
  → LAN8720AI PHY(RMII,百兆)
  • SoC dtsi(zephyr/dts/arm/renesas/ra/ra8/ra8x1.dtsi)已定义 eth(0x40354100)与mdio 节点,均 disabled,phy-connection-type = "rmii" 已默认。

  • 驱动:zephyr/drivers/ethernet/eth_renesas_ra.c(FSP r_ether)。注意不是 eth_renesas_ra_rmac——RMAC 属于 RA8x2 系列(ra8x2.dtsi),RA8D1 不适用。

  • pinctrl 挂在 mdio 节点上(binding 强制要求),eth 节点只需phy-handle + local-mac-address + status。

关键参数(均已真机验证)

RMII 引脚("_B" 组,与 ek_ra8m1 完全一致)

信号引脚信号引脚





MDCP401TXD0P700
MDIOP402REF50CK(输入)P701
LINKSTAP403RXD0P702
TX_ENP405RXD1P703
TXD1P406RX_ER / CRS_DVP704 / P705

pinctrl 分组照抄 ek_ra8m1-pinctrl.dtsi 的 ether_default(RA_PSEL_ETH_RMII, drive-strength = high),引脚与 CPKEXP 原理图逐网核对一致。

PHY

项值



芯片LAN8720AI(PHY ID 0x7C0F1)
MDIO 地址0(PHYAD0 默认内部下拉)
nRSTP510,扩展板外接下拉,固件必须拉高(见坑 1)
REFCLKPHY 侧 25MHz 晶振倍频出 50MHz,经跳线送 P701(REFCLKO 模式)
复位时序reset-gpios 拉低 1ms,释放后等 100ms 再走 MDIO 软复位

硬件前提(跳线)

  • 拔下 CEU 摄像头模组(RMII 与 CEU 管脚复用,使用 SDRAM 时二选一)

  • 接好扩展板上全部 10 个 RMII 跳线(RXD1/RXD0/RXER/RXDV/MDIO/MDC/REFCLK/TXEN/TXD0/TXD1),含 REFCLK-P701——"断开 REFCLK" 是 CEU 摄像头场景的要求,用以太网时恰恰相反

  • image.png

overlay 配置(boards/cpkcor_ra8d1b.overlay)

&ioport5 {
    status = "okay";  /* P510 = PHY nRST 用,不开会编译报 __device_dts_ord 错误 */
};

&eth {
    local-mac-address = [02 00 00 00 00 01];  /* LAA 本地管理地址 */
    phy-handle = <&phy>;
    status = "okay";
};

&mdio {
    pinctrl-0 = <&ether_default>;
    pinctrl-names = "default";
    status = "okay";

    phy: ethernet-phy@0 {
        compatible = "ethernet-phy";
        reg = <0>;
        reset-gpios = <&ioport5 10 GPIO_ACTIVE_LOW>;
        reset-assert-duration-us = <1000>;
        reset-deassertion-timeout-ms = <100>;
        status = "okay";
    };
};
/* + &pinctrl 里的 ether_default 分组(见上表,照抄 ek_ra8m1) */

prj.conf 关键项

CONFIG_NETWORKING=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_MDIO=y
# 初始化顺序:MDIO(50) < PHY(55) < eth 驱动(默认 60),否则 check_init_priorities 报错
CONFIG_MDIO_INIT_PRIORITY=50
CONFIG_PHY_INIT_PRIORITY=55
CONFIG_ENTROPY_GENERATOR=y      # DHCP 需要随机数(板 dts 已 chosen trng)
CONFIG_NET_IPV4=y / ARP / UDP / TCP, CONFIG_NET_IPV6=n
CONFIG_NET_DHCPV4=y
CONFIG_NET_MGMT=y / NET_MGMT_EVENT=y / NET_SHELL=y / NET_LOG=y

应用侧:DHCP 不会自动启动,必须显式调用(参照 samples/net/dhcpv4_client):

net_dhcpv4_start(net_if_get_default());

拿到地址用 net_mgmt 订阅 NET_EVENT_IPV4_ADDR_ADD 事件获知(回调签名第二参数 Zephyr 4.4 起为 uint64_t)。

主代码main.c

/*
 * CPKCOR-RA8D1B + CPKEXP-EKRA8X1:LVGL 显示演示 + LED 心跳
 *
 * 硬件连接:
 *   - LCD:H0233S001 模组(222x480,ST7796U 驱动 IC),MIPI-DSI 接口
 *     (专用 D-PHY 引脚,1 lane video mode),显示链路为
 *     GLCDC -> MIPI-DSI host -> ST7796U
 *   - LCD 复位:P000(低有效,panel 驱动管理)
 *   - LCD 背光:P001(高有效,GLCDC 节点 backlight-gpios 管理)
 *   - 显存:SDRAM(0x68000000),GLCDC 帧缓冲行步长 64 字节对齐为 224px;
 *     LVGL 渲染 buffer 为静态分配(10% 屏大小),flush 后经 GLCDC 驱动
 *     逐行 memcpy 进对齐显存
 *   - 用户 LED1:PA01(绿色,高电平点亮)
 *   - 以太网:扩展板 LAN8720AI PHY(RMII 百兆,"_B" 组引脚 P401/P402/
 *     P405/P406/P700~P705),Zephyr 原生 TCP/IP 栈,DHCP 自动获取 IP;
 *     RMII 与 CEU 摄像头管脚复用,使用时须拔下摄像头并改跳线
 *
 * UI 内容:标题 + RGB 三色块(验证颜色通道) + 进度条动画 + DHCP 获取的
 * IP 地址显示;每 500ms 翻转 LED 并打印心跳(含 DSI host 状态检查)。
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/net_event.h>
#include <zephyr/net/net_ip.h>
#include <zephyr/net/dhcpv4.h>
#include <lvgl.h>

/* 诊断:MIPI DSI host 状态寄存器(基址 0x40346000)
 * LINKSR(0x10):bit8 VRUN = 视频模式运行中
 * VMSR(0x410):bit22 VBUFUDF = 视频 FIFO 下溢,bit23 VBUFOVF = 上溢 */
#define DSI_LINKSR (*(volatile uint32_t *)0x40346010UL)
#define DSI_VMSR   (*(volatile uint32_t *)0x40346410UL)
#define DSI_VMSCR  (*(volatile uint32_t *)0x40346414UL)

#define LED_PERIOD_MS 500

static const struct device *display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);

static lv_obj_t *bar;
static lv_obj_t *count_label;
static lv_obj_t *ip_label;

/* DHCP/IPv4 地址就绪标志与字符串(网络事件回调置位,主循环刷 UI) */
static volatile bool ip_ready;
static char ip_str[NET_IPV4_ADDR_LEN] = "waiting DHCP...";

static struct net_mgmt_event_callback ip_cb;

/* IPv4 地址添加(DHCP 成功)回调:只取地址置标志,不碰 LVGL */
static void ipv4_addr_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event,
                  struct net_if *iface)
{
    struct in_addr *addr;

    if (mgmt_event != NET_EVENT_IPV4_ADDR_ADD) {
        return;
    }

    addr = net_if_ipv4_get_global_addr(iface, NET_ADDR_PREFERRED);
    if (addr == NULL) {
        return;
    }

    net_addr_ntop(AF_INET, addr, ip_str, sizeof(ip_str));
    ip_ready = true;
    printk("DHCP got IPv4 addr: %s\n", ip_str);
}

/* RGB 三色块,验证颜色通道是否正确(BGR/MADCTL 配置) */
static void create_color_swatch(lv_obj_t *parent, lv_color_t color, lv_coord_t x)
{
    lv_obj_t *rect = lv_obj_create(parent);

    lv_obj_set_size(rect, 60, 40);
    lv_obj_set_pos(rect, x, 60);
    lv_obj_set_style_bg_color(rect, color, 0);
    lv_obj_set_style_border_width(rect, 0, 0);
    lv_obj_set_style_radius(rect, 4, 0);
}

static void ui_init(void)
{
    lv_obj_t *scr = lv_screen_active();
    lv_obj_t *title;

    title = lv_label_create(scr);
    lv_label_set_text(title, "CPK-RA8D1 LVGL");
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 10);

    create_color_swatch(scr, lv_color_hex(0xFF0000), 6);
    create_color_swatch(scr, lv_color_hex(0x00FF00), 81);
    create_color_swatch(scr, lv_color_hex(0x0000FF), 156);

    bar = lv_bar_create(scr);
    lv_obj_set_size(bar, 190, 16);
    lv_obj_align(bar, LV_ALIGN_TOP_MID, 0, 130);
    lv_bar_set_range(bar, 0, 100);

    count_label = lv_label_create(scr);
    lv_label_set_text(count_label, "count: 0");
    lv_obj_align(count_label, LV_ALIGN_TOP_MID, 0, 160);

    ip_label = lv_label_create(scr);
    lv_label_set_text(ip_label, ip_str);
    lv_obj_align(ip_label, LV_ALIGN_TOP_MID, 0, 190);
}

int main(void)
{
    uint32_t count = 0;
    int ret;

    if (!device_is_ready(display_dev)) {
        printk("display device not ready\n");
        return 0;
    }

    if (gpio_is_ready_dt(&led)) {
        ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
        if (ret != 0) {
            printk("led0 cfg failed ret=%d\n", ret);
        }
    }

    display_blanking_off(display_dev);

    /* 订阅 IPv4 地址事件;显式启动 DHCP 客户端(参照 dhcpv4_client 例程) */
    net_mgmt_init_event_callback(&ip_cb, ipv4_addr_handler, NET_EVENT_IPV4_ADDR_ADD);
    net_mgmt_add_event_callback(&ip_cb);
    net_dhcpv4_start(net_if_get_default());

    ui_init();
    printk("ra8d1_blink lvgl demo start\n");

    while (1) {
        /* LVGL 任务处理 */
        lv_bar_set_value(bar, (count / 2) % 101, LV_ANIM_ON);
        lv_label_set_text_fmt(count_label, "count: %u", count);
        if (ip_ready) {
            lv_label_set_text(ip_label, ip_str);
            ip_ready = false;
        }
        lv_timer_handler();

        gpio_pin_toggle_dt(&led);
        ++count;

        /* DSI host 状态检查:异常时打印 */
        uint32_t vmsr = DSI_VMSR;

        if (vmsr & (BIT(20) | BIT(22) | BIT(23))) {
            printk("dsi vmsr=%08lx%s%s%s\n", (unsigned long)vmsr,
                   (vmsr & BIT(20)) ? " TIMERR" : "",
                   (vmsr & BIT(22)) ? " VBUFUDF" : "",
                   (vmsr & BIT(23)) ? " VBUFOVF" : "");
            DSI_VMSCR = vmsr;
        }

        k_msleep(LED_PERIOD_MS);
    }

    return 0;
}

踩坑记录

1. PHY 完全无应答:phy_mii: Failed to reset PHY (x): -116

根因:扩展板把 PHY 的 nRST(P510)外接下拉电阻——出厂缺省(CEU 摄像头模式) PHY 一直被硬件复位,MDIO 自然无任何响应,换哪个地址(0/1)都一样超时(-116 = ETIMEDOUT)。解决:PHY 节点加 reset-gpios(phy_mii 驱动支持,先硬复位脉冲再软复位),并启用ioport5。LAN8720 的 RXER/PHYAD0 默认下拉,地址就是 0,不用猜。

2. 链路正常但永远拿不到 IP

现象:link up 100Mb 全双工,但无任何 dhcpv4 日志。根因:Zephyr 的 DHCPv4 客户端 不会随接口 up 自动首次启动(首次启动由 net_config 库或应用负责),只配置了CONFIG_NET_DHCPV4=y 没人调用 start。解决:应用里显式 net_dhcpv4_start()。 排障手段:CONFIG_NET_DHCPV4_LOG_LEVEL_DBG=y + CONFIG_ETHERNET_LOG_LEVEL_DBG=y能清楚看到 DISCOVER/OFFER 交互,定位完记得关掉。 (附:D-Cache 不是问题,本板 CONFIG_DCACHE 默认未开。)

3. 设备初始化优先级校验失败

ERROR: /soc/ethernet@40354100 is initialized before its dependency ethernet-phy@0。 eth/MDIO/PHY 三者 *_INIT_PRIORITY 默认都是 60,链接顺序不保证依赖顺序。解决:MDIO=50 < PHY=55 < eth(60)。

4. uart3 虚拟串口无输出

板 dts 控制台是 uart3(SCI3,P409),文档称经 R207/R208 接 J-Link OB 的 USB CDC, 但实测 COM 口(COM44)无任何数据(复位抓 boot banner 也没有),原因未查。解决:按项目惯例控制台走 RTT——CONFIG_USE_SEGGER_RTT=y、CONFIG_RTT_CONSOLE=y、CONFIG_UART_CONSOLE=n。RTT Viewer 连接参数:device R7FA8D1BH,SWD; 控制块地址 0x22000410(自动搜索一般能找到)。

5. RTT shell 与 LOG_BACKEND_RTT 冲突

shell 切 RTT(CONFIG_SHELL_BACKEND_RTT=y)后编译报static assertion failed: Conflicting log RTT backend enabled on the same channel。 shell RTT 与 LOG_BACKEND_RTT 不能同用 RTT 通道 0。解决:关掉 LOG_BACKEND_RTT,日志改走 shell 后端(CONFIG_SHELL_LOG_BACKEND=y), 日志和 shell 命令在同一个 RTT 终端里输出,互不影响。

6. DHCP 日志里的 "option unknown" 不是错误

option unknown: 6(DNS 服务器)/ 213(厂商选项)只是 DBG 提示解析器不处理这些 选项,IP/掩码/网关/租期均正常。需要 DHCP 下发 DNS 时再开 CONFIG_DNS_RESOLVER 相关选项。

验证方法

  1. west build -b cpkcor_ra8d1b app/ra8d1_blink + west flash

  2. RTT Viewer 看启动日志:phy_mii: PHY (0) ID 7C0F1 → Link speed 100 Mb, full duplex→ DHCP got IPv4 addr: ...

  3. shell(同一 RTT 终端):net iface / net ping 192.168.3.1

image.png

image.png

4. 从 PC ping <板子IP> 反向验证

image.png

5. 在lvgl屏上也显示出获取到的当前IP地址

image.png

【工程源代码】

ra8d1_blink.zip




关键词: 瑞萨     RA8D1     测评     zephyr     以太网     LA    

高工
2026-09-18 20:13:03     打赏
2楼

感谢大佬的以太网的知识介绍


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]