【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]