硬汉嵌入式论坛

 找回密码
 立即注册
查看: 296|回复: 7
收起左侧

[NetX] 有没有坛友用过AT32F437移植NetXDuo,一直ping不通,没招了来求助

[复制链接]

5

主题

16

回帖

31

积分

新手上路

积分
31
发表于 2025-10-14 19:36:03 | 显示全部楼层 |阅读模式

/**
  **************************************************************************
  * @file     netx_glue_at32_emac.c
  * @brief    NetX Duo driver for Artery AT32 series EMAC controller.
  * @version  V1.0.0
  * @date     2025-10-12
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * This driver is a glue layer connecting the NetX Duo TCP/IP stack with
  * the Artery AT32 low-level EMAC driver.
  * The logic for DMA descriptor management is heavily based on the official
  * Artery LwIP ethernetif.c driver.
  *
  **************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "nx_api.h"
#include "at32f435_437_emac.h"
#include "nx_arp.h"
#include "wk_emac.h"
#include "commons.h"

/* Defines -------------------------------------------------------------------*/
#define IFNAME0 'a'
#define IFNAME1 't'

/* Number of DMA Descriptors */
#define EMAC_RXBUFNB        6
#define EMAC_TXBUFNB        6

/* Shift constant for extracting frame length from Rx descriptor */
#define EMAC_DMARxDesc_FrameLengthShift  16


/* Global Variables ----------------------------------------------------------*/
/* NetX Duo IP and Packet Pool instances - MUST be defined in the application */
extern NX_IP              ip_0;
extern NX_PACKET_POOL     pool_0;

/* DMA descriptors and buffers */
static emac_dma_desc_type  DMARxDscrTab[EMAC_RXBUFNB] __attribute__((aligned(4)));
static emac_dma_desc_type  DMATxDscrTab[EMAC_TXBUFNB] __attribute__((aligned(4)));
static uint8_t Rx_Buff[EMAC_RXBUFNB][EMAC_MAX_PACKET_LENGTH] __attribute__((aligned(4)));
static uint8_t Tx_Buff[EMAC_TXBUFNB][EMAC_MAX_PACKET_LENGTH] __attribute__((aligned(4)));

/* MAC Address storage */
static uint8_t MACaddr[6] = {0x00, 0x80, 0xE1, 0x00, 0x00, 0x00};

/* Structure for managing received frames, ported from LwIP driver */
typedef struct{
    uint32_t length;
    uint32_t buffer;
    emac_dma_desc_type *descriptor;
    emac_dma_desc_type *rx_fs_desc; /* First segment descriptor */
emac_dma_desc_type *rx_ls_desc; /* Last segment descriptor */
uint32_t g_seg_count;
}FrameTypeDef;

static FrameTypeDef rx_frame;

/* Externs for low-level driver variables and functions from at32_emac.c */
extern emac_dma_desc_type  *dma_tx_desc_to_set;
extern emac_dma_desc_type  *dma_rx_desc_to_get;

/* These functions are helpers from the LwIP driver, assumed to be available */
error_status emac_rxpkt_chainmode(void)
{
    /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if((dma_rx_desc_to_get->status & EMAC_DMARXDESC_OWN) != (u32)RESET)
    {
        /* return error: own bit set */
return ERROR;
    }
    if((dma_rx_desc_to_get->status & EMAC_DMARXDESC_LS) != (u32)RESET)
    {
        rx_frame.g_seg_count ++;
        if(rx_frame.g_seg_count == 1)
        {
            rx_frame.rx_fs_desc = dma_rx_desc_to_get;
        }
        rx_frame.rx_ls_desc = dma_rx_desc_to_get;
        rx_frame.length = ((dma_rx_desc_to_get->status & EMAC_DMARXDESC_FL) >> EMAC_DMARxDesc_FrameLengthShift) - 4;
        rx_frame.buffer = rx_frame.rx_fs_desc->buf1addr;

        /* Selects the next DMA Rx descriptor list for next buffer to read */
dma_rx_desc_to_get = (emac_dma_desc_type*) (dma_rx_desc_to_get->buf2nextdescaddr);

        return SUCCESS;
    }
    else if((dma_rx_desc_to_get->status & EMAC_DMARXDESC_FS) != (u32)RESET)
    {
        rx_frame.g_seg_count = 1;
        rx_frame.rx_fs_desc = dma_rx_desc_to_get;
        rx_frame.rx_ls_desc = NULL;
        dma_rx_desc_to_get = (emac_dma_desc_type*) (dma_rx_desc_to_get->buf2nextdescaddr);
    }
    else
{
        rx_frame.g_seg_count ++;
        dma_rx_desc_to_get = (emac_dma_desc_type*) (dma_rx_desc_to_get->buf2nextdescaddr);
    }

    return ERROR;
}

error_status emac_txpkt_chainmode(uint32_t FrameLength)
{
    uint32_t buf_cnt = 0, index = 0;

    /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
if((dma_tx_desc_to_set->status & EMAC_DMATXDESC_OWN) != (u32)RESET)
    {
        /* Return ERROR: OWN bit set */
return ERROR;
    }

    if(FrameLength == 0)
    {
        return ERROR;
    }

    if(FrameLength > EMAC_MAX_PACKET_LENGTH)
    {
        buf_cnt = FrameLength / EMAC_MAX_PACKET_LENGTH;
        if(FrameLength % EMAC_MAX_PACKET_LENGTH)
        {
            buf_cnt += 1;
        }
    }
    else
{
        buf_cnt = 1;
    }

    if(buf_cnt == 1)
    {
        /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */
dma_tx_desc_to_set->status |= EMAC_DMATXDESC_LS | EMAC_DMATXDESC_FS;

        /* Setting the Frame Length: bits[12:0] */
dma_tx_desc_to_set->controlsize = (FrameLength & EMAC_DMATXDESC_TBS1);

        /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
dma_tx_desc_to_set->status |= EMAC_DMATXDESC_OWN;

        /* Selects the next DMA Tx descriptor list for next buffer to send */
dma_tx_desc_to_set = (emac_dma_desc_type*) (dma_tx_desc_to_set->buf2nextdescaddr);
    }
    else
{
        for(index = 0; index < buf_cnt; index ++)
        {
            /* clear first and last segments */
dma_tx_desc_to_set->status &= ~(EMAC_DMATXDESC_LS | EMAC_DMATXDESC_FS);

            /* set first segments */
if(index == 0)
            {
                dma_tx_desc_to_set->status |= EMAC_DMATXDESC_FS;
            }

            /* set size */
dma_tx_desc_to_set->controlsize = (EMAC_MAX_PACKET_LENGTH & EMAC_DMATXDESC_TBS1);

            /* set last segments */
if(index == (buf_cnt - 1))
            {
                dma_tx_desc_to_set->status |= EMAC_DMATXDESC_LS;
                dma_tx_desc_to_set->controlsize = ((FrameLength - ((buf_cnt-1) * EMAC_MAX_PACKET_LENGTH)) & EMAC_DMATXDESC_TBS1);
            }

            /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
dma_tx_desc_to_set->status |= EMAC_DMATXDESC_OWN;

            /* Selects the next DMA Tx descriptor list for next buffer to send */
dma_tx_desc_to_set = (emac_dma_desc_type*) (dma_tx_desc_to_set->buf2nextdescaddr);

        }
    }

    /* When Tx Buffer unavailable flag is set: clear it and resume transmission */
if(emac_dma_flag_get(EMAC_DMA_TBU_FLAG))
    {
        /* Clear TBUS ETHERNET DMA flag */
emac_dma_flag_clear(EMAC_DMA_TBU_FLAG);
        /* Resume DMA transmission*/
EMAC_DMA->tpd_bit.tpd = 0;
    }

    return SUCCESS;
}

u32 emac_getcurrenttxbuffer(void)
{
    /* Return Buffer address */
return (dma_tx_desc_to_set->buf1addr);
}

/**
  * @brief  Updates the link states by reading the PHY status register.
  * @param  none
  * @retval link state: 0 for link down or error, 1 for link up.
  */
uint16_t link_update(void)
{
    uint16_t link_data, link_state;
    if(emac_phy_register_read(PHY_ADDRESS, PHY_STATUS_REG, &link_data) == ERROR)
    {
        return ERROR;
    }

    link_state = (link_data & PHY_LINKED_STATUS_BIT)>>2;
    return link_state;
}


/* Forward declarations */
static VOID at32_emac_driver_initialize(NX_IP_DRIVER *driver_req);
static VOID at32_emac_driver_enable(NX_IP_DRIVER *driver_req);
static VOID at32_emac_driver_disable(NX_IP_DRIVER *driver_req);
static VOID at32_emac_driver_packet_send(NX_IP_DRIVER *driver_req);
static VOID at32_emac_driver_get_status(NX_IP_DRIVER *driver_req);


/**
  * @brief  Sets the MAC address for the driver.
  * @note   This function should be called BEFORE nx_ip_create().
  * @param  mac_addr Pointer to a 6-byte MAC address array.
  * @retval None
  */
void netx_mac_address_set(uint8_t* mac_addr)
{
    for(int i = 0; i < 6; i++)
    {
        MACaddr = mac_addr;
    }
}


/**
  * @brief  The main entry point for the NetX Duo AT32 EMAC driver.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
VOID at32_emac_driver_entry(NX_IP_DRIVER *driver_req)
{
    switch (driver_req->nx_ip_driver_command)
    {
        case NX_LINK_INITIALIZE:
            at32_emac_driver_initialize(driver_req);
            break;

        case NX_LINK_ENABLE:
            at32_emac_driver_enable(driver_req);
            break;

        case NX_LINK_DISABLE:
            at32_emac_driver_disable(driver_req);
            break;

        case NX_LINK_ARP_SEND:
        case NX_LINK_RARP_SEND:
        case NX_LINK_PACKET_SEND:
            at32_emac_driver_packet_send(driver_req);
            break;

        case NX_LINK_GET_STATUS:
            at32_emac_driver_get_status(driver_req);
            break;

        default:
            /* Mark the request as not handled */
driver_req->nx_ip_driver_status = NX_UNHANDLED_COMMAND;
            break;
    }
}

/**
  * @brief  Handles the NX_LINK_INITIALIZE command.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
static VOID at32_emac_driver_initialize(NX_IP_DRIVER *driver_req)
{
    NX_IP *ip_ptr = driver_req->nx_ip_driver_ptr;
    UINT index;

    /* --- Logic ported from low_level_init() --- */
    /* Set up the MAC address in the hardware */
emac_local_address_set(MACaddr);

    /* Set up the MAC address in the NetX IP interface */
ip_ptr->nx_ip_interface[0].nx_interface_physical_address_msw = (ULONG)((MACaddr[0] << 8) | MACaddr[1]);
    ip_ptr->nx_ip_interface[0].nx_interface_physical_address_lsw = (ULONG)((MACaddr[2] << 24) | (MACaddr[3] << 16) | (MACaddr[4] << 8) | MACaddr[5]);

    /* Set the Maximum Transfer Unit (MTU) */
ip_ptr->nx_ip_interface[0].nx_interface_ip_mtu_size = 1500;

    /* Initialize Tx Descriptors list: Chain Mode */
emac_dma_descriptor_list_address_set(EMAC_DMA_TRANSMIT, DMATxDscrTab, &Tx_Buff[0][0], EMAC_TXBUFNB);

    /* Initialize Rx Descriptors list: Chain Mode */
emac_dma_descriptor_list_address_set(EMAC_DMA_RECEIVE, DMARxDscrTab, &Rx_Buff[0][0], EMAC_RXBUFNB);

    /* Enable Ethernet Rx interrupt for each descriptor */
for(index = 0; index < EMAC_RXBUFNB; index++)
    {
        emac_dma_rx_desc_interrupt_config(&DMARxDscrTab[index], TRUE);
    }

#ifdef CHECKSUM_BY_HARDWARE
    /* Enable checksum offloading in Tx descriptors */
    for(index = 0; index < EMAC_TXBUFNB; index++)
    {
      DMATxDscrTab[index].status |= EMAC_DMATXDESC_CIC_TUI_FULL;
    }
#endif
/* Initialize the received frame segment counter */
rx_frame.g_seg_count = 0;

    /* Report success to NetX Duo */
driver_req->nx_ip_driver_status = NX_SUCCESS;
}

/**
  * @brief  Handles the NX_LINK_ENABLE command.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
static VOID at32_emac_driver_enable(NX_IP_DRIVER *driver_req)
{
    /* Enable MAC and DMA transmission and reception */
emac_start();

    /* Set the link status to UP in the IP instance */
driver_req->nx_ip_driver_ptr->nx_ip_interface[0].nx_interface_link_up = NX_TRUE;

    /* Report success */
driver_req->nx_ip_driver_status = NX_SUCCESS;
}

/**
  * @brief  Handles the NX_LINK_DISABLE command.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
static VOID at32_emac_driver_disable(NX_IP_DRIVER *driver_req)
{
    /* Disable MAC and DMA transmission and reception */
emac_stop();

    /* Set the link status to DOWN in the IP instance */
driver_req->nx_ip_driver_ptr->nx_ip_interface[0].nx_interface_link_up = NX_FALSE;

    /* Report success */
driver_req->nx_ip_driver_status = NX_SUCCESS;
}

/**
  * @brief  Handles packet transmission commands.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
static VOID at32_emac_driver_packet_send(NX_IP_DRIVER *driver_req)
{
    NX_PACKET *packet_ptr = driver_req->nx_ip_driver_packet;
    NX_PACKET *current_packet;
    uint8_t *buffer;
    uint32_t buffer_offset = 0;

    /* --- Logic ported from low_level_output() --- */
    /* 1. Pre-check: is the current DMA descriptor available by CPU? */
if((dma_tx_desc_to_set->status & EMAC_DMATXDESC_OWN) != RESET)
    {
        /* The DMA is busy. Report queue depth.
           NetX will retain the packet and retry later. */
driver_req->nx_ip_driver_status = NX_TX_QUEUE_DEPTH;
        return;
    }

    /* Get the standard AT32 EMAC buffer address */
buffer = (uint8_t *)emac_getcurrenttxbuffer();

    /* 2. Copy data from NetX packet chain to EMAC DMA buffer */
for(current_packet = packet_ptr; current_packet != NULL; current_packet = current_packet->nx_packet_next)
    {
        /* Note: This logic assumes the total packet length fits in one EMAC buffer
           (EMAC_MAX_PACKET_LENGTH, usually 1500-1536 bytes).
           If you use Jumbo frames, the complex multi-buffer copy logic from
           lwIP's ethernetif.c must be ported here. */
if ((buffer_offset + current_packet->nx_packet_length) <= EMAC_MAX_PACKET_LENGTH)
        {
            memcpy(buffer + buffer_offset, current_packet->nx_packet_prepend_ptr, current_packet->nx_packet_length);
            buffer_offset += current_packet->nx_packet_length;
        }
        else
{
            /* Packet exceeds buffer size. This shouldn't happen if MTU is set correctly.
               Drop packet and report success to avoid NetX retrying an impossible packet. */
nx_packet_release(packet_ptr);
            driver_req->nx_ip_driver_status = NX_SUCCESS;
            return;
        }
    }

    /* 3. Trigger the DMA to send the packet via underlying AT32 driver */
if (emac_txpkt_chainmode(packet_ptr->nx_packet_length) == SUCCESS)
    {
        /* Success: DMA now owns the buffer.
           NetX is done with this packet, so we release it back to the pool. */
nx_packet_release(packet_ptr);
        driver_req->nx_ip_driver_status = NX_SUCCESS;
    }
    else
{
        /* Hardware failed to accept the packet (e.g., descriptor became owned by DMA
           between step 1 and 3, or length was 0).
           Report queue depth so NetX retries sending this packet later.
           DO NOT release the packet here. */
driver_req->nx_ip_driver_status = NX_TX_QUEUE_DEPTH; /* Replaced NX_HARDWARE_ERROR */
}
}


/**
  * @brief  Handles the NX_LINK_GET_STATUS command.
  * @param  driver_req Pointer to the driver request structure.
  * @retval None
  */
static VOID at32_emac_driver_get_status(NX_IP_DRIVER *driver_req)
{
    /* Use the low-level link update function */
if (link_update())
    {
        *(driver_req->nx_ip_driver_return_ptr) = NX_TRUE;
    }
    else
{
        *(driver_req->nx_ip_driver_return_ptr) = NX_FALSE;
    }

    driver_req->nx_ip_driver_status = NX_SUCCESS;
}


/**
  * @brief  The interrupt handler for the EMAC.
  * @note   This function should be called from the EMAC_IRQHandler in your interrupt vector file.
  * @param  None
  * @retval None
  */
void netx_emac_interrupt_handler(void)
{
    /* Check for the Receive Interrupt flag */
if (emac_dma_flag_get(EMAC_DMA_RI_FLAG) != RESET)
    {
        /* Process all received frames in the chain */
while(emac_rxpkt_chainmode() == SUCCESS)
        {
            NX_PACKET *packet_ptr = NX_NULL;
            UINT status;
            rtt_printf("[EMAC_IRQ] Frame received, driver length = %lu\r\n", rx_frame.length);
            /* Allocate a NetX packet to hold the received data */
status = nx_packet_allocate(&pool_0, &packet_ptr, NX_RECEIVE_PACKET, NX_NO_WAIT);
            if (status != NX_SUCCESS)
            {
                /* Packet pool is empty, we have to drop this frame. */
                /* TODO: Add error statistics tracking here. */
}
            else
{
                /* Copy data from the DMA buffer into the newly allocated NetX packet */
status = nx_packet_data_append(packet_ptr, (uint8_t *)rx_frame.buffer, rx_frame.length, &pool_0, NX_NO_WAIT);
                if (status != NX_SUCCESS)
                {
                    /* Failed to append data, release the packet and drop the frame */
nx_packet_release(packet_ptr);
                }
                else
{
                    /* Data copied successfully, determine the packet type from the Ethernet header */
USHORT ether_type = (((USHORT)(*(packet_ptr->nx_packet_prepend_ptr + 12))) << 8) | ((USHORT)(*(packet_ptr->nx_packet_prepend_ptr + 13)));

                    /* Hand off the packet to the appropriate NetX Duo receiver */
if (ether_type == 0x0800) /* IP Packet */
{
                        rtt_printf("[EMAC_IRQ] IP Packet Received.\r\n"); // 添加日志
_nx_ip_packet_receive(&ip_0, packet_ptr);
                    }
                    else if (ether_type == 0x0806) /* ARP Packet */
{
                        rtt_printf("[EMAC_IRQ] ARP Packet Received.\r\n"); // 添加日志
_nx_arp_packet_receive(&ip_0, packet_ptr);
                    }
                    else
{
                        /* Unsupported packet type, release it */
rtt_printf("[EMAC_IRQ] Unknown Packet Type: 0x%04X\r\n", ether_type); // 添加日志
nx_packet_release(packet_ptr);
                    }
                }
            }

            /* Regardless of success or failure, give ownership of the DMA descriptors back to the hardware */
emac_dma_desc_type* dma_rx_desc = rx_frame.rx_fs_desc;
            UINT i;
            for(i = 0; i < rx_frame.g_seg_count; i++)
            {
                dma_rx_desc->status |= EMAC_DMARXDESC_OWN;
                dma_rx_desc = (emac_dma_desc_type*)(dma_rx_desc->buf2nextdescaddr);
            }
            rx_frame.g_seg_count = 0;
        }

        /* Clear the main interrupt flags after processing all packets */
emac_dma_flag_clear(EMAC_DMA_RI_FLAG);
        emac_dma_flag_clear(EMAC_DMA_NIS_FLAG);
    }

    /* Handle other EMAC interrupts if necessary (e.g., Tx complete, errors) */
    /* if(emac_dma_flag_get(EMAC_DMA_TI_FLAG) != RESET) { ... } */
}



这是写的一个glue,发现打断点一直不会进入at32_emac_driver_packet_send
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119430
QQ
发表于 2025-10-15 11:42:18 | 显示全部楼层
考虑用wireshark抓包下,看看是不是完全没反应。
回复

使用道具 举报

5

主题

16

回帖

31

积分

新手上路

积分
31
 楼主| 发表于 2025-10-15 11:54:24 | 显示全部楼层
eric2013 发表于 2025-10-15 11:42
考虑用wireshark抓包下,看看是不是完全没反应。

昨晚用wireshark看了,没有send出任何东西,没有响应电脑的arp包。
调试看了一下,只有初始化的时候进入了三次nx_ip_create指定的entry,不知道为什么收到arp包的时候没进入entry的SEND case
回复

使用道具 举报

5

主题

16

回帖

31

积分

新手上路

积分
31
 楼主| 发表于 2025-10-15 11:57:34 | 显示全部楼层
eric2013 发表于 2025-10-15 11:42
考虑用wireshark抓包下,看看是不是完全没反应。

不过,看了传给nx的消息,和电脑发的arp包是一致的,不知道什么原因nx没有进入SEND case
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119430
QQ
发表于 2025-10-16 10:41:00 | 显示全部楼层
MDLZCOOL 发表于 2025-10-15 11:57
不过,看了传给nx的消息,和电脑发的arp包是一致的,不知道什么原因nx没有进入SEND case

今天进展怎么样,解决没
回复

使用道具 举报

5

主题

16

回帖

31

积分

新手上路

积分
31
 楼主| 发表于 2025-10-17 02:07:32 | 显示全部楼层
eric2013 发表于 2025-10-16 10:41
今天进展怎么样,解决没

还没解决,准备暂时搁置到下周三
回复

使用道具 举报

14

主题

91

回帖

153

积分

初级会员

积分
153
发表于 2025-10-17 09:09:12 | 显示全部楼层
没这种国产芯片的带ETH的开发板,最近也没有相关的试用活动
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119430
QQ
发表于 2025-10-17 09:50:57 | 显示全部楼层
egoistaw 发表于 2025-10-17 09:09
没这种国产芯片的带ETH的开发板,最近也没有相关的试用活动

如果要是你做的话,可以申请下,说帮他们做个ThreadX NetX驱动代码,那必须赠送你一个。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-11-22 01:32 , Processed in 0.042992 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表