关键词

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以太网例程 - 1.概览

TC397以太网例程 - 2.STM 定时器初始化

TC397以太网例程 - 3.LwIP 配置及初始化

TC397以太网例程 - 4.ASCLIN 串口配置

TC397以太网例程 - 5.IP 地址声明

TC397以太网例程 - 6.内存 & 协议等初始化

TC397以太网例程 - 7.netif 网卡配置

TC397以太网例程 - 8.硬件初始化

TC397以太网例程 - 9.基本设置

TC397以太网例程 - 10.默认/用户配置

TC397以太网例程 - 11.RTL8211F 复位

TC397以太网例程 - 12.GETH 初始化

TC397以太网例程 - 13.PHY 初始化

TC397以太网例程 - 14.Tx/Rx 使能

TC397以太网例程 - 15.其他配置

TC397以太网例程 - 16.ECHO 应用 - 初始化

TC397以太网例程 - 17.ECHO 应用 - 轮询定时器

TC397以太网例程 - 18.ECHO 应用 - 接收报文


目录

1.获取 GETH 寄存器组

2.使能 GETH 模块

3.设置接口引脚(RGMII)

3.1.输出引脚

3.2.输入引脚

4.复位 GETH

5.复位 DMA

6.MAC 配置

6.1.工作模式

6.2.连接速率

6.3.以太网前导码

6.4.数据包大小

6.5.是否去除 CRC

6.6.是否启用 CRC 校验

6.7.是否启用网络环回

6.8.禁用监听模式

6.9.禁用组播

6.10.设置 MAC 地址

7.MTL 配置

7.1.队列数量

7.2.清除中断标志

7.3.Tx 队列配置

7.4.Rx 队列设置

7.5.MTL 中断配置

8.DMA 配置

8.1.通道数量

8.2.DMA 基本设置

8.3.Tx 通道配置

8.4.Rx 通道配置

8.5.DMA 中断配置


// 函数调用栈
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 = &ETH_TXCLK_PIN,     /* TXCLK */
                                   .txd0 = &ETH_TXD0_PIN,       /* TXD0 */
                                   .txd1 = &ETH_TXD1_PIN,       /* TXD1 */
                                   .txd2 = &ETH_TXD2_PIN,       /* TXD2 */
                                   .txd3 = &ETH_TXD3_PIN,       /* TXD3 */
                                   .txCtl = &ETH_TXCTL_PIN,     /* TXCTL */
                                   .rxClk = &ETH_RXCLK_PIN,     /* RXCLK */
                                   .rxd0 = &ETH_RXD0_PIN,       /* RXD0 */
                                   .rxd1 = &ETH_RXD1_PIN,       /* RXD1 */
                                   .rxd2 = &ETH_RXD2_PIN,       /* RXD2 */
                                   .rxd3 = &ETH_RXD3_PIN,       /* RXD3 */
                                   .rxCtl = &ETH_RXCTL_PIN,     /* RXCTL */
                                   .mdc = &ETH_MDC_PIN,         /* MDC */
                                   .mdio = &ETH_MDIO_PIN,       /* MDIO */
                                   .grefClk = &ETH_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,允许接收该节点的中断请求;


下一篇:TC397以太网例程 - 14.Tx/Rx 使能

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐