EPTmachine 发表于 2025-6-30 18:43

【EtherCAT开发】1、移植瑞萨官方EtherCAT IO例程到EtherKit开发板`

本帖最后由 EPTmachine 于 2025-7-1 16:42 编辑

@21小跑堂   #申请原创#

# 1、硬件平台

EtherKit是瑞萨和RT-Thread联合推出的RZN2L开发板,芯片型号为R9A07G084M08GBG,带有EtherCAT从站控制器,可以作为EtherCAT从站控制芯片。以下为开发板的介绍页面。

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/hw-board/rzn2l-etherkit/rzn2l-etherkit

# 2、官方EtherCAT IO工程

EtherCAT从站的IO控制是EtherCAT应用中的基础应用。RZN2L芯片有多款官方的开发板,开发板配置的例程可以作为应用开发的参考。CN032-GATEWAYREFZ RZ/N2L 远程 I/O 解决方案套件的链接如下。

https://www.renesas.cn/zh/design-resources/boards-kits/cn032-gatewayrefz#overview

在开发板的介绍页面可以下载示例程序以及使用说明。

!(data/attachment/forum/202506/30/183440wzorjh7z7hmh3zj2.png "demo_code.png")

# 3、例程移植

基于fsp_rzn_v2.2.0移植官方的Remote IO例程到EtherKit开发板上。完成移植需要:

- EtherKit开发板
- Jlink调试器
- 官方示例工程

RTThread为EtherKit开发板提供有不同的开发例程,工程中有RZN2L的引脚的配置,导出RT_Thread官方例程中引脚配置,用于在新的工程中配置芯片引脚。打开工程中的FSP工程配置文件,在Pins选项卡中导出引脚的配置文件,方便后续开发中的引脚配置。

## 3.1 工程创建以及外设配置

开发环境选择e2studio,fsp版本选择v2.0.0(使用v2.2.0也可以,可以移植成功),参考下载的示例工程说明书进行工程的移植。

!(data/attachment/forum/202506/30/183529ccn0737z3z13d13y.png "demo_document_code.png")

在e2studio中创建RZ/N芯片工程

!(data/attachment/forum/202506/30/183548ylazlr1ape00h9a9.png "RZ_project_create1.png")

!(data/attachment/forum/202506/30/183601m5d5qav7iraiy8ve.png "RZ_project_create2.png")

指定工程名称

!(data/attachment/forum/202506/30/183609o8gg718yluzd4uss.png "RZ_project_create3.png")

选择开发板类型、启动方式、芯片型号以及编译器

!(data/attachment/forum/202506/30/183618ss1sq3aasa7kvg88.png "RZ_project_create4.png")

选择编译输出结果类型以及RTOS

!(data/attachment/forum/202506/30/183630ekiussfewssf2ius.png "RZ_project_create5.png")

选择工程模板

!(data/attachment/forum/202506/30/183639sqc4v5z1dnd1f5k4.png "RZ_project_create6.png")

工程创建完成后,打开其中的configuration.xml文件进入FSP配置界面。

!(data/attachment/forum/202506/30/183654fboi1l6ezeh1ndh3.png "project_config1.png")

在FSP配置界面中导入之前导出的EtherKit开发板的引脚配置,

!(data/attachment/forum/202506/30/183707wy0m00z4qu7r5qki.png "import_pin_cfg.png")

以这种方式导入到e2studio中,在生成代码时会出现配置变量重定义的错误,将原有的引脚配置删除掉。

!(data/attachment/forum/202506/30/183734yrt6jzccp6q05rhp.png "delete_default_pincfg.png")

在Stacks界面中的“NetWorking”一栏中添加EtherCAT从站的驱动,修改其中的默认参数。

!(data/attachment/forum/202506/30/183746sc0hq9v1vrffnfv8.png "ssc_config1.png")

EtherKit开发板的网卡芯片为RTL8211F,设置用户自定义的驱动,并设置控制其的网络控制器通道以及定义初始化函数名称。

!(data/attachment/forum/202506/30/183753dh1hhs1wws65i1hb.png "ssc_config2.png")

修改网络控制器的配置模式

!(data/attachment/forum/202506/30/183800iqkzqbonfn4n4fkn.png "ssc_config3.png")

同样地,修改网络控制器1的配置信息如下

!(data/attachment/forum/202506/30/183809hqqqdvj4k07ud5u5.png "ssc_config4.png")

!(data/attachment/forum/202506/30/183816ewol4sw4j1c49r4w.png "ssc_config5.png")

添加用于周期控制的定时器,并设置定时器的中断优先级。

!(data/attachment/forum/202506/30/183822mx3qhphnx6qxaxeb.png "ssc_config6.png")

完成配置后保存并生成代码。

## 3.2 生成从站代码、修改应用程序

根据示例程序的说明,需要使用SSC V5.13工程生成从站的EtherCAT代码。打开SSC工具,创建新的工程

!(data/attachment/forum/202506/30/183832qa7zh400h47p7tsg.png "SSC_Code1.png")

导入示例工程中SSC配置文件

!(data/attachment/forum/202506/30/183838zylaoolay8ykzavt.png "SSC_Code2.png")

!(data/attachment/forum/202506/30/183844os21ugfqqlyqy2zy.png "SSC_Code3.png")

生成相应的EtherCAT从站配置代码。

!(data/attachment/forum/202506/30/183849mwhjnaewj0wz0bwx.png "SSC_Code4.png")

!(data/attachment/forum/202506/30/183905gyyfj4u5yejcj5yp.png "SSC_Code5.png")

示例程序中配套有相应的代码,由于使用的硬件不同,在移植时只需要其中的src文件夹下的代码即可。

!(data/attachment/forum/202506/30/183919uoxa4xe6zqqhx06q.png "demo_port1.png")

!(data/attachment/forum/202506/30/183925auxyyiti1t7tf7dy.png "demo_port2.png")

在工程中添加"ETHERCAT_SSC_PORT_GMAC_MDIO_SUPPORT=1"宏定义以及相关的文件路径。

!(data/attachment/forum/202506/30/183932vlmlbzu7ntc7nebc.png "demo_port3.png")

!(data/attachment/forum/202506/30/183938x17xvru85137v71u.png "demo_port4.png")

同时添加网卡接口芯片的初始化函数如下

```c
void phy_rtl8211f_initial(ether_phy_instance_ctrl_t *phydev)
{
#define RTL_8211F_PAGE_SELECT 0x1F
#define RTL_8211F_EEELCR_ADDR 0x11
#define RTL_8211F_LED_PAGE 0xD04
#define RTL_8211F_LCR_ADDR 0x10

    uint32_t val1, val2 = 0;

    /* switch to led page */
    R_ETHER_PHY_Write(phydev, RTL_8211F_PAGE_SELECT, RTL_8211F_LED_PAGE);

    /* set led1(green) Link 10/100/1000M, and set led2(yellow) Link 10/100/1000M+Active */
    R_ETHER_PHY_Read(phydev, RTL_8211F_LCR_ADDR, &val1);
    val1 |= (1 << 5);
    val1 |= (1 << 8);
    val1 &= (uint32_t)(~(1 << 9));
    val1 |= (1 << 10);
    val1 |= (1 << 11);
    R_ETHER_PHY_Write(phydev, RTL_8211F_LCR_ADDR, val1);

    /* set led1(green) EEE LED function disabled so it can keep on when linked */
    R_ETHER_PHY_Read(phydev, RTL_8211F_EEELCR_ADDR, &val2);
    val2 &=(uint32_t)(~(1 << 2));
    R_ETHER_PHY_Write(phydev, RTL_8211F_EEELCR_ADDR, val2);

    /* switch back to page0 */
    R_ETHER_PHY_Write(phydev, RTL_8211F_PAGE_SELECT, 0xa42);

    R_BSP_SoftwareDelay(100,BSP_DELAY_UNITS_MILLISECONDS);

    return;
}
```

根据示例说明书,为了可以正常调试,需要在代码的 `system_init`函数中添加延时代码,添加的位置如下。

!(data/attachment/forum/202506/30/183944mxbrwzrcojrww9gi.png "demo_port5.png")

具体的代码为

```c
#if 1
    __asm volatile (
      "    mov   r0, #0                               \n"
      "    movwr1, #0xf07f                  \n"
      "    movtr1, #0x2fa                        \n"
      "software_loop:                              \n"
      "    addsr0, #1                                 \n"
      "    cmp   r0, r1                                 \n"
      "    bne   software_loop                  \n"
      ::: "memory");
#endif
```

由于硬件存在差异,控制从站IO引脚和数量不同,需要修改应用程序中的部分代码。

!(data/attachment/forum/202506/30/183951pxurcr5053rzriru.png "demo_port6.png")

具体有以下几处:
sampleios.c中修改IO控制的引脚

```c
#if defined(BOARD_RZN2L_Gateway)
/** Array of DIP SW IOPORT pins. */
static const uint16_t g_sample_prv_dip_sws[] =
{
    (UINT16) BSP_IO_PORT_14_PIN_2, // SW2-1
    (UINT16) BSP_IO_PORT_16_PIN_3, // SW2-2
};
/** Array of LED IOPORT pins. */
static const uint16_t g_sample_prv_leds[] =
{
    (uint16_t) BSP_IO_PORT_14_PIN_0,   ///< RLED0 GREEN
    (uint16_t) BSP_IO_PORT_14_PIN_1,   ///< RLED1 GREEN
    (uint16_t) BSP_IO_PORT_14_PIN_3,   ///< RLED2 GREEN
};
#endif
```

simpleapp.c中注释掉未定义的IO控制函数调用。

```c
void APPL_SetLed(UINT16 value)
{
        /* LED type structure */
        sample_leds_t leds = g_sample_leds;

    /* Holds level to set for pins */
    bsp_io_level_t pin_level;

        /* This code uses BSP IO functions to show how it is used.*/
        R_BSP_PinAccessEnable();
#if defined(BOARD_RZN2L_Gateway)
    pin_level = ((value & 1) ?BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
    pin_level = ((value & 2) ?BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
    pin_level = ((value & 4) ?BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
//    pin_level = ((value & 8) ?BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
#else
    pin_level = ((value & 1) ?BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    pin_level = ((value & 2) ?BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    pin_level = ((value & 4) ?BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
    pin_level = ((value & 8) ?BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
#endif
    R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds, pin_level);
    R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds, pin_level);
    R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds, pin_level);
//    R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds, pin_level);

        /* Protect PFS registers */
        R_BSP_PinAccessDisable();
}
/////////////////////////////////////////////////////////////////////////////////////////
/**
\retuen   UINT16 DIP SW value. Low input level means ON.

\brief    Get DIP SW
*////////////////////////////////////////////////////////////////////////////////////////
UINT16 APPL_GetDipSw(void)
{
        UINT16 u16DipSw;

        u16DipSw = 0;

        /* DIP SW type structure */
    sample_dip_sws_t dipsws = g_sample_dip_sws;

    /* This code uses BSP IO functions to show how it is used.*/
    R_BSP_PinAccessEnable();

    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x01;
    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x02;
//    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x04;
//    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x08;

#if defined(BOARD_RZT2M_RSK)
    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x10;
    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x20;
    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x40;
    if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws), (bsp_io_port_pin_t)dipsws.p_sws) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x80;
#endif

        /* Protect PFS registers */
        R_BSP_PinAccessDisable();

        return u16DipSw;
}
```

至此,示例工程的移植完成,编译正常通过后,即可下载到开发板进行调试。可用的工程可以参考附件工程。

# 4、程序运行

示例工程使用TWinCAT作为EtherCAT主站来控制从站。将示例代码中的从站配置文件复制到TWinCAT的EtherCAT目录中。

!(data/attachment/forum/202506/30/184004eo0kolkzoo81zrml.png "demo_Run_1.png")

参考示例使用说明中的更新从站的EEPROM,详细的过程说明可以参考说明文档。

!(data/attachment/forum/202506/30/184012qz26ryy2tudjrbyf.png "demo_Run_2.png")

从站运行后,通过控制开发板上的按键,可以改变EtherCAT PDO Input的数据。

!(data/attachment/forum/202506/30/184020tk6p4m4y47ak6app.png "demo_Run_3.png")

# 5、总结

EtherKit开发板的芯片是瑞萨RZN2L,瑞萨官方提供不同的开发板和例程,配套有具体的使用说明,在此基础上稍加修改即可移植EtherCAT应用代码,作为EtherCAT应用的一个参考。


[!(/source/plugin/zhanmishu_markdown/template/editor/images/upload.svg) 附件:RZN2L_etherkit_esc_io.zip](forum.html?mod=attachment&aid=2419688 "attachment")
页: [1]
查看完整版本: 【EtherCAT开发】1、移植瑞萨官方EtherCAT IO例程到EtherKit开发板`