[i=s] 本帖最后由 EPTmachine 于 2025-7-1 16:42 编辑 [/i]<br />
<br />
@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
在开发板的介绍页面可以下载示例程序以及使用说明。

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也可以,可以移植成功),参考下载的示例工程说明书进行工程的移植。

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


指定工程名称

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

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

选择工程模板

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

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

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

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

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

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

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


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

完成配置后保存并生成代码。
3.2 生成从站代码、修改应用程序
根据示例程序的说明,需要使用SSC V5.13工程生成从站的EtherCAT代码。打开SSC工具,创建新的工程

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


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


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


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


同时添加网卡接口芯片的初始化函数如下
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
函数中添加延时代码,添加的位置如下。

具体的代码为
#if 1
__asm volatile (
" mov r0, #0 \n"
" movw r1, #0xf07f \n"
" movt r1, #0x2fa \n"
"software_loop: \n"
" adds r0, #1 \n"
" cmp r0, r1 \n"
" bne software_loop \n"
::: "memory");
#endif
由于硬件存在差异,控制从站IO引脚和数量不同,需要修改应用程序中的部分代码。

具体有以下几处:
sampleios.c中修改IO控制的引脚
#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控制函数调用。
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[4];
/* This code uses BSP IO functions to show how it is used.*/
R_BSP_PinAccessEnable();
#if defined(BOARD_RZN2L_Gateway)
pin_level[SAMPLE_LED_RLED0] = ((value & 1) ? BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
pin_level[SAMPLE_LED_RLED1] = ((value & 2) ? BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
pin_level[SAMPLE_LED_RLED2] = ((value & 4) ? BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
// pin_level[SAMPLE_LED_RLED3] = ((value & 8) ? BSP_IO_LEVEL_LOW : BSP_IO_LEVEL_HIGH);
#else
pin_level[SAMPLE_LED_RLED0] = ((value & 1) ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
pin_level[SAMPLE_LED_RLED1] = ((value & 2) ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
pin_level[SAMPLE_LED_RLED2] = ((value & 4) ? BSP_IO_LEVEL_HIGH : BSP_IO_LEVEL_LOW);
pin_level[SAMPLE_LED_RLED3] = ((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[SAMPLE_LED_RLED0], pin_level[SAMPLE_LED_RLED0]);
R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds[SAMPLE_LED_RLED1], pin_level[SAMPLE_LED_RLED1]);
R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds[SAMPLE_LED_RLED2], pin_level[SAMPLE_LED_RLED2]);
// R_IOPORT_PinWrite(&g_ioport_ctrl, (bsp_io_port_pin_t)leds.p_leds[SAMPLE_LED_RLED3], pin_level[SAMPLE_LED_RLED3]);
/* 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[SAMPLE_DIPSW_0]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_0]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x01;
if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_1]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_1]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x02;
// if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_2]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_2]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x04;
// if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_3]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_3]) == 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[SAMPLE_DIPSW_4]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_4]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x10;
if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_5]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_5]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x20;
if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_6]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_6]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x40;
if (R_BSP_FastPinRead(R_BSP_IoRegionGet((bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_7]), (bsp_io_port_pin_t)dipsws.p_sws[SAMPLE_DIPSW_7]) == BSP_IO_LEVEL_LOW) u16DipSw |= 0x80;
#endif
/* Protect PFS registers */
R_BSP_PinAccessDisable();
return u16DipSw;
}
至此,示例工程的移植完成,编译正常通过后,即可下载到开发板进行调试。可用的工程可以参考附件工程。
4、程序运行
示例工程使用TWinCAT作为EtherCAT主站来控制从站。将示例代码中的从站配置文件复制到TWinCAT的EtherCAT目录中。

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

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

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