[Example][TC397以太网例程详解] - 12.GETH 初始化
Aurix TriCore TC397 以太网官方例程
关键词
TC397 官方例程;TC397 以太网例程;TC397 GETH;
简介
本篇为 Aurix TriCore TC397 以太网官方例程分析,重点关注其硬件行为
调试所用的开发板型号:KIT-A2G-TC397-5V-TFT
所使用的例程:Ethernet_1_KIT_TC397_TFT
英飞凌 TriCore 官方例程下载地址:
https://github.com/Infineon/AURIX_code_examples
系列文章链接
TC397以太网例程 - 17.ECHO 应用 - 轮询定时器
TC397以太网例程 - 18.ECHO 应用 - 接收报文
目录
// 函数调用栈
core0_main()
|--> Ifx_Lwip_init()
|--> netif_add()
|--> ifx_netif_init()
|--> low_level_init() // 硬件初始化
|--> IfxGeth_Eth_initModule()
IfxGeth_Eth_initModule() 将相关配置,写入实际的硬件寄存器,即进行 GETH 实际硬件的初始化:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
IfxGeth_Eth *ethernetif = netif->state;
...
IfxGeth_Eth_Config GethConfig;
...
// initialize the module
IfxGeth_Eth_initModule(ethernetif, &GethConfig);
1.获取 GETH 寄存器组
将配置写入硬件寄存器,完成 GETH 模块的初始化,初始化前先从传入的配置项中获取 GETH 模块的寄存器组:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
Ifx_GETH *gethSFR = config->gethSFR;
geth->gethSFR = gethSFR;
2.使能 GETH 模块
IfxGeth_enableModule() 检查模块是否使能(CLC.DISS == 0),若未使能则发送使能信号(CLC.DISR = 0):
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* Enable Module */
IfxGeth_enableModule(gethSFR);
----------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_enableModule(Ifx_GETH *gethSFR)
{
uint16 psw = IfxScuWdt_getCpuWatchdogPassword();
// 检查模块是否已使能,若未使能则发送使能请求
if (IfxGeth_isModuleEnabled(gethSFR) != 1) /* if module is not enabled already */
{
IfxScuWdt_clearCpuEndinit(psw); /* clears the endinit protection*/
// 发送模块使能请求
gethSFR->CLC.B.DISR = 0; /* set the enable request */
IfxScuWdt_setCpuEndinit(psw); /* sets the endinit protection back on*/
}
// 检查模块是否已使能
IfxGeth_isModuleEnabled(gethSFR); /* read back to ensure proper enabling */
|--> return (gethSFR->CLC.B.DISS == 0) ? 1 : 0;
}
3.设置接口引脚(RGMII)
该示例中,用户配置使用 RGMII 接口,并设置了具体的引脚:
// Libraries/Ethernet/lwip/port/src/netif.c
/* pin configuration RTL8211F */
const IfxGeth_Eth_RgmiiPins rtl8211f_pins = {
.txClk = Ð_TXCLK_PIN, /* TXCLK */
.txd0 = Ð_TXD0_PIN, /* TXD0 */
.txd1 = Ð_TXD1_PIN, /* TXD1 */
.txd2 = Ð_TXD2_PIN, /* TXD2 */
.txd3 = Ð_TXD3_PIN, /* TXD3 */
.txCtl = Ð_TXCTL_PIN, /* TXCTL */
.rxClk = Ð_RXCLK_PIN, /* RXCLK */
.rxd0 = Ð_RXD0_PIN, /* RXD0 */
.rxd1 = Ð_RXD1_PIN, /* RXD1 */
.rxd2 = Ð_RXD2_PIN, /* RXD2 */
.rxd3 = Ð_RXD3_PIN, /* RXD3 */
.rxCtl = Ð_RXCTL_PIN, /* RXCTL */
.mdc = Ð_MDC_PIN, /* MDC */
.mdio = Ð_MDIO_PIN, /* MDIO */
.grefClk = Ð_GREFCLK_PIN /* GREFCLK */
};
----------------------------------------------------------------------
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
GethConfig.phyInterfaceMode = IfxGeth_PhyInterfaceMode_rgmii;
GethConfig.pins.rgmiiPins = &rtl8211f_pins;
设置 RGMII 接口的输入输出引脚:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* Set up the pins */
...
else if (config->phyInterfaceMode == IfxGeth_PhyInterfaceMode_rgmii)
{
if (config->pins.rgmiiPins != NULL_PTR)
{
IfxGeth_Eth_setupRgmiiOutputPins(geth, config->pins.rgmiiPins);
IfxGeth_Eth_setupRgmiiInputPins(geth, config->pins.rgmiiPins);
}
}
3.1.输出引脚
IfxGeth_Eth_setupRgmiiOutputPins() 设置 RGMII 的输出引脚:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_setupRgmiiOutputPins(IfxGeth_Eth *geth, const IfxGeth_Eth_RgmiiPins *rgmiiPins)
{
IFX_UNUSED_PARAMETER(geth);
IfxPort_OutputMode mode = IfxPort_OutputMode_pushPull;
IfxPort_PadDriver speedGrade = IfxPort_PadDriver_cmosAutomotiveSpeed4;
IfxGeth_Txclk_Out *txClk = rgmiiPins->txClk;
IfxGeth_Txctl_Out *txCtl = rgmiiPins->txCtl;
IfxGeth_Txd_Out *txd0 = rgmiiPins->txd0;
IfxGeth_Txd_Out *txd1 = rgmiiPins->txd1;
IfxGeth_Txd_Out *txd2 = rgmiiPins->txd2;
IfxGeth_Txd_Out *txd3 = rgmiiPins->txd3;
IfxGeth_Mdc_Out *mdc = rgmiiPins->mdc;
IfxGeth_Mdio_InOut *mdio = rgmiiPins->mdio;
// -------------------------------------------------------------------
// 引脚启用 SCR 控制
IfxPort_setPinControllerSelection(mdc->pin.port, mdc->pin.pinIndex);
IfxPort_setPinControllerSelection(mdio->pin.port, mdio->pin.pinIndex);
IfxPort_setPinControllerSelection(txClk->pin.port, txClk->pin.pinIndex);
IfxPort_setPinControllerSelection(txCtl->pin.port, txCtl->pin.pinIndex);
IfxPort_setPinControllerSelection(txd0->pin.port, txd0->pin.pinIndex);
IfxPort_setPinControllerSelection(txd1->pin.port, txd1->pin.pinIndex);
IfxPort_setPinControllerSelection(txd2->pin.port, txd2->pin.pinIndex);
IfxPort_setPinControllerSelection(txd3->pin.port, txd3->pin.pinIndex);
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// 输出模式选择:推挽、开漏
IfxPort_setPinModeOutput(mdc->pin.port, mdc->pin.pinIndex, mode, mdc->select);
IfxPort_setPinModeOutput(txClk->pin.port, txClk->pin.pinIndex, mode, txClk->select);
IfxPort_setPinModeOutput(txCtl->pin.port, txCtl->pin.pinIndex, mode, txCtl->select);
IfxPort_setPinModeOutput(txd0->pin.port, txd0->pin.pinIndex, mode, txd0->select);
IfxPort_setPinModeOutput(txd1->pin.port, txd1->pin.pinIndex, mode, txd1->select);
IfxPort_setPinModeOutput(txd2->pin.port, txd2->pin.pinIndex, mode, txd2->select);
IfxPort_setPinModeOutput(txd3->pin.port, txd3->pin.pinIndex, mode, txd3->select);
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// 引脚驱动特性:TTL、CMOS
IfxPort_setPinPadDriver(mdc->pin.port, mdc->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txClk->pin.port, txClk->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txCtl->pin.port, txCtl->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txd0->pin.port, txd0->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txd1->pin.port, txd1->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txd2->pin.port, txd2->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(txd3->pin.port, txd3->pin.pinIndex, speedGrade);
// -------------------------------------------------------------------
}
3.2.输入引脚
IfxGeth_Eth_setupRgmiiInputPins() 设置 RGMII 的输入引脚,同时关联 GETH 模块的 GPCTL 寄存器:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_setupRgmiiInputPins(IfxGeth_Eth *geth, const IfxGeth_Eth_RgmiiPins *rgmiiPins)
{
IfxPort_InputMode mode = IfxPort_InputMode_noPullDevice;
IfxPort_PadDriver speedGrade = IfxPort_PadDriver_cmosAutomotiveSpeed4;
IfxGeth_Rxclk_In *rxClk = rgmiiPins->rxClk;
IfxGeth_Rxctl_In *rxCtl = rgmiiPins->rxCtl;
IfxGeth_Rxd_In *rxd0 = rgmiiPins->rxd0;
IfxGeth_Rxd_In *rxd1 = rgmiiPins->rxd1;
IfxGeth_Rxd_In *rxd2 = rgmiiPins->rxd2;
IfxGeth_Rxd_In *rxd3 = rgmiiPins->rxd3;
IfxGeth_Grefclk_In *grefClk = rgmiiPins->grefClk;
IfxGeth_Mdio_InOut *mdio = rgmiiPins->mdio;
// -------------------------------------------------------------------
// 将相关引脚与 GETH 模块的 GPCTL 寄存器绑定
geth->gethSFR->GPCTL.B.ALTI0 = mdio->inSelect;
geth->gethSFR->GPCTL.B.ALTI1 = rxClk->select;
geth->gethSFR->GPCTL.B.ALTI4 = rxCtl->select;
geth->gethSFR->GPCTL.B.ALTI6 = rxd0->select;
geth->gethSFR->GPCTL.B.ALTI7 = rxd1->select;
geth->gethSFR->GPCTL.B.ALTI8 = rxd2->select;
geth->gethSFR->GPCTL.B.ALTI9 = rxd3->select;
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// 引脚启用 SCR 控制
IfxPort_setPinControllerSelection(rxClk->pin.port, rxClk->pin.pinIndex);
IfxPort_setPinControllerSelection(rxCtl->pin.port, rxCtl->pin.pinIndex);
IfxPort_setPinControllerSelection(rxd0->pin.port, rxd0->pin.pinIndex);
IfxPort_setPinControllerSelection(rxd1->pin.port, rxd1->pin.pinIndex);
IfxPort_setPinControllerSelection(rxd2->pin.port, rxd2->pin.pinIndex);
IfxPort_setPinControllerSelection(rxd3->pin.port, rxd3->pin.pinIndex);
IfxPort_setPinControllerSelection(grefClk->pin.port, grefClk->pin.pinIndex);
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// 输入模式选择:高/低电平
IfxPort_setPinModeInput(rxClk->pin.port, rxClk->pin.pinIndex, mode);
IfxPort_setPinModeInput(rxCtl->pin.port, rxCtl->pin.pinIndex, mode);
IfxPort_setPinModeInput(rxd0->pin.port, rxd0->pin.pinIndex, mode);
IfxPort_setPinModeInput(rxd1->pin.port, rxd1->pin.pinIndex, mode);
IfxPort_setPinModeInput(rxd2->pin.port, rxd2->pin.pinIndex, mode);
IfxPort_setPinModeInput(rxd3->pin.port, rxd3->pin.pinIndex, mode);
IfxPort_setPinModeInput(grefClk->pin.port, grefClk->pin.pinIndex, mode);
// -------------------------------------------------------------------
// -------------------------------------------------------------------
// 引脚驱动特性:TTL、CMOS
IfxPort_setPinPadDriver(rxClk->pin.port, rxClk->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(rxCtl->pin.port, rxCtl->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(rxd0->pin.port, rxd0->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(rxd1->pin.port, rxd1->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(rxd2->pin.port, rxd2->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(rxd3->pin.port, rxd3->pin.pinIndex, speedGrade);
IfxPort_setPinPadDriver(grefClk->pin.port, grefClk->pin.pinIndex, speedGrade);
// -------------------------------------------------------------------
}
4.复位 GETH
同时向 KRST0.RST 和 KRST1.RST 写 1 发送模块复位请求,复位执行后会将 KRST0.RSTSTAT 置 1
通过向 KRSTCLR.CLR 写 1 清除 KRST0.RSTSTAT(将其置 0):
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* reset the Module */
IfxGeth_resetModule(gethSFR);
---------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_resetModule(Ifx_GETH *gethSFR)
{
...
// -------------------------------------------------------------------
// 发送复位请求
gethSFR->KRST0.B.RST = 1; /* Only if both Kernel reset bits are set a reset is executed */
gethSFR->KRST1.B.RST = 1;
// -------------------------------------------------------------------
...
// -------------------------------------------------------------------
// 检查复位操作是否完成
while (0 == gethSFR->KRST0.B.RSTSTAT) {} /* Wait until reset is executed */
// -------------------------------------------------------------------
...
// -------------------------------------------------------------------
// 清除复位状态
gethSFR->KRSTCLR.B.CLR = 1; /* Clear Kernel reset status bit */
// -------------------------------------------------------------------
...
}
5.复位 DMA
DMA 复位前设置 GPCTL.EPR(External Phy Interface RMII Mode Bit),将外部 PHY 接口的类型设置为 RGMII
后续 MAC/DMA 复位时,会根据接口类型进行相应的操作
通过向 DMA_MODE.SWR 写 1 发送 MAC/DMA 复位请求,MAC/DMA 复位完成后会将 DMA_MODE.SWR 置 1:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* select the Phy Interface Mode */
IfxGeth_setPhyInterfaceMode(gethSFR, config->phyInterfaceMode);
IfxGeth_dma_applySoftwareReset(gethSFR);
/* wait until reset is finished or timeout. */
{
uint32 timeout = 0;
while ((IfxGeth_dma_isSoftwareResetDone(gethSFR) == 0) &&
(timeout < IFXGETH_MAX_TIMEOUT_VALUE)) // IFXGETH_MAX_TIMEOUT_VALUE = 1000
{
timeout++;
}
}
---------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_setPhyInterfaceMode(Ifx_GETH *gethSFR, IfxGeth_PhyInterfaceMode mode)
{
gethSFR->GPCTL.B.EPR = mode; // Mode = IfxGeth_PhyInterfaceMode_rgmii = 1
}
---------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_dma_applySoftwareReset(Ifx_GETH *gethSFR)
{
gethSFR->DMA_MODE.B.SWR = 1; // 发送复位请求
}
---------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE boolean IfxGeth_dma_isSoftwareResetDone(Ifx_GETH *gethSFR)
{
return gethSFR->DMA_MODE.B.SWR == 0;
}
6.MAC 配置
IfxGeth_Eth_configureMacCore() 将配置写入 MAC 相关的寄存器:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* Configure MAC Core */
IfxGeth_Eth_configureMacCore(geth, &config->mac);
6.1.工作模式
MAC_CONFIGURATION.DM(Duplex Mode)置 1,将 MAC 设置为全双工模式,表示可以同时进行接收/发送:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModuleConfig(IfxGeth_Eth_Config *config, Ifx_GETH *gethSFR)
{
...
.mac = {
.duplexMode = IfxGeth_DuplexMode_fullDuplex,
---------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
...
/* MAC configuration */
IfxGeth_mac_setDuplexMode(geth->gethSFR, macConfig->duplexMode);
---------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setDuplexMode(Ifx_GETH *gethSFR, IfxGeth_DuplexMode mode)
{
gethSFR->MAC_CONFIGURATION.B.DM = mode; // IfxGeth_DuplexMode_fullDuplex = 1
}
6.2.连接速率
MAC_CONFIGURATION.PS(Port Select )与 MAC_CONFIGURATION.FES(Speed)共同决定连接速率,将二者均设置为 0 表示连接速率为 1000Mbps:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
GethConfig.mac.lineSpeed = IfxGeth_LineSpeed_1000Mbps;
---------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setLineSpeed(geth->gethSFR, macConfig->lineSpeed);
---------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_mac_setLineSpeed(Ifx_GETH *gethSFR, IfxGeth_LineSpeed speed)
{
switch (speed)
{
...
case IfxGeth_LineSpeed_1000Mbps:
gethSFR->MAC_CONFIGURATION.B.PS = 0;
gethSFR->MAC_CONFIGURATION.B.FES = 0;
break;
6.3.以太网前导码
以太网前导码(Preamble)一般为 7 个字节,每个字节均为固定的 10101010,其作用是,发送方和接收方之间进行时钟同步,当发送方发送数据时,加上 7 个字节的前导码作为报文头部,发送给接收方,接收方收到 10101010 时,会按照协议规定,调整自己的时钟,准备接收发送方发来的数据,该例程中,前导码的长度为 7 个字节:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setPreambleLength(geth->gethSFR, IfxGeth_PreambleLength_7Bytes);
---------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setPreambleLength(Ifx_GETH *gethSFR, IfxGeth_PreambleLength length)
{
gethSFR->MAC_CONFIGURATION.B.PRELEN = length; // IfxGeth_PreambleLength_7Bytes = 0
}
MAC_CONFIGURATION.PRELEN(Preamble Length for Transmit Packets)控制每个 Tx 数据包前加上的前导码的长度,00 表示前导码长度为 7-bytes
6.4.数据包大小
Tx/Rx 单个数据包的最大长度为 1518 字节,相关寄存器位的含义如下:
-
JE:Jumbo Packet Enable,是否启用大型帧,置 "1" 将允许传输最大 9018 字节的数据包;
-
S2KP:Support for 2K Packets,该位置 "1" 后,会将长度不超过 2000 字节的数据包视为普通数据包;
-
GPSLCE:Giant Packet Size Limit Control Enable,该位置 "1" 后,将 MAC_Ext_Configuration.GPSL 中的值用于判断该帧是否为大型帧;
-
JD:Jabber Disable,Jabber 帧是指,有效长度大于端口允许通过的最大报文长度,且 CRC 校验错误的帧,如果禁用(该位置 "1"),当传输大于 2048 字节的数据时,超出部分的数据会被丢弃;
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModuleConfig(IfxGeth_Eth_Config *config, Ifx_GETH *gethSFR)
{
...
.mac = {
...
.maxPacketSize = 1518,
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setMaxPacketSize(geth->gethSFR, macConfig->maxPacketSize);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_mac_setMaxPacketSize(Ifx_GETH *gethSFR, uint16 maxPacketSize)
{
...
// -------------------------------------------------------------------
maxSize = maxPacketSize;
macConfig.U = gethSFR->MAC_CONFIGURATION.U;
// -------------------------------------------------------------------
// -------------------------------------------------------------------
if (maxSize == 1518)
{
macConfig.B.JE = 0;
macConfig.B.S2KP = 0;
macConfig.B.GPSLCE = 0;
macConfig.B.JD = 0;
}
// -------------------------------------------------------------------
...
// -------------------------------------------------------------------
// 将值写入硬件寄存器
gethSFR->MAC_CONFIGURATION.U = macConfig.U;
// -------------------------------------------------------------------
}
6.5.是否去除 CRC
-
ACS:Automatic Pad or CRC Stripping,该位置 "1" 后,仅当帧小于 1536 字节时,MAC 才会去除 Pad 或 FCS 相关位,该位置 "0" 时,MAC 直接将数据帧传输给应用程序,而不进行任何修改;
-
CST:CRC stripping for Type packets,该位置 "1" 后,在将数据帧传输给应用程序前,去除所有 EtherType 大于 1536(0x0600) 数据帧的最后 4 个字节(FCS);
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setCrcStripping(geth->gethSFR, FALSE, FALSE);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setCrcStripping(Ifx_GETH *gethSFR, boolean acsEnabled, boolean cstEnabled)
{
gethSFR->MAC_CONFIGURATION.B.ACS = ((acsEnabled == 1) ? 1 : 0); // 0
gethSFR->MAC_CONFIGURATION.B.CST = ((cstEnabled == 1) ? 1 : 0); // 0
}
EtherType 用于指明数据帧字段中,使用的协议类型,常见的 EtherType 值有:
-
IPv4:0x0800;
-
ARP:0x0806;
-
PPPoE:0x8864;
-
802.1Q TAG:0x8100;
-
IPv6:0x86DD;
-
MPLS Label:0x8847;
6.6.是否启用 CRC 校验
IfxGeth_mac_setCrcChecking() 设置是否启用接收数据包的 CRC 校验,MAC_EXT_CONFIGURATION.DCRCC 置 "1" 将禁用接收数据包的 CRC 校验:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setCrcChecking(geth->gethSFR, FALSE);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setCrcChecking(Ifx_GETH *gethSFR, boolean enabled)
{
gethSFR->MAC_EXT_CONFIGURATION.B.DCRCC = ((enabled == 1) ? 0 : 1); // DCRCC = 1
}
6.7.是否启用网络环回
MAC_CONFIGURATION.LM(Loopback Mode )控制是否启用网络环回,该例程禁用网络环回:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
GethConfig.mac.loopbackMode = IfxGeth_LoopbackMode_disable;
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
/* MAC configuration */
...
IfxGeth_mac_setLoopbackMode(geth->gethSFR, macConfig->loopbackMode);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setLoopbackMode(Ifx_GETH *gethSFR, IfxGeth_LoopbackMode mode)
{
gethSFR->MAC_CONFIGURATION.B.LM = mode;
}
6.8.禁用监听模式
MAC_PACKET_FILTER.PR(Promiscuous Mode)置 "1" 后直接传输所有数据包,而不管其源地址和目标地址:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
...
/* packet Filter Configuration */
IfxGeth_mac_setPromiscuousMode(geth->gethSFR, FALSE);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setPromiscuousMode(Ifx_GETH *gethSFR, boolean enabled)
{
gethSFR->MAC_PACKET_FILTER.B.PR = ((enabled == 1) ? 1 : 0); // PR = 0
}
6.9.禁用组播
MAC_PACKET_FILTER.PM(Pass All Multicast)置 "1" 允许所有包含组播地址的数据包传输:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
...
/* packet Filter Configuration */
...
IfxGeth_mac_setAllMulticastPassing(geth->gethSFR, FALSE);
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.h
IFX_INLINE void IfxGeth_mac_setAllMulticastPassing(Ifx_GETH *gethSFR, boolean enabled)
{
gethSFR->MAC_PACKET_FILTER.B.PM = ((enabled == 1) ? 1 : 0); // PM = 0
}
6.10.设置 MAC 地址
将用户定义的 MAC 地址写入 MAC_ADDRESS_HIGH0 及 MAC_ADDRESS_LOW0 寄存器:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
GethConfig.mac.macAddress[0] = netif->hwaddr[0];
GethConfig.mac.macAddress[1] = netif->hwaddr[1];
GethConfig.mac.macAddress[2] = netif->hwaddr[2];
GethConfig.mac.macAddress[3] = netif->hwaddr[3];
GethConfig.mac.macAddress[4] = netif->hwaddr[4];
GethConfig.mac.macAddress[5] = netif->hwaddr[5];
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMacCore(IfxGeth_Eth *geth, IfxGeth_Eth_MacConfig *macConfig)
{
...
/* set MAC Address */
IfxGeth_mac_setMacAddress(geth->gethSFR, macConfig->macAddress);
}
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_mac_setMacAddress(Ifx_GETH *gethSFR, uint8 *macAddress)
{
gethSFR->MAC_ADDRESS_HIGH0.U = 0
| ((uint32)macAddress[4] << 0U)
| ((uint32)macAddress[5] << 8U)
| 0x80000000U;
gethSFR->MAC_ADDRESS_LOW0.U = 0
| ((uint32)macAddress[0] << 0U)
| ((uint32)macAddress[1] << 8U)
| ((uint32)macAddress[2] << 16U)
| ((uint32)macAddress[3] << 24U);
}
MAC_ADDRESS0_HIGH.ADDRHI 存储 MAC 地址的高 16 位
MAC_ADDRESS0_LOW.ADDRLO 存储 MAC 地址的低 32 位
7.MTL 配置
IfxGeth_Eth_configureMTL() 配置 Tx/Rx 队列及 MTL 中断:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* Configure MTL */
IfxGeth_Eth_configureMTL(geth, &config->mtl);
7.1.队列数量
numOfQueues 设置为 Tx/Rx 队列数量中较大的一个:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
// MTL configuration
GethConfig.mtl.numOfTxQueues = 1;
GethConfig.mtl.numOfRxQueues = 1;
---------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMTL(IfxGeth_Eth *geth, IfxGeth_Eth_MtlConfig *mtlConfig)
{
uint32 txQueueIndex, rxQueueIndex, queueIndex;
// numOfQueues = 1
uint32 numOfQueues = (mtlConfig->numOfTxQueues >= mtlConfig->numOfRxQueues) ?
mtlConfig->numOfTxQueues :
mtlConfig->numOfRxQueues;
7.2.清除中断标志
Tx/Rx 各自包含 1 条数据队列,初始化前先清空队列的中断标志位:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMTL(IfxGeth_Eth *geth, IfxGeth_Eth_MtlConfig *mtlConfig)
{
...
/* clear all flags */
for (queueIndex = 0; queueIndex < numOfQueues; queueIndex++)
{
IfxGeth_mtl_clearAllInterruptFlags(geth->gethSFR, (IfxGeth_MtlQueue)queueIndex);
}
----------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Std/IfxGeth.c
void IfxGeth_mtl_clearAllInterruptFlags(Ifx_GETH *gethSFR, IfxGeth_MtlQueue queueId)
{
uint32 value = (1 << IfxGeth_MtlInterruptFlag_txQueueUnderflow) |
(1 << IfxGeth_MtlInterruptFlag_averageBitsPerSlot) |
(1 << IfxGeth_MtlInterruptFlag_rxQueueOverflow);
switch (queueId)
{
case IfxGeth_MtlQueue_0:
gethSFR->MTL_Q0.INTERRUPT_CONTROL_STATUS.U |= value;
break;
其中,各参数的含义如下:
-
IfxGeth_MtlInterruptFlag_txQueueUnderflow == 0:对应寄存器位 MTL_Q0_INTERRUPT_CONTROL_STATUS.TXUNFIS(Transmit Queue Underflow Interrupt Status),指示 Tx 是否产生 UnderFlow 中断,置 1 清除;
-
IfxGeth_MtlInterruptFlag_averageBitsPerSlot == 1:对应寄存器位 MTL_Q0_INTERRUPT_CONTROL_STATUS.ABPSIS(Average Bits Per Slot Interrupt Status),指示 MAC 是否更新了平均码率,置 1 清除;
-
IfxGeth_MtlInterruptFlag_rxQueueOverflow == 16:对应寄存器位 MTL_Q0_INTERRUPT_CONTROL_STATUS.RXOVFIS(Receive Queue Overflow Interrupt Status),指示 Rx 是否产生 OverFlow 中断,置 1 清除;
7.3.Tx 队列配置
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMTL(IfxGeth_Eth *geth, IfxGeth_Eth_MtlConfig *mtlConfig)
{
...
// --------------------------------------------------------------
/* TX Queue(s) configuration */
// 如果 Tx 队列的数量大于 1,则需要设置队列调度算法,该示例中,Tx 仅包含 1 条发送队列
if (mtlConfig->numOfTxQueues > 1)
{
IfxGeth_mtl_setTxSchedulingAlgorithm(geth->gethSFR,
mtlConfig->txSchedulingAlgorithm);
|--> gethSFR->MTL_OPERATION_MODE.B.SCHALG = schedulingAlgorithm;
}
// --------------------------------------------------------------
// 初始化队列
for (txQueueIndex = 0; txQueueIndex < mtlConfig->numOfTxQueues; txQueueIndex++)
{
// --------------------------------------------------------------
// 设置队列大小:
// GethConfig.mtl.txQueue[0].txQueueSize = IfxGeth_QueueSize_2560Bytes;
IfxGeth_mtl_setTxQueueSize(geth->gethSFR,
(IfxGeth_TxMtlQueue)txQueueIndex,
mtlConfig->txQueue[txQueueIndex].txQueueSize);
|--> gethSFR->MTL_TXQ0.OPERATION_MODE.B.TQS = queueSize;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 启用存储转发:
// GethConfig.mtl.txQueue[0].storeAndForward = TRUE;
IfxGeth_mtl_setTxStoreAndForward(geth->gethSFR,
(IfxGeth_TxMtlQueue)txQueueIndex,
mtlConfig->txQueue[txQueueIndex].storeAndForward);
|--> gethSFR->MTL_TXQ0.OPERATION_MODE.B.TSF = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Tx 队列使能
IfxGeth_mtl_enableTxQueue(geth->gethSFR, (IfxGeth_TxMtlQueue)txQueueIndex);
|--> gethSFR->MTL_TXQ0.OPERATION_MODE.B.TXQEN = 2;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 禁用 Tx 队列的 UnderFlow 中断
// txQueueUnderflowInterruptEnabled = FALSE
if (mtlConfig->txQueue[txQueueIndex].txQueueUnderflowInterruptEnabled)
{
IfxGeth_mtl_enableInterrupt(geth->gethSFR,
(IfxGeth_MtlQueue)txQueueIndex,
IfxGeth_MtlInterruptFlag_txQueueUnderflow);
|--> uint32 mask = (1 << IfxGeth_MtlInterruptFlag_txQueueUnderflow) |
(1 << IfxGeth_MtlInterruptFlag_averageBitsPerSlot) |
(1 << IfxGeth_MtlInterruptFlag_rxQueueOverflow);
|--> uint32 value = (1 << (flag + 8));
|--> gethSFR->MTL_Q0.INTERRUPT_CONTROL_STATUS.U =
(gethSFR->MTL_Q0.INTERRUPT_CONTROL_STATUS.U & ~mask) | value;
}
// --------------------------------------------------------------
}
其中,相关寄存器位及写入值的含义如下:
-
MTL_OPERATION_MODE.SCHALG:Tx Scheduling Algorithm,Tx 队列的调度算法:
-
00:WRR algorithm,负载均衡;
-
01:未使用;
-
10:未使用;
-
11:Strict priority algorithm,严格优先级;
-
该示例中,Tx 仅包含 1 条队列,因此不需要设置队列调度算法(默认为负载均衡 WRR);
-
-
MTL_TXQ0_OPERATION_MODE.TQS:Transmit Queue Size,Tx 队列的大小,设置为 2560 字节;
-
MTL_TXQ0_OPERATION_MODE.TSF:Transmit Store and Forward ,是否启用存储转发,设置为 "1" 启用;
-
MTL_TXQ0_OPERATION_MODE.TXQEN:Transmit Queue Enable,使能 Tx 队列(设置为 "10"):
-
00:禁用;
-
01:未使用;
-
10:使能;
-
11:未使用;
-
-
MTL_Q0_INTERRUPT_CONTROL_STATUS:队列 0 的相关中断是否启用,以及中断状态,该示例中,未启用 Tx 队列的 UnderFlow 中断,因此无需设置;
7.4.Rx 队列设置
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMTL(IfxGeth_Eth *geth, IfxGeth_Eth_MtlConfig *mtlConfig)
{
...
// --------------------------------------------------------------
/* RX Queue(s) configuration */
// 如果 Rx 队列的数量大于 1,则需要设置队列调度算法,该示例中,Rx 仅包含 1 条接收队列
if (mtlConfig->numOfRxQueues > 1)
{
IfxGeth_mtl_setRxArbitrationAlgorithm(geth->gethSFR,
mtlConfig->rxArbitrationAlgorithm);
|--> gethSFR->MTL_OPERATION_MODE.B.RAA = arbitrationAlgorithm;
}
// --------------------------------------------------------------
for (rxQueueIndex = 0; rxQueueIndex < mtlConfig->numOfRxQueues; rxQueueIndex++)
{
// --------------------------------------------------------------
// 设置 Rx 队列大小:
// GethConfig.mtl.rxQueue[0].rxQueueSize = IfxGeth_QueueSize_2560Bytes;
IfxGeth_mtl_setRxQueueSize(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
mtlConfig->rxQueue[rxQueueIndex].rxQueueSize);
|--> gethSFR->MTL_RXQ0.OPERATION_MODE.B.RQS = queueSize;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 启用 Rx 队列的存储转发:
// GethConfig.mtl.rxQueue[0].storeAndForward = TRUE;
IfxGeth_mtl_setRxStoreAndForward(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
mtlConfig->rxQueue[rxQueueIndex].storeAndForward);
|--> gethSFR->MTL_RXQ0.OPERATION_MODE.B.RSF = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 丢弃出错的数据包
// forwardErrorPacket = FALSE
IfxGeth_mtl_setRxForwardErrorPacket(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
mtlConfig->rxQueue[rxQueueIndex].forwardErrorPacket);
|--> gethSFR->MTL_RXQ0.OPERATION_MODE.B.FEP = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 允许小于设定值的正常数据包传输
// forwardUndersizedGoodPacket = FALSE
IfxGeth_mtl_setRxForwardUndersizedGoodPacket(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
mtlConfig->rxQueue[rxQueueIndex].forwardUndersizedGoodPacket);
|--> gethSFR->MTL_RXQ0.OPERATION_MODE.B.FUP = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 使用 DMA 通道 0 接收数据
// daBasedDmaChannelEnabled = FALSE
if (mtlConfig->rxQueue[rxQueueIndex].daBasedDmaChannelEnabled != 0)
{
IfxGeth_mtl_setRxQueueForDaBasedDmaChannel(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
TRUE);
|--> gethSFR->MTL_RXQ_DMA_MAP0.U |= (enabled << ((queueId * 8) + 4));
}
else
{
IfxGeth_mtl_setRxQueueDmaChannelMapping(geth->gethSFR,
(IfxGeth_RxMtlQueue)rxQueueIndex,
mtlConfig->rxQueue[rxQueueIndex].rxDmaChannelMap);
|--> gethSFR->MTL_RXQ_DMA_MAP0.U |= (dmaChannel << (queueId * 8));
}
// --------------------------------------------------------------
// --------------------------------------------------------------
// 使能 Rx 队列
IfxGeth_mtl_enableRxQueue(geth->gethSFR, (IfxGeth_RxMtlQueue)rxQueueIndex);
|--> gethSFR->MAC_RXQ_CTRL0.U |= (2 << (queueId * 2));
// --------------------------------------------------------------
// --------------------------------------------------------------
// 禁用 Rx 队列的 OverFlow 中断:
// .rxQueueOverflowInterruptEnabled = FALSE
if (mtlConfig->rxQueue[rxQueueIndex].rxQueueOverflowInterruptEnabled)
{
IfxGeth_mtl_enableInterrupt(geth->gethSFR,
(IfxGeth_MtlQueue)rxQueueIndex,
IfxGeth_MtlInterruptFlag_rxQueueOverflow);
|--> uint32 mask = (1 << IfxGeth_MtlInterruptFlag_txQueueUnderflow) |
(1 << IfxGeth_MtlInterruptFlag_averageBitsPerSlot) |
(1 << IfxGeth_MtlInterruptFlag_rxQueueOverflow);
|--> uint32 value = (1 << (flag + 8));
|--> gethSFR->MTL_Q0.INTERRUPT_CONTROL_STATUS.U =
(gethSFR->MTL_Q0.INTERRUPT_CONTROL_STATUS.U & ~mask) | value;
}
// --------------------------------------------------------------
}
其中,相关寄存器位及写入值的含义如下:
-
MTL_OPERATION_MODE.RAA:Receive Arbitration Algorithm,接收队列的调度算法:
-
0:严格优先级(SP);
-
1:负载均衡(WRR);
-
该示例中,Rx 仅包含一条队列,因此不会设置队列调度算法(默认为严格优先级);
-
-
MTL_RXQ0_OPERATION_MODE.RQS:Receive Queue Size,Rx 队列的大小,设置为 2560 字节;
-
MTL_RXQ0_OPERATION_MODE.RSF:Receive Queue Store and Forward,是否启用存储转发,设置为 "1",即启用 Rx 队列的存储转发;
-
MTL_RXQ0_OPERATION_MODE.FEP:Forward Error Packets,设置为 "0",表示丢弃出错的数据包;
-
MTL_RXQ0_OPERATION_MODE.FUP:Forward Undersized Good Packets,设置为 "0",表示允许小于设定值的正常数据包传输;
-
MTL_RXQ_DMA_MAP0:该例程中 daBasedDmaChannelEnabled = FALSE,不会设置 Rx 队列和 DMA 通道的目标地址映射,直接将 Rx 队列 0 映射至 DMA 的通道 0,设置 MTL_RXQ_DMA_MAP0.Q0MDMACH 为 "00";
-
MAC_RXQ_CTRL0.RXQ0EN:使能 Rx 的队列 0,设置为 "01";
-
MTL_Q0_INTERRUPT_CONTROL_STATUS:队列 0 的相关中断是否启用,以及中断状态,该示例中,未启用Rx 队列的 OverFlow 中断,因此无需设置;
7.5.MTL 中断配置
MTL 默认中断优先级为 0,即不启用中断,后续未进行 MTL 中断相关配置,因此 MTL 并不会产生中断:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModuleConfig(IfxGeth_Eth_Config *config, Ifx_GETH *gethSFR)
{
...
const IfxGeth_Eth_Config defaultConfig = {
...
.mtl = {
...
.interrupt = {
.serviceRequest = IfxGeth_ServiceRequest_1,
.priority = 0,
.provider = IfxSrc_Tos_cpu0
}
---------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureMTL(IfxGeth_Eth *geth, IfxGeth_Eth_MtlConfig *mtlConfig)
{
...
// 中断优先级为 0,即禁用中断,不会进行下面的 MTL 中断配置流程
if (mtlConfig->interrupt.priority > 0)
{
volatile Ifx_SRC_SRCR *srcSFR;
// --------------------------------------------------------------
// 获取对应的中断请求节点
srcSFR = IfxGeth_getSrcPointer(geth->gethSFR, mtlConfig->interrupt.serviceRequest);
|--> return &MODULE_SRC.GETH.GETH[0].SR[serviceRequest];
// --------------------------------------------------------------
// --------------------------------------------------------------
// 设置中断优先级、中断请求对象、发送中断清除请求
IfxSrc_init(srcSFR, mtlConfig->interrupt.provider, mtlConfig->interrupt.priority);
|--> src->B.SRPN = priority;
|--> src->B.TOS = typOfService;
|--> IfxSrc_clearRequest(src);
|--> src->B.CLRR = 1;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 允许接收该中断请求节点产生的中断
IfxSrc_enable(srcSFR);
|--> src->B.SRE = 1;
// --------------------------------------------------------------
}
}
8.DMA 配置
IfxGeth_Eth_configureDMA() 执行 Tx/Rx 的 DMA 通道及中断等配置:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initModule(IfxGeth_Eth *geth, IfxGeth_Eth_Config *config)
{
...
/* Configure DMA */
IfxGeth_Eth_configureDMA(geth, &config->dma);
}
8.1.通道数量
该示例中,Tx/Rx 各自仅使用 1 条 DMA 通道,numOfChannels 设置为 Tx/Rx 通道数量较大的一个:
// Libraries/Ethernet/lwip/port/src/netif.c
static void low_level_init(netif_t *netif)
{
...
GethConfig.dma.numOfTxChannels = 1;
GethConfig.dma.numOfRxChannels = 1;
--------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureDMA(IfxGeth_Eth *geth, IfxGeth_Eth_DmaConfig *dmaConfig)
{
uint32 txChannelIndex, rxChannelIndex, channelIndex;
// numOfChannels = 1
uint32 numOfChannels = (dmaConfig->numOfTxChannels >= dmaConfig->numOfRxChannels) ?
dmaConfig->numOfTxChannels :
dmaConfig->numOfRxChannels;
8.2.DMA 基本设置
单次 DMA 传输的字节数量称为 Burst 数量,基本设置包含是否使用地址对齐、采用固定大小的传输数量、采用可变大小的传输数量:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureDMA(IfxGeth_Eth *geth, IfxGeth_Eth_DmaConfig *dmaConfig)
{
...
// --------------------------------------------------------------
/* DMA top level configuration */
// 禁用地址对齐:
// addressAlignedBeatsEnabled = FALSE
IfxGeth_dma_setAddressAlignedBeats(geth->gethSFR,
dmaConfig->addressAlignedBeatsEnabled);
|--> gethSFR->DMA_SYSBUS_MODE.B.AAL = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 不指定传输大小
// fixedBurstEnabled = FALSE
IfxGeth_dma_setFixedBurst(geth->gethSFR, dmaConfig->fixedBurstEnabled);
|--> gethSFR->DMA_SYSBUS_MODE.B.FB = enabled;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 不使用混合传输方式
// mixedBurstEnabled = FALSE
IfxGeth_dma_setMixedBurst(geth->gethSFR, dmaConfig->mixedBurstEnabled);
|--> gethSFR->DMA_SYSBUS_MODE.B.MB = enabled;
// --------------------------------------------------------------
其中,相关寄存器位及设定值的含义如下:
-
DMA_SYSBUS_MODE.AAL:Address-Aligned Beats,"FALSE",禁用地址对齐;
-
DMA_SYSBUS_MODE.FB:Fixed Burst Length ,"FALSE",不指定传输大小;
-
DMA_SYSBUS_MODE.MB:Mixed Burst,"FALSE",不采用混合传输方式;
该例程中,FB 与 MB 均设置为 FALSE,因此 DMA 每次传输的字节数量不固定
8.3.Tx 通道配置
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureDMA(IfxGeth_Eth *geth, IfxGeth_Eth_DmaConfig *dmaConfig)
{
...
// --------------------------------------------------------------
/* TX Channels(s) configuration */
// 禁用 Tx DMA 传输,将状态设置为 Stop
IfxGeth_Eth_stopTransmitters(geth, dmaConfig->numOfTxChannels);
|--> IfxGeth_mac_disableTransmitter(geth->gethSFR);
|--> gethSFR->MAC_CONFIGURATION.B.TE = 0;
|--> IfxGeth_dma_stopTransmitter(geth->gethSFR, (IfxGeth_TxDmaChannel)i);
|--> gethSFR->DMA_CH[channel].TX_CONTROL.B.ST = FALSE;
// --------------------------------------------------------------
for (txChannelIndex = 0; txChannelIndex < dmaConfig->numOfTxChannels; txChannelIndex++)
{
// --------------------------------------------------------------
// 不指定每次 DMA 传输的具体长度
// maxBurstLength = IfxGeth_DmaBurstLength_0 --> 0
IfxGeth_dma_setTxMaxBurstLength(geth->gethSFR,
dmaConfig->txChannel[txChannelIndex].channelId,
dmaConfig->txChannel[txChannelIndex].maxBurstLength);
|--> gethSFR->DMA_CH[channel].TX_CONTROL.B.TXPBL = length;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 初始化 Tx 描述符链表
IfxGeth_Eth_initTransmitDescriptors(geth, &dmaConfig->txChannel[txChannelIndex]);
// --------------------------------------------------------------
}
------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initTransmitDescriptors(IfxGeth_Eth *geth,
IfxGeth_Eth_TxChannelConfig *config)
{
int i;
// --------------------------------------------------------------
// 获取软件定义的 Tx Buffer
// GethConfig.dma.txChannel[0].txBuffer1StartAddress = (uint32 *)&channel0TxBuffer1[0][0]; // user buffer
// buffer1StartAddress = channel0TxBuffer1
uint32 buffer1StartAddress = (uint32)config->txBuffer1StartAddress;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Tx 的 DMA 通道编号
// GethConfig.dma.txChannel[0].channelId = IfxGeth_TxDmaChannel_0;
IfxGeth_TxDmaChannel channelId = config->channelId;
geth->txChannel[channelId].channelId = channelId;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Tx 的描述符链表
// GethConfig.dma.txChannel[0].txDescrList = (IfxGeth_TxDescrList*)&IfxGeth_Eth_txDescrList[0];
// IFX_EXTERN IfxGeth_TxDescrList IfxGeth_Eth_txDescrList[IFXGETH_NUM_MODULES][IFXGETH_NUM_TX_CHANNELS];
geth->txChannel[channelId].txDescrList = config->txDescrList;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Tx Buffer 的大小
// GethConfig.dma.txChannel[0].txBuffer1Size = IFXGETH_MAX_TX_BUFFER_SIZE
// txBuffer1Size = 2560 + 14 + 2
geth->txChannel[channelId].txBuf1Size = (uint16)config->txBuffer1Size;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 获取 Tx 通道 0 的描述符
volatile IfxGeth_TxDescr *descr = IfxGeth_Eth_getBaseTxDescriptor(geth, channelId);
|--> return geth->txChannel[channelId].txDescrList->descr;
// --------------------------------------------------------------
geth->txChannel[channelId].txDescrPtr = descr;
// --------------------------------------------------------------
// 确保 Tx Buffer 为 4 字节对齐
// 这里就体现了为什么 Buffer 大小是 2560(数据大小) + 14(Header Size) + 2(为了对齐)
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, (config->txBuffer1Size) % 4 == 0);
// --------------------------------------------------------------
// --------------------------------------------------------------
// 初始化环形缓冲区
/* Initialize descriptors in ring mode */
for (i = 0; i < IFXGETH_MAX_TX_DESCRIPTORS; i++)
{
descr->TDES0.U = (uint32)(config->txBuffer1Size * i) + buffer1StartAddress;
descr->TDES1.U = 0; /* buffer2 not used */
descr->TDES2.R.B1L = config->txBuffer1Size;
descr->TDES2.R.VTIR = 0; /* do not use VLAN tag */
descr->TDES2.R.B2L = 0; /* buffer2 not used */
descr->TDES2.R.TTSE_TMWD = 0; /* timestamp not used */
descr->TDES2.R.IOC = 0; /* interrupt disabled */
/* TDES3 will be configured while trasmitting each packet */
descr = &descr[1];
}
// --------------------------------------------------------------
/* rest the current pointer to base pointer in the handle */
geth->txChannel[channelId].txDescrPtr = IfxGeth_Eth_getBaseTxDescriptor(geth, channelId);
// --------------------------------------------------------------
// 设置 Tx DMA 通道 0 的描述符地址
IfxGeth_dma_setTxDescriptorListAddress(geth->gethSFR,
channelId,
(uint32)IfxGeth_Eth_getBaseTxDescriptor(geth, channelId));
|--> gethSFR->DMA_CH[channel].TXDESC_LIST_ADDRESS.U = address;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 设置环形链表的长度
// IFXGETH_MAX_TX_DESCRIPTORS = 8
IfxGeth_dma_setTxDescriptorRingLength(geth->gethSFR,
channelId,
(IFXGETH_MAX_TX_DESCRIPTORS - 1));
|--> gethSFR->DMA_CH[channel].TXDESC_RING_LENGTH.U = length;
// --------------------------------------------------------------
}
其中,相关寄存器位及设定值的含义如下:
-
MAC_CONFIGURATION.TE:Transmitter Enable,置 "0" 禁用 Tx DMA 传输,DMA 完成当前传输任务后禁用;
-
DMA_CHi_TX_CONTROL.ST:Start or Stop Transmission Command,置 "0" 会使得 DMA 在完成当前传输任务后进入 STOP 状态;
-
DMA_CHi_TX_CONTROL.TXPBL:Transmit Programmable Burst Length,每次 DMA 传输的具体长度,"0" 表示不指定具体长度;
-
DMA_CHi_TXDESC_LIST_ADDRESS.TDESLA:Start of Transmit List,存储 Tx 描述符链表的地址;
-
DMA_CHi_TXDESC_RING_LENGTH.TDRL:Transmit Descriptor Ring Length,环形描述符链表中,描述符节点的个数,"[0~7]";
8.4.Rx 通道配置
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureDMA(IfxGeth_Eth *geth, IfxGeth_Eth_DmaConfig *dmaConfig)
{
...
/* RX Channels(s) configuration */
for (rxChannelIndex = 0; rxChannelIndex < dmaConfig->numOfRxChannels; rxChannelIndex++)
{
// 不指定每次 DMA 传输的具体长度
// maxBurstLength = IfxGeth_DmaBurstLength_0 --> 0
IfxGeth_dma_setRxMaxBurstLength(geth->gethSFR,
dmaConfig->rxChannel[rxChannelIndex].channelId,
dmaConfig->rxChannel[rxChannelIndex].maxBurstLength);
|--> gethSFR->DMA_CH[channel].RX_CONTROL.B.RXPBL = length;
IfxGeth_Eth_initReceiveDescriptors(geth, &dmaConfig->rxChannel[rxChannelIndex]);
}
--------------------------------------------------------------------------------------
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_initReceiveDescriptors(IfxGeth_Eth *geth, IfxGeth_Eth_RxChannelConfig *config)
{
int i;
// --------------------------------------------------------------
// 软件定义的 Rx Buffer 的起始地址
// uint8 channel0RxBuffer1[IFXGETH_MAX_RX_DESCRIPTORS][IFXGETH_MAX_RX_BUFFER_SIZE];
// GethConfig.dma.rxChannel[0].rxBuffer1StartAddress = (uint32 *)&channel0RxBuffer1[0][0]; // user buffer
uint32 buffer1StartAddress = (uint32)config->rxBuffer1StartAddress;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Rx DMA 的通道编号
// GethConfig.dma.rxChannel[0].channelId = IfxGeth_RxDmaChannel_0;
IfxGeth_RxDmaChannel channelId = config->channelId;
geth->rxChannel[channelId].channelId = channelId;
// --------------------------------------------------------------
// --------------------------------------------------------------
// Rx 的描述符链表
// GethConfig.dma.rxChannel[0].rxDescrList = (IfxGeth_RxDescrList *)&IfxGeth_Eth_rxDescrList[0];
geth->rxChannel[channelId].rxDescrList = config->rxDescrList;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 从 Rx 描述符链表中获取通道 0 的描述符节点
volatile IfxGeth_RxDescr *descr = IfxGeth_Eth_getBaseRxDescriptor(geth, channelId);
|--> return geth->rxChannel[channelId].rxDescrList->descr;
// --------------------------------------------------------------
geth->rxChannel[channelId].rxDescrPtr = descr;
// --------------------------------------------------------------
// 确保 Rx 的软件 Buffer 按照 4 字节对齐
IFX_ASSERT(IFX_VERBOSE_LEVEL_ERROR, (config->rxBuffer1Size) % 4 == 0);
// --------------------------------------------------------------
// --------------------------------------------------------------
// 初始化 Rx 的描述符(环形链表)
/* Initialize descriptors in ring mode */
for (i = 0; i < IFXGETH_MAX_RX_DESCRIPTORS; i++)
{
descr->RDES0.U = (uint32)(config->rxBuffer1Size * i) + buffer1StartAddress;
descr->RDES2.U = 0; /* buffer2 not used */
descr->RDES3.R.BUF1V = 1; /* buffer 1 valid */
descr->RDES3.R.BUF2V = 0; /* buffer 2 not valid */
descr->RDES3.R.IOC = 1; /* interrupt enabled */
descr->RDES3.R.OWN = 1; /* owned by DMA */
descr = &descr[1];
}
// --------------------------------------------------------------
/* rest the current pointer to base pointer in the handle */
geth->rxChannel[channelId].rxDescrPtr = IfxGeth_Eth_getBaseRxDescriptor(geth, channelId);
// --------------------------------------------------------------
// 设置 Rx Buffer 的大小,IFX_GETH_DMA_CH_RX_CONTROL_RBSZ_13_Y_MSK = 0xFFF
/* set the buffer size */
IfxGeth_dma_setRxBufferSize(geth->gethSFR, channelId, config->rxBuffer1Size);
|--> gethSFR->DMA_CH[channel].RX_CONTROL.B.RBSZ_13_Y = (uint32)((size >> 2) & IFX_GETH_DMA_CH_RX_CONTROL_RBSZ_13_Y_MSK);
// --------------------------------------------------------------
// --------------------------------------------------------------
// 设置 Rx 描述符链表的地址
IfxGeth_dma_setRxDescriptorListAddress(geth->gethSFR, channelId, (uint32)IfxGeth_Eth_getBaseRxDescriptor(geth, channelId));
|--> gethSFR->DMA_CH[channel].RXDESC_LIST_ADDRESS.U = (uint32)address;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 设置 Rx 描述符链表的尾指针
IfxGeth_dma_setRxDescriptorTailPointer(geth->gethSFR, channelId, (uint32)descr);
|--> gethSFR->DMA_CH[channel].RXDESC_TAIL_POINTER.U = address;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 设置 Rx 描述符链表的长度,IFXGETH_MAX_RX_DESCRIPTORS = 8
IfxGeth_dma_setRxDescriptorRingLength(geth->gethSFR, channelId, (IFXGETH_MAX_RX_DESCRIPTORS - 1));
|--> gethSFR->DMA_CH[channel].RXDESC_RING_LENGTH.U = length;
// --------------------------------------------------------------
}
其中,相关寄存器位及设定值的含义如下:
-
DMA_CHi_RX_CONTROL.RXPBL:Receive Programmable Burst Length,每次 DMA 传输的具体长度,"0" 表示不指定具体长度;
-
DMA_CHi_RX_CONTROL.RBSZ_13_y:Receive Buffer size High,Rx Buffer 的大小;
-
DMA_CHi_RXDESC_LIST_ADDRESS.RDESLA:Start of Receive List,Rx 描述符链表的起始地址;
-
DMA_CHi_RXDESC_TAIL_POINTER.RDTP:Receive Descriptor Tail Pointer,Rx 链表的尾指针;
-
DMA_CHi_RXDESC_RING_LENGTH.RDRL:Receive Descriptor Ring Length,Rx 描述符环形链表的长度,其长度为 "[0~7]";
8.5.DMA 中断配置
该示例中,Tx/Rx 各自仅包含 1 条 DMA 通道,配置该 DMA 通道的中断:
// Libraries/iLLD/TC39B/Tricore/Geth/Eth/IfxGeth_Eth.c
void IfxGeth_Eth_configureDMA(IfxGeth_Eth *geth, IfxGeth_Eth_DmaConfig *dmaConfig)
{
...
/* initialise the selected interrupts */
for (channelIndex = 0; channelIndex < numOfChannels; channelIndex++)
{
// --------------------------------------------------------------
// 清除 DMA 通道 0 的所有中断标记
IfxGeth_dma_clearAllInterruptFlags(geth->gethSFR, dmaConfig->txInterrupt[channelIndex].channelId);
|--> gethSFR->DMA_CH[channelId].STATUS.U = 0;
// --------------------------------------------------------------
// GethConfig.dma.txInterrupt[0].priority = ISR_PRIORITY_GETH_TX; --> 100
/* Transmit interrupts */
if ((dmaConfig->txInterrupt[channelIndex].priority > 0) || (dmaConfig->txInterrupt[channelIndex].provider == IfxSrc_Tos_dma))
{
// --------------------------------------------------------------
// 使能 DMA 通道 0 的 Tx 中断
// DMA_CHi_INTERRUPT_ENABLE.TIE = 1
IfxGeth_dma_enableInterrupt(geth->gethSFR, dmaConfig->txInterrupt[channelIndex].channelId, IfxGeth_DmaInterruptFlag_transmitInterrupt);
|--> uint32 value = (1 << flag); // flag --> IfxGeth_DmaInterruptFlag_transmitInterrupt --> 0
|--> gethSFR->DMA_CH[channelId].INTERRUPT_ENABLE.U |= value;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 获取中断请求节点
volatile Ifx_SRC_SRCR *srcSFR;
srcSFR = IfxGeth_getSrcPointer(geth->gethSFR, (IfxGeth_ServiceRequest)((uint32)IfxGeth_ServiceRequest_2 + (uint32)dmaConfig->txInterrupt[channelIndex].channelId));
|--> return &MODULE_SRC.GETH.GETH[0].SR[serviceRequest];
// --------------------------------------------------------------
// --------------------------------------------------------------
// 初始化中断请求节点
IfxSrc_init(srcSFR, dmaConfig->txInterrupt[channelIndex].provider, dmaConfig->txInterrupt[channelIndex].priority);
|--> src->B.SRPN = priority; // 写入中断优先级,100
|--> src->B.TOS = typOfService; // 写入中断请求对象,1 --> DMA
|--> IfxSrc_clearRequest(src);
|--> src->B.CLRR = 1; // 清除该节点的中断请求
IfxSrc_enable(srcSFR);
|-> src->B.SRE = 1; // 允许接收该节点的中断请求
// --------------------------------------------------------------
}
// GethConfig.dma.rxInterrupt[0].priority = ISR_PRIORITY_GETH_RX; --> 101
/* Receive interrupts */
if ((dmaConfig->rxInterrupt[channelIndex].priority > 0) || (dmaConfig->rxInterrupt[channelIndex].provider == IfxSrc_Tos_dma))
{
// --------------------------------------------------------------
// 使能 DMA 通道 0 的 Rx 中断
// DMA_CHi_INTERRUPT_ENABLE.RIE
IfxGeth_dma_enableInterrupt(geth->gethSFR, dmaConfig->rxInterrupt[channelIndex].channelId, IfxGeth_DmaInterruptFlag_receiveInterrupt);
|--> uint32 value = (1 << flag); // flag --> IfxGeth_DmaInterruptFlag_receiveInterrupt --> 6
|--> gethSFR->DMA_CH[channelId].INTERRUPT_ENABLE.U |= value;
// --------------------------------------------------------------
// --------------------------------------------------------------
// 获取中断请求节点
volatile Ifx_SRC_SRCR *srcSFR;
srcSFR = IfxGeth_getSrcPointer(geth->gethSFR, (IfxGeth_ServiceRequest)((uint32)IfxGeth_ServiceRequest_6 + (uint32)dmaConfig->rxInterrupt[channelIndex].channelId));
|--> |--> return &MODULE_SRC.GETH.GETH[0].SR[serviceRequest];
// --------------------------------------------------------------
// --------------------------------------------------------------
// 初始化中断请求节点
IfxSrc_init(srcSFR, dmaConfig->rxInterrupt[channelIndex].provider, dmaConfig->rxInterrupt[channelIndex].priority);
|--> src->B.SRPN = priority; // 写入中断优先级,101
|--> src->B.TOS = typOfService; // 写入中断请求对象,1 --> DMA
|--> IfxSrc_clearRequest(src);
|--> src->B.CLRR = 1; // 清除该节点的中断请求
IfxSrc_enable(srcSFR);
|-> src->B.SRE = 1; // 允许接收该节点的中断请求
// --------------------------------------------------------------
其中,相关寄存器位及设定值的含义如下:
-
DMA_CHi_STATUS:该寄存器的各个位置 "1",指示当前有哪种类型的中断产生;
-
DMA_CHi_INTERRUPT_ENABLE.TIE:Transmit Interrupt Enable,使能发送中断;
-
DMA_CHi_INTERRUPT_ENABLE.RIE:Receive Interrupt Enable,使能接收中断;
-
SRC.SRPN:Service Request Priority Number,中断优先级;
-
SRC.TOS:Type of Service Control,中断请求对象;
-
SRC.CLRR:Request Clear Bit,清除该节点的中断请求;
-
SRC.SRE:Service Request Enable,允许接收该节点的中断请求;
更多推荐



所有评论(0)