From 6802bb15e036c6300d6c43ca0299fc16f8eed4fd Mon Sep 17 00:00:00 2001 From: Bluebear233 <417350690@qq.com> Date: Sun, 20 Jan 2019 13:43:15 +0800 Subject: [PATCH] [bsp][nuvoton_m487]Add EMAC drive --- bsp/nuvoton_m487/README.md | 1 + bsp/nuvoton_m487/driver/SConscript | 3 +- bsp/nuvoton_m487/driver/board.c | 2 - bsp/nuvoton_m487/driver/board.h | 19 +- bsp/nuvoton_m487/driver/drv_emac.c | 733 +++++++++++++++++++++++++++++ bsp/nuvoton_m487/driver/drv_emac.h | 126 +++++ bsp/nuvoton_m487/driver/drv_uart.c | 11 +- bsp/nuvoton_m487/rtconfig.h | 17 +- 8 files changed, 878 insertions(+), 34 deletions(-) create mode 100644 bsp/nuvoton_m487/driver/drv_emac.c create mode 100644 bsp/nuvoton_m487/driver/drv_emac.h diff --git a/bsp/nuvoton_m487/README.md b/bsp/nuvoton_m487/README.md index ca6e82c859..3956040d60 100644 --- a/bsp/nuvoton_m487/README.md +++ b/bsp/nuvoton_m487/README.md @@ -42,6 +42,7 @@ | 驱动 | 支持情况 | 备注 | | ------ | ---- | :------: | | UART | 支持 | UART0| +| EMAC | 支持 | EH0| ### 4.1 IO在板级支持包中的映射情况 diff --git a/bsp/nuvoton_m487/driver/SConscript b/bsp/nuvoton_m487/driver/SConscript index 4de25c676a..73cc8e1dc6 100644 --- a/bsp/nuvoton_m487/driver/SConscript +++ b/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] diff --git a/bsp/nuvoton_m487/driver/board.c b/bsp/nuvoton_m487/driver/board.c index a80024b0b7..3105de76c3 100644 --- a/bsp/nuvoton_m487/driver/board.c +++ b/bsp/nuvoton_m487/driver/board.c @@ -8,9 +8,7 @@ * 2018-11-16 bluebear233 first version */ -#include #include -#include #include "NuMicro.h" #include "drv_uart.h" #include "board.h" diff --git a/bsp/nuvoton_m487/driver/board.h b/bsp/nuvoton_m487/driver/board.h index 515ab1bb39..8db57161ad 100644 --- a/bsp/nuvoton_m487/driver/board.h +++ b/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_ */ diff --git a/bsp/nuvoton_m487/driver/drv_emac.c b/bsp/nuvoton_m487/driver/drv_emac.c new file mode 100644 index 0000000000..a12ba9ba37 --- /dev/null +++ b/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 + +#ifdef RT_USING_LWIP +#include "NuMicro.h" +#include "drv_emac.h" +#include +#include +#include +#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; itot_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(ð); + } + else if(status & EMAC_INTSTS_RXGDIF_Msk) + { + EMAC->INTEN &= ~EMAC_INTEN_RXGDIEN_Msk; + eth_device_ready(ð); + } + + 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(ð_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(ð, RT_TRUE); + } /* link up. */ + else + { + ETH_TRACE("link down\r\n"); + + /* send link down. */ + eth_device_linkchange(ð, 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(ð_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO); + + rt_thread_init(ð_tid, "eth", eth_entry, RT_NULL, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10); + + rt_thread_startup(ð_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(ð_sem, RT_IPC_CMD_RESET, 0); + + EMAC->INTSTS = EMAC_INTSTS_TXCPIF_Msk; + EMAC->INTEN |= EMAC_INTEN_TXCPIEN_Msk; + + do{ + rt_sem_take(ð_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(ð, 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 + diff --git a/bsp/nuvoton_m487/driver/drv_emac.h b/bsp/nuvoton_m487/driver/drv_emac.h new file mode 100644 index 0000000000..3ff629703d --- /dev/null +++ b/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_ */ diff --git a/bsp/nuvoton_m487/driver/drv_uart.c b/bsp/nuvoton_m487/driver/drv_uart.c index 40219da801..4e292bdfc9 100644 --- a/bsp/nuvoton_m487/driver/drv_uart.c +++ b/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) { diff --git a/bsp/nuvoton_m487/rtconfig.h b/bsp/nuvoton_m487/rtconfig.h index 5eb9dca57e..7f151fe1de 100644 --- a/bsp/nuvoton_m487/rtconfig.h +++ b/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