[bsp][nuvoton_m487]Add EMAC drive
This commit is contained in:
parent
0889bafda8
commit
6802bb15e0
|
@ -42,6 +42,7 @@
|
|||
| 驱动 | 支持情况 | 备注 |
|
||||
| ------ | ---- | :------: |
|
||||
| UART | 支持 | UART0|
|
||||
| EMAC | 支持 | EH0|
|
||||
|
||||
### 4.1 IO在板级支持包中的映射情况
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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(ð);
|
||||
}
|
||||
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
|
||||
|
|
@ -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_ */
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue