Browse Source

Merge pull request #2241 from Bluebear233/nuvoton_m487

[bsp][nuvoton_m487]Add EMAC drive
Bernard Xiong 6 years ago
parent
commit
a7babadbdc

+ 1 - 0
bsp/nuvoton_m487/README.md

@@ -42,6 +42,7 @@
 | 驱动 | 支持情况  |  备注  |
 | ------ | ----  | :------:  |
 | UART | 支持 | UART0|
+| EMAC | 支持 | EH0|
 
 ### 4.1 IO在板级支持包中的映射情况
 

+ 2 - 1
bsp/nuvoton_m487/driver/SConscript

@@ -1,4 +1,4 @@
-# RT-Thread building script for component
+# RT-Thread building script for component
 
 from building import *
 
@@ -6,6 +6,7 @@ cwd     = GetCurrentDir()
 src     = Split('''
 board.c
 drv_uart.c
+drv_emac.c
 ''')
 CPPPATH = [cwd]
 

+ 0 - 2
bsp/nuvoton_m487/driver/board.c

@@ -8,9 +8,7 @@
  * 2018-11-16    bluebear233   first version
  */
 
-#include <rtconfig.h>
 #include <rtthread.h>
-#include <rthw.h>
 #include "NuMicro.h"
 #include "drv_uart.h"
 #include "board.h"

+ 2 - 17
bsp/nuvoton_m487/driver/board.h

@@ -15,22 +15,7 @@
 #define SRAM_SIZE         (160)
 #define SRAM_END          (0x20000000 + SRAM_SIZE * 1024)
 
-#define RT_UART_485_MODE      1
-#define RT_UART_FLOW_CTS_CTRL 2
-#define RT_UART_FLOW_RTS_CTRL 3
-#define RT_UART_CLEAR_BUF     4
-
-void rt_hw_pdma_init(void);
-void rt_hw_uart_handle(void);
-void rt_hw_sc_init(void);
-void rt_hw_usart_init(void);
-void rt_hw_uusart_init(void);
-void rt_hw_io_init(void);
-void phy_error_led(void);
-
-unsigned char *eth_get_default_mac(void);
-void eth_set_mac(const unsigned char * mac);
-void wdt_reload(void);
-unsigned int get_uid(void);
+void rt_hw_board_init(void);
+void rt_hw_cpu_reset(void);
 
 #endif /* BOARD_H_ */

+ 733 - 0
bsp/nuvoton_m487/driver/drv_emac.c

@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-1-20      bluebear233  first version
+ */
+
+#include <rtthread.h>
+
+#ifdef RT_USING_LWIP
+#include "NuMicro.h"
+#include "drv_emac.h"
+#include <netif/ethernetif.h>
+#include <netif/etharp.h>
+#include <lwip/icmp.h>
+#include "lwipopts.h"
+
+#define ETH_DEBUG
+//#define ETH_RX_DUMP
+//#define ETH_TX_DUMP
+
+#ifdef ETH_DEBUG
+#define ETH_TRACE         rt_kprintf
+#else
+#define ETH_TRACE(...)
+#endif /* ETH_DEBUG */
+
+
+#if defined(ETH_RX_DUMP) ||  defined(ETH_TX_DUMP)
+static void packet_dump(const char * msg, const struct pbuf* p)
+{
+    rt_uint32_t i;
+    rt_uint8_t *ptr = p->payload;
+
+    ETH_TRACE("%s %d byte\n", msg, p->tot_len);
+
+    for(i=0; i<p->tot_len; i++)
+    {
+        if( (i%8) == 0 )
+        {
+            ETH_TRACE("  ");
+        }
+        if( (i%16) == 0 )
+        {
+            ETH_TRACE("\r\n");
+        }
+        ETH_TRACE("%02x ",*ptr);
+        ptr++;
+    }
+    ETH_TRACE("\n\n");
+}
+#endif /* dump */
+
+#define ETH_TRIGGER_RX()    EMAC->RXST = 0
+#define ETH_TRIGGER_TX()    EMAC->TXST = 0
+#define ETH_ENABLE_TX()     EMAC->CTL |= EMAC_CTL_TXON
+#define ETH_ENABLE_RX()     EMAC->CTL |= EMAC_CTL_RXON
+#define ETH_DISABLE_TX()    EMAC->CTL &= ~EMAC_CTL_TXON
+#define ETH_DISABLE_RX()    EMAC->CTL &= ~EMAC_CTL_RXON
+
+#define EMAC_DMARXDESC_CRCEIF_Msk (1ul << 17)
+
+#define ETH_TID_STACK 256
+
+static rt_uint8_t volatile phy_speed = 0;
+static rt_uint8_t eth_addr[6];
+static struct eth_device eth;
+static struct rt_semaphore eth_sem;
+static struct rt_thread eth_tid;
+static rt_uint32_t eth_stack[ETH_TID_STACK / 4];
+static struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
+static struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
+static struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
+
+static rt_uint32_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
+static rt_uint32_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
+
+
+static void mdio_write(rt_uint8_t addr, rt_uint8_t reg, rt_uint16_t val)
+{
+    EMAC->MIIMDAT = val;
+    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_WRITE_Msk | EMAC_MIIMCTL_MDCON_Msk;
+
+    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
+}
+
+static rt_uint16_t mdio_read(rt_uint8_t addr, rt_uint8_t reg)
+{
+    EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
+    while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
+
+    return EMAC->MIIMDAT;
+}
+
+static void init_tx_desc(void)
+{
+    rt_uint32_t i;
+
+    cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
+
+    for(i = 0; i < TX_DESCRIPTOR_NUM; i++) 
+    {
+        tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;
+        tx_desc[i].buf = (rt_uint8_t*)tx_buf[i];
+        tx_desc[i].status2 = 0;
+        tx_desc[i].next = &tx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
+    }
+    EMAC->TXDSA = (unsigned int)&tx_desc[0];
+    return;
+}
+
+static void init_rx_desc(void)
+{
+    rt_uint32_t i;
+
+    cur_rx_desc_ptr = &rx_desc[0];
+
+    for(i = 0; i < RX_DESCRIPTOR_NUM; i++)
+    {
+        rx_desc[i].status1 = OWNERSHIP_EMAC;
+        rx_desc[i].buf = (rt_uint8_t*)rx_buf[i];
+        rx_desc[i].status2 = 0;
+        rx_desc[i].next = &rx_desc[(i + 1) % RX_DESCRIPTOR_NUM];
+    }
+    EMAC->RXDSA = (unsigned int)&rx_desc[0];
+    return;
+}
+
+static void add_mac_addr(const rt_uint8_t *addr)
+{
+    rt_uint32_t *EMAC_CAMxM;
+    rt_uint32_t *EMAC_CAMxL;
+    rt_uint8_t index = 0;
+    rt_uint8_t mac[6];
+
+    for(; index < 13; index ++)
+    {
+        EMAC_CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8));
+        EMAC_CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8));
+
+        mac[0] = (*EMAC_CAMxM >> 24) & 0xff;
+        mac[1] = (*EMAC_CAMxM >> 16) & 0xff;
+        mac[2] = (*EMAC_CAMxM >> 8) & 0xff;
+        mac[3] = (*EMAC_CAMxM) & 0xff;
+        mac[4] = (*EMAC_CAMxL >> 24) & 0xff;
+        mac[5] = (*EMAC_CAMxL >> 16) & 0xff;
+
+        if(memcmp(mac, addr, sizeof(mac)) == 0)
+        {
+            return;
+        }
+
+        if(*EMAC_CAMxM == 0 && *EMAC_CAMxL == 0)
+        {
+            break;
+        }
+    }
+
+    RT_ASSERT(index < 13)
+
+    *EMAC_CAMxM  = (addr[0] << 24) |
+                  (addr[1] << 16) |
+                  (addr[2] << 8) |
+                  addr[3];
+
+    *EMAC_CAMxL = (addr[4] << 24) |
+                  (addr[5] << 16);
+
+    EMAC->CAMEN |= (1 << index);
+}
+
+void EMAC_init()
+{
+    // Reset MAC
+    EMAC->CTL = EMAC_CTL_RST_Msk;
+    while(EMAC->CTL & EMAC_CTL_RST_Msk);
+
+    init_tx_desc();
+    init_rx_desc();
+
+    EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | EMAC_CAMCTL_ABP_Msk;
+    add_mac_addr(eth_addr);
+
+    EMAC->CTL |= EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk | EMAC_CTL_RMIIEN_Msk;
+    EMAC->INTEN = EMAC_INTEN_RXIEN_Msk |
+                   EMAC_INTEN_RXGDIEN_Msk |
+                   EMAC_INTEN_RDUIEN_Msk |
+                   EMAC_INTEN_RXBEIEN_Msk |
+                   EMAC_INTEN_TXIEN_Msk |
+                   EMAC_INTEN_TXBEIEN_Msk;
+
+    /* Limit the max receive frame length to 1514 + 4 */
+    EMAC->MRFL = PACKET_BUFFER_SIZE;
+    EMAC->RXST = 0;  // trigger Rx
+}
+
+void EMAC_Reinit(void)
+{
+    rt_uint32_t EMAC_CAMxM[13];
+    rt_uint32_t EMAC_CAMxL[13];
+    rt_uint32_t EMAC_CAMEN;
+
+    EMAC_CAMEN = EMAC->CAMEN;
+    for(rt_uint8_t index = 0 ; index < 13; index ++)
+    {
+        rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8));
+        rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8));
+
+        EMAC_CAMxM[index] = *CAMxM;
+        EMAC_CAMxL[index] = *CAMxL;
+    }
+
+    EMAC_init();
+
+    for(rt_uint8_t index = 0 ; index < 13; index ++)
+    {
+        rt_uint32_t *CAMxM = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0M + (index * 8));
+        rt_uint32_t *CAMxL = (rt_uint32_t *)((rt_uint32_t)&EMAC->CAM0L + (index * 8));
+
+        *CAMxM = EMAC_CAMxM[index];
+        *CAMxL = EMAC_CAMxL[index];
+    }
+    EMAC->CAMEN = EMAC_CAMEN;
+
+    phy_speed = 0;
+}
+
+void ETH_halt(void)
+{
+    EMAC->CTL &= ~(EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk);
+}
+
+__inline static rt_uint8_t *emac_get_tx_buf(void)
+{
+    if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
+    {
+        return(RT_NULL);
+    }
+    else
+    {
+        return(cur_tx_desc_ptr->buf);
+    }
+}
+
+__inline static void ETH_trigger_tx(rt_uint16_t length)
+{
+    struct eth_descriptor volatile *desc;
+    
+    cur_tx_desc_ptr->status2 = (unsigned int)length;
+    desc = cur_tx_desc_ptr->next;    // in case TX is transmitting and overwrite next pointer before we can update cur_tx_desc_ptr
+    cur_tx_desc_ptr->status1 |= OWNERSHIP_EMAC;
+    cur_tx_desc_ptr = desc;
+}
+
+#if LWIP_IPV4 && LWIP_IGMP
+static err_t igmp_mac_filter( struct netif *netif, const ip4_addr_t *ip4_addr, u8_t action )
+{
+    rt_uint8_t mac[6];
+    const uint8_t *p = (const uint8_t *)ip4_addr;
+
+    mac[0] = 0x01;
+    mac[1] = 0x00;
+    mac[2] = 0x5E;
+    mac[3] = *(p+1) & 0x7F;
+    mac[4] = *(p+2);
+    mac[5] = *(p+3);
+
+    add_mac_addr(mac);
+
+    if(1)
+    {
+        rt_kprintf("%s %s %s ", __FUNCTION__, (action==NETIF_ADD_MAC_FILTER)?"add":"del", ip4addr_ntoa(ip4_addr));
+        rt_kprintf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+    }
+
+    return 0;
+}
+#endif /* LWIP_IPV4 && LWIP_IGMP */
+
+/*
+ * M480 EMAC Driver for RT-Thread
+ * Change Logs:
+ * Date           Author       Notes
+ * 2017-12-31     Bluebear233  first implementation
+ */
+void EMAC_RX_IRQHandler(void)
+{
+    /* enter interrupt */
+    rt_interrupt_enter();
+    
+    unsigned int status = EMAC->INTSTS;
+
+    if(status & EMAC_INTSTS_RDUIF_Msk)
+    {
+        EMAC->INTEN &= ~(EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk);
+        eth_device_ready(&eth);
+    }
+    else if(status & EMAC_INTSTS_RXGDIF_Msk)
+    {
+        EMAC->INTEN &= ~EMAC_INTEN_RXGDIEN_Msk;
+        eth_device_ready(&eth);
+    }
+
+    if(status & EMAC_INTSTS_RXBEIF_Msk)
+    {
+        ETH_TRACE("Reinit Rx EMAC\n");
+        EMAC->INTSTS = EMAC_INTSTS_RXBEIF_Msk;
+        EMAC_Reinit();
+    }
+
+    /* leave interrupt */
+    rt_interrupt_leave();
+}
+
+void EMAC_TX_IRQHandler(void)
+{
+    rt_interrupt_enter();
+
+    unsigned int status = EMAC->INTSTS;
+
+    if(status & EMAC_INTSTS_TXCPIF_Msk)
+    {
+        EMAC->INTEN &= ~EMAC_INTEN_TXCPIEN_Msk;
+        rt_sem_release(&eth_sem);
+    }
+
+    if(status & EMAC_INTSTS_TXBEIF_Msk)
+    {
+        ETH_TRACE("Reinit Tx EMAC\n");
+        EMAC->INTSTS = EMAC_INTSTS_TXBEIF_Msk;
+        EMAC_Reinit();
+    }
+
+    rt_interrupt_leave();
+}
+
+#define PHY_LINK_MASK       (1<<0)
+#define PHY_10FULL_MASK     (1<<1)
+#define PHY_100FULL_MASK    (1<<2)
+#define PHY_10HALF_MASK     (1<<3)
+#define PHY_100HALF_MASK    (1<<4)
+
+#define PHY_ANLPA_DR100_TX_FULL   (1UL << 8UL)
+#define PHY_ANLPA_DR100_TX_HALF   (1UL << 7UL)
+#define PHY_ANLPA_DR10_TX_FULL    (1UL << 6UL)
+#define PHY_ANLPA_DR10_TX_HALF    (1UL << 5UL)
+
+void eth_entry(void *param)
+{
+    uint8_t phy_addr = 0xFF;
+    uint8_t phy_speed_new = 0;
+
+    /* phy search */
+    {
+        rt_uint32_t i;
+        rt_uint16_t temp;
+
+        for(i=0; i<=0x1F; i++)
+        {
+            temp = mdio_read(i, 0x02);
+            if( temp != 0xFFFF )
+            {
+                phy_addr = i;
+                break;
+            }
+        }
+    } /* phy search */
+
+    if(phy_addr == 0xFF)
+    {
+        ETH_TRACE("phy not probe!\n");
+        return;
+    }
+    else
+    {
+        ETH_TRACE("found a phy, address:0x%02X\n", phy_addr);
+    }
+
+    /* RESET PHY */
+    mdio_write(phy_addr, MII_BMCR, BMCR_RESET);
+    while (1)
+    {
+        rt_thread_delay(RT_TICK_PER_SECOND);
+
+        rt_uint16_t reg = mdio_read(phy_addr, MII_BMCR);
+        if ((reg & BMCR_RESET) == 0)
+        {
+            break;
+        }
+    }
+
+    mdio_write(phy_addr, MII_ADVERTISE, ADVERTISE_CSMA |
+               ADVERTISE_10HALF |
+               ADVERTISE_10FULL |
+               ADVERTISE_100HALF |
+               ADVERTISE_100FULL);
+    {
+        uint16_t reg = mdio_read(phy_addr, MII_BMCR);
+        mdio_write(phy_addr, MII_BMCR, reg | BMCR_ANRESTART);
+    }
+
+    while(1)
+    {
+        uint16_t status = mdio_read(phy_addr, MII_BMSR);
+        phy_speed_new = 0;
+
+        if((status & (BMSR_ANEGCAPABLE | BMSR_LSTATUS)) == (BMSR_ANEGCAPABLE | BMSR_LSTATUS))
+        {
+            phy_speed_new = PHY_LINK_MASK;
+
+            status = mdio_read(phy_addr, MII_LPA);
+
+            if(status & PHY_ANLPA_DR100_TX_FULL)
+            {
+                phy_speed_new |= PHY_100FULL_MASK;
+            }
+            else if(status & PHY_ANLPA_DR100_TX_HALF)
+            {
+                phy_speed_new |= PHY_100HALF_MASK;
+            }
+            else if(status & PHY_ANLPA_DR10_TX_FULL)
+            {
+                phy_speed_new |= PHY_10FULL_MASK;
+            }
+            else if(status & PHY_ANLPA_DR10_TX_HALF)
+            {
+                phy_speed_new |= PHY_10HALF_MASK;
+            }
+        }
+
+        /* linkchange */
+        if(phy_speed_new != phy_speed)
+        {
+            if(phy_speed_new & PHY_LINK_MASK)
+            {
+                ETH_TRACE("link up ");
+
+                if(phy_speed_new & PHY_100FULL_MASK)
+                {
+                    ETH_TRACE("100Mbps full-duplex\n");
+                    EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
+                }
+                else if(phy_speed_new & PHY_100HALF_MASK)
+                {
+                    ETH_TRACE("100Mbps half-duplex\n");
+                    EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
+                }
+                else if(phy_speed_new & PHY_10FULL_MASK)
+                {
+                    ETH_TRACE("10Mbps full-duplex\n");
+                    EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
+                }
+                else
+                {
+                    ETH_TRACE("10Mbps half-duplex\n");
+                    EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
+                }
+
+                /* send link up. */
+                eth_device_linkchange(&eth, RT_TRUE);
+            } /* link up. */
+            else
+            {
+                ETH_TRACE("link down\r\n");
+
+                /* send link down. */
+                eth_device_linkchange(&eth, RT_FALSE);
+            } /* link down. */
+
+            phy_speed = phy_speed_new;
+        } /* linkchange */
+
+        rt_thread_delay(RT_TICK_PER_SECOND);
+    } /* while(1) */
+}
+
+static rt_err_t rt_m480_emac_init(rt_device_t dev)
+{
+    /* Unlock protected registers */
+    SYS_UnlockReg();
+
+    CLK_EnableModuleClock(EMAC_MODULE);
+
+    // Configure MDC clock rate to HCLK / (127 + 1) = 1.5 MHz if system is running at 192 MHz
+    CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
+
+    // Configure RMII pins
+//    SYS->GPA_MFPL |= SYS_GPA_MFPL_PA6MFP_EMAC_RMII_RXERR | SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV;
+    SYS->GPA_MFPL |= SYS_GPA_MFPL_PA7MFP_EMAC_RMII_CRSDV;
+    SYS->GPC_MFPL |= SYS_GPC_MFPL_PC6MFP_EMAC_RMII_RXD1 | SYS_GPC_MFPL_PC7MFP_EMAC_RMII_RXD0;
+    SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_RMII_REFCLK;
+    SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC |
+                     SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO |
+                     SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 |
+                     SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 |
+                     SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN;
+
+    // Enable high slew rate on all RMII TX output pins
+    PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) |
+                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN11_Pos) |
+                  (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN12_Pos);
+
+        /* Lock protected registers */
+    SYS_LockReg();
+
+    EMAC_init();
+
+    NVIC_SetPriority(EMAC_TX_IRQn, 1);
+    NVIC_EnableIRQ(EMAC_TX_IRQn);
+    NVIC_SetPriority(EMAC_RX_IRQn, 1);
+    NVIC_EnableIRQ(EMAC_RX_IRQn);
+
+    rt_sem_init(&eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
+
+    rt_thread_init(&eth_tid, "eth", eth_entry, RT_NULL, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
+
+    rt_thread_startup(&eth_tid);
+
+
+#if LWIP_IPV4 && LWIP_IGMP
+    netif_set_igmp_mac_filter(eth.netif, igmp_mac_filter);
+#endif /* LWIP_IPV4 && LWIP_IGMP */
+    
+    return RT_EOK;
+}
+
+static rt_err_t rt_m480_emac_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+static rt_err_t rt_m480_emac_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_size_t rt_m480_emac_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_size_t rt_m480_emac_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_err_t rt_m480_emac_control(rt_device_t dev, int cmd, void *args)
+{
+    switch(cmd)
+    {
+    case NIOCTL_GADDR:
+        /* get mac address */
+        if(args) rt_memcpy(args, eth_addr, 6);
+        else return -RT_ERROR;
+
+        break;
+
+    default :
+        break;
+    }
+
+    return RT_EOK;
+}
+
+rt_err_t rt_m480_emac_tx(rt_device_t dev, struct pbuf* p)
+{
+    struct pbuf* q;
+    rt_uint32_t offset;
+    rt_uint8_t *buf;
+
+    buf = emac_get_tx_buf();
+
+    /* get free tx buffer */
+    if(buf == RT_NULL)
+    {
+        rt_sem_control(&eth_sem, RT_IPC_CMD_RESET, 0);
+
+        EMAC->INTSTS = EMAC_INTSTS_TXCPIF_Msk;
+        EMAC->INTEN |= EMAC_INTEN_TXCPIEN_Msk;
+
+        do{
+            rt_sem_take(&eth_sem, 1);
+
+            buf = emac_get_tx_buf();
+        }while(buf == RT_NULL);
+    }
+
+
+    offset = 0;
+    for (q = p; q != NULL; q = q->next)
+    {
+        rt_uint8_t* ptr;
+        rt_uint32_t len;
+
+        len = q->len;
+        ptr = q->payload;
+
+        // todo 优化复制
+        memcpy(&buf[offset], ptr, len);
+
+        offset += len;
+    }
+
+
+#ifdef ETH_TX_DUMP
+    packet_dump("TX dump", p);
+#endif
+
+    ETH_trigger_tx(offset);
+
+    if(EMAC->INTSTS & EMAC_INTSTS_TDUIF_Msk)
+    {
+        EMAC->INTSTS = EMAC_INTSTS_TDUIF_Msk;
+        ETH_TRIGGER_TX();
+    }
+
+    /* Return SUCCESS */
+    return RT_EOK;
+}
+
+struct pbuf *rt_m480_emac_rx(rt_device_t dev)
+{
+    unsigned int status;
+    struct pbuf* p;
+
+    /* init p pointer */
+    p = RT_NULL;
+
+start:
+    status = cur_rx_desc_ptr->status1;
+
+    if(status & OWNERSHIP_EMAC)
+    {
+        goto end;
+    }
+
+    if ((status & RXFD_RXGD) && !(status & EMAC_DMARXDESC_CRCEIF_Msk))
+    {
+        p = pbuf_alloc(PBUF_RAW, status & 0xFFFF, PBUF_RAM);
+        if (p != RT_NULL)
+        {
+            RT_ASSERT(p->next == RT_NULL);
+
+            const char * from = (const char *)(cur_rx_desc_ptr->buf);
+
+            // todo 优化复制
+            memcpy(p->payload, from, p->len);
+        }
+    }
+
+#ifdef ETH_RX_DUMP
+    packet_dump("RX dump", p);
+#endif /* ETH_RX_DUMP */
+
+    cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
+    cur_rx_desc_ptr = cur_rx_desc_ptr->next;
+
+    if(p == RT_NULL)
+    {
+        goto start;
+    }
+
+    return p;
+    
+end:
+    if(!(EMAC->INTEN & EMAC_INTEN_RDUIEN_Msk))
+    {
+        EMAC->INTSTS = (EMAC_INTSTS_RDUIF_Msk | EMAC_INTSTS_RXGDIF_Msk);
+        EMAC->INTEN |= (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk);
+
+        ETH_TRIGGER_RX();
+    }
+    else
+    {
+        EMAC->INTSTS = EMAC_INTSTS_RXGDIF_Msk;
+        EMAC->INTEN |= EMAC_INTEN_RXGDIEN_Msk;
+    }
+    
+    return RT_NULL;
+}
+
+static void rt_hw_m480_emac_register(char *dev_name)
+{
+    rt_uint32_t value = 0;
+
+    SYS_UnlockReg();
+    FMC_Open();
+
+    for (rt_uint8_t i = 0; i < 3; i++)
+    {
+        value += FMC_ReadUID(i);
+    }
+
+    FMC_Close();
+    SYS_LockReg();
+
+    eth_addr[0] = 0x00;
+    eth_addr[1] = 0x00;
+    eth_addr[2] = 0x00;
+    eth_addr[3] = (value >> 16) & 0xff;
+    eth_addr[4] = (value >> 8) & 0xff;
+    eth_addr[5] = (value) & 0xff;
+
+    eth.parent.init       = rt_m480_emac_init;
+    eth.parent.open       = rt_m480_emac_open;
+    eth.parent.close      = rt_m480_emac_close;
+    eth.parent.read       = rt_m480_emac_read;
+    eth.parent.write      = rt_m480_emac_write;
+    eth.parent.control    = rt_m480_emac_control;
+    eth.parent.user_data  = RT_NULL;
+
+    eth.eth_rx     = rt_m480_emac_rx;
+    eth.eth_tx     = rt_m480_emac_tx;
+
+    /* register eth device */
+    eth_device_init(&eth, dev_name);
+}
+
+static int rt_hw_nuc487_emac_init(void)
+{
+    rt_hw_m480_emac_register("eh0");
+
+    return RT_EOK;
+}
+
+INIT_APP_EXPORT(rt_hw_nuc487_emac_init);
+#endif
+

+ 126 - 0
bsp/nuvoton_m487/driver/drv_emac.h

@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016 Nuvoton Technology Corp.
+ * Description:   M480 EMAC driver header file
+ */
+#include "NuMicro.h"
+#ifndef  _M480_ETH_
+#define  _M480_ETH_
+
+/* Generic MII registers. */
+
+#define MII_BMCR            0x00        /* Basic mode control register */
+#define MII_BMSR            0x01        /* Basic mode status register  */
+#define MII_PHYSID1         0x02        /* PHYS ID 1                   */
+#define MII_PHYSID2         0x03        /* PHYS ID 2                   */
+#define MII_ADVERTISE       0x04        /* Advertisement control reg   */
+#define MII_LPA             0x05        /* Link partner ability reg    */
+#define MII_EXPANSION       0x06        /* Expansion register          */
+#define MII_DCOUNTER        0x12        /* Disconnect counter          */
+#define MII_FCSCOUNTER      0x13        /* False carrier counter       */
+#define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
+#define MII_RERRCOUNTER     0x15        /* Receive error counter       */
+#define MII_SREVISION       0x16        /* Silicon revision            */
+#define MII_RESV1           0x17        /* Reserved...                 */
+#define MII_LBRERROR        0x18        /* Lpback, rx, bypass error    */
+#define MII_PHYADDR         0x19        /* PHY address                 */
+#define MII_RESV2           0x1a        /* Reserved...                 */
+#define MII_TPISTATUS       0x1b        /* TPI status for 10mbps       */
+#define MII_NCONFIG         0x1c        /* Network interface config    */
+
+/* Basic mode control register. */
+#define BMCR_RESV               0x007f  /* Unused...                   */
+#define BMCR_CTST               0x0080  /* Collision test              */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
+#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
+#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
+#define BMCR_RESET              0x8000  /* Reset the DP83840           */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_JCD                0x0002  /* Jabber detected             */
+#define BMSR_LSTATUS            0x0004  /* Link status                 */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+#define BMSR_RESV               0x07c0  /* Unused...                   */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_RESV          0x1c00  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define RX_DESCRIPTOR_NUM 4    // Max Number of Rx Frame Descriptors
+#define TX_DESCRIPTOR_NUM 2    // Max number of Tx Frame Descriptors
+
+#define PACKET_BUFFER_SIZE  1520
+
+#define CONFIG_PHY_ADDR     1
+
+
+// Frame Descriptor's Owner bit
+#define OWNERSHIP_EMAC 0x80000000  // 1 = EMAC
+//#define OWNERSHIP_CPU 0x7fffffff  // 0 = CPU
+
+
+
+// Rx Frame Descriptor Status
+#define RXFD_RXGD    0x00100000  // Receiving Good Packet Received
+#define RXFD_RTSAS   0x00800000  // RX Time Stamp Available 
+
+
+// Tx Frame Descriptor's Control bits
+#define TXFD_TTSEN    0x08    // Tx Time Stamp Enable
+#define TXFD_INTEN    0x04    // Interrupt Enable
+#define TXFD_CRCAPP   0x02    // Append CRC
+#define TXFD_PADEN    0x01    // Padding Enable
+
+// Tx Frame Descriptor Status
+#define TXFD_TXCP    0x00080000  // Transmission Completion
+#define TXFD_TTSAS   0x08000000  // TX Time Stamp Available
+
+// Tx/Rx buffer descriptor structure
+struct eth_descriptor;
+struct eth_descriptor
+{
+    uint32_t  status1;
+    uint8_t *buf;
+    uint32_t  status2;
+    struct eth_descriptor *next;
+#ifdef TIME_STAMPING
+    u32_t backup1;
+    u32_t backup2;
+    u32_t reserved1;
+    u32_t reserved2;
+#endif
+};
+
+#ifdef TIME_STAMPING
+
+#define ETH_TS_ENABLE() do{EMAC->TSCTL = EMAC_TSCTL_TSEN_Msk;}while(0)
+#define ETH_TS_START() do{EMAC->TSCTL |= (EMAC_TSCTL_TSMODE_Msk | EMAC_TSCTL_TSIEN_Msk);}while(0)
+s32_t ETH_settime(u32_t sec, u32_t nsec);
+s32_t ETH_gettime(u32_t *sec, u32_t *nsec);
+s32_t ETH_updatetime(u32_t neg, u32_t sec, u32_t nsec);
+s32_t ETH_adjtimex(int ppm);
+void ETH_setinc(void);
+
+#endif
+
+#endif  /* _M480_ETH_ */

+ 3 - 8
bsp/nuvoton_m487/driver/drv_uart.c

@@ -315,11 +315,6 @@ static rt_err_t usart_control(struct rt_serial_device *serial,
         }
         break;
 // TODO 完善DMA接口
-//    case RT_DEVICE_FLAG_DMA_TX:
-//        USART_DMACmd(dev->usart_base, USART_DMAReq_Tx, ENABLE);
-//        stm32_uart_tx_dma_configure(dev, RT_TRUE);
-//        stm32_uart_tx_dma_nvic(dev, RT_TRUE);
-//        break;
     default:
         RT_ASSERT(0)
         ;
@@ -365,9 +360,9 @@ static int usart_receive(struct rt_serial_device *serial)
 /**
  * @brief 串口设备注册
  * @param uart           : UART设备结构体
- * @param uart_base      : STM32 UART外设基地址
- * @param name           : STM32 UART设备名
- * @param tx_dma_channel : STM32 UART TX的DMA通道基地址(可选)
+ * @param uart_base      : UART外设基地址
+ * @param name           : UART设备名
+ * @param tx_dma_channel : UART TX的DMA通道基地址(可选)
  */
 static void rt_hw_uart_register(usart_t usart, UART_T * uart_base, char *name)
 {

+ 11 - 6
bsp/nuvoton_m487/rtconfig.h

@@ -36,6 +36,7 @@
 #define RT_USING_CONSOLE
 #define RT_CONSOLEBUF_SIZE 128
 #define RT_CONSOLE_DEVICE_NAME "uart0"
+#define RT_VER_NUM 0x40000
 
 /* RT-Thread Components */
 
@@ -147,11 +148,6 @@
 
 /* RT-Thread online packages */
 
-/* system packages */
-
-/* RT-Thread GUI Engine */
-
-
 /* IoT - internet of things */
 
 
@@ -163,6 +159,9 @@
 /* Wiced WiFi */
 
 
+/* IoT Cloud */
+
+
 /* security packages */
 
 
@@ -175,10 +174,16 @@
 /* tools packages */
 
 
+/* system packages */
+
+
+/* peripheral libraries and drivers */
+
+
 /* miscellaneous packages */
 
 
-/* example package: hello */
+/* samples: kernel and components samples */
 
 
 #endif