A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Revision:
59:e0e556c8bd46
Child:
60:1d8c7a1e7483
diff -r d48c899e482f -r e0e556c8bd46 link/nic.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/link/nic.cpp	Thu Dec 14 20:55:40 2017 +0000
@@ -0,0 +1,279 @@
+#include "mbed.h"
+#include "nicdefs.h"
+#include "log.h"
+
+#define NUM_RX_FRAMES       3           // Number of Rx Frames (== packets)
+#define NUM_TX_FRAMES       2           // Number of Tx Frames (== packets)
+
+#define ETH_FRAME_LEN       1536        // Maximum Ethernet Frame Size
+
+static volatile                    uint8_t r_buff[NUM_RX_FRAMES][ETH_FRAME_LEN];
+static volatile                    uint8_t t_buff[NUM_TX_FRAMES][ETH_FRAME_LEN];
+static volatile            RX_DESC_TypeDef r_desc[NUM_RX_FRAMES];
+static volatile __align(8) RX_STAT_TypeDef r_stat[NUM_RX_FRAMES]; //Must be aligned on an 8 byte boundary
+static volatile            TX_DESC_TypeDef t_desc[NUM_TX_FRAMES];
+static volatile            TX_STAT_TypeDef t_stat[NUM_TX_FRAMES];
+
+char* NicGetReceivedPacketOrNull(int* pSize)
+{    
+    if (LPC_EMAC->RxProduceIndex == LPC_EMAC->RxConsumeIndex) return NULL;
+        
+    uint32_t info = r_stat[LPC_EMAC->RxConsumeIndex].Info;
+    *pSize = (info & RINFO_SIZE) + 1 - 4; // exclude checksum
+        
+    return (char*)r_buff[LPC_EMAC->RxConsumeIndex];
+}
+void NicReleaseReceivedPacket()
+{
+    if (LPC_EMAC->RxConsumeIndex == LPC_EMAC->RxDescriptorNumber) LPC_EMAC->RxConsumeIndex = 0;
+    else                                                          LPC_EMAC->RxConsumeIndex++;
+}
+char* NicGetTransmitPacketOrNull(int* pSize)
+{
+    if (LPC_EMAC->TxConsumeIndex == 0 && LPC_EMAC->TxProduceIndex == LPC_EMAC->TxDescriptorNumber) return NULL;
+    if (LPC_EMAC->TxProduceIndex == LPC_EMAC->TxConsumeIndex - 1)                                  return NULL;
+    *pSize = ETH_FRAME_LEN - 4;
+    return (char*)t_buff[LPC_EMAC->TxProduceIndex];
+}
+void NicSendTransmitPacket(int size)
+{
+    if (size == 0) return;
+    t_desc[LPC_EMAC->TxProduceIndex].Ctrl = (size - 1) | (TCTRL_INT | TCTRL_LAST);
+    if (LPC_EMAC->TxProduceIndex == LPC_EMAC->TxDescriptorNumber) LPC_EMAC->TxProduceIndex = 0;
+    else                                                          LPC_EMAC->TxProduceIndex++;
+}
+
+static void txdscr_init()
+{
+    int i;
+
+    for(i = 0; i < NUM_TX_FRAMES; i++)
+    {
+        t_desc[i].Packet = (uint32_t)&t_buff[i];
+        t_desc[i].Ctrl   = 0;
+        t_stat[i].Info   = 0;
+    }
+
+    LPC_EMAC->TxDescriptor       = (uint32_t)t_desc;         /* Set EMAC Transmit Descriptor Registers. */
+    LPC_EMAC->TxStatus           = (uint32_t)t_stat;
+    LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAMES - 1;
+
+    LPC_EMAC->TxProduceIndex  = 0;                           /* Tx Descriptors Point to 0 */
+}
+
+static void rxdscr_init()
+{
+    int i;
+
+    for(i = 0; i < NUM_RX_FRAMES; i++)
+    {
+        r_desc[i].Packet  = (uint32_t)&r_buff[i];
+        r_desc[i].Ctrl    = RCTRL_INT | (ETH_FRAME_LEN-1);
+        r_stat[i].Info    = 0;
+        r_stat[i].HashCRC = 0;
+    }
+
+    LPC_EMAC->RxDescriptor       = (uint32_t)r_desc;        /* Set EMAC Receive Descriptor Registers. */
+    LPC_EMAC->RxStatus           = (uint32_t)r_stat;        //Must be aligned on an 8 byte boundary
+    LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAMES - 1;
+
+    LPC_EMAC->RxConsumeIndex  = 0;                          /* Rx Descriptors Point to 0 */
+}
+static int phy_write(unsigned int PhyReg, unsigned short Data)
+{
+    unsigned int timeOut;
+
+    LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
+    LPC_EMAC->MWTD = Data;
+
+    // Wait until operation completed
+    for(timeOut = 0; timeOut < MII_WR_TOUT; timeOut++)
+    {
+        if((LPC_EMAC->MIND & MIND_BUSY) == 0)  return 0;
+    }
+
+    //Timed out
+    return -1;
+}
+
+static int phy_read(unsigned int PhyReg)
+{
+    unsigned int timeOut;
+
+    LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
+    LPC_EMAC->MCMD = MCMD_READ;
+
+    // Wait until operation completed
+    for(timeOut = 0; timeOut < MII_RD_TOUT; timeOut++)
+    {
+        if((LPC_EMAC->MIND & MIND_BUSY) == 0)
+        {
+            LPC_EMAC->MCMD = 0;
+            return LPC_EMAC->MRDD; // Return a 16-bit value.
+        }
+    }
+    return -1;
+}
+
+void NicLinkAddress(char *mac)
+{
+    mbed_mac_address(mac);
+}
+
+void NicLinkSetSpeedDuplex(int speed, int duplex)
+{
+    unsigned short phy_data;
+    int tout;
+
+    if((speed < 0) || (speed > 1)) phy_data = PHY_AUTO_NEG;
+    else                           phy_data = (((unsigned short) speed << 13) | ((unsigned short) duplex << 8));
+
+    phy_write(PHY_REG_BMCR, phy_data);
+
+    for(tout = 100; tout; tout--) __NOP();     /* A short delay */
+    
+    phy_data = phy_read(PHY_REG_STS);
+
+    if(phy_data & PHY_STS_DUPLEX)
+    {
+        LPC_EMAC->MAC2    |= MAC2_FULL_DUP;
+        LPC_EMAC->Command |=   CR_FULL_DUP;
+        LPC_EMAC->IPGT     = IPGT_FULL_DUP;
+    }
+    else
+    {
+        LPC_EMAC->MAC2    &= ~MAC2_FULL_DUP;
+        LPC_EMAC->Command &=   ~CR_FULL_DUP;
+        LPC_EMAC->IPGT     =  IPGT_HALF_DUP;
+    }
+
+    if(phy_data & PHY_STS_SPEED)
+    {
+        LPC_EMAC->SUPP &= ~SUPP_SPEED;
+    }
+    else
+    {
+        LPC_EMAC->SUPP |= SUPP_SPEED;
+    }
+}
+
+int NicLinkIsUp(void)
+{
+    return (phy_read(PHY_REG_STS) & PHY_STS_LINK);
+}
+static int phy_reset()
+{
+    int regv, tout;
+    
+    // perform PHY reset
+    phy_write(PHY_REG_BMCR, PHY_BMCR_RESET);           
+  
+    // Wait for hardware reset to end.
+    for(tout = 0x20000; ; tout--)
+    {                    
+        regv = phy_read(PHY_REG_BMCR);
+        if(regv < 0 || tout == 0)     return -1;  // Error
+        if(!(regv & PHY_BMCR_RESET))  break;      // Reset complete.
+    }
+    uint32_t phy_id  = (phy_read(PHY_REG_IDR1) << 16);
+    phy_id |= (phy_read(PHY_REG_IDR2) & 0XFFF0);
+
+    //Check is the right PHY
+    if (phy_id != DP83848C_ID)
+    {
+        error("Unknown Ethernet PHY (%x)", (unsigned int)phy_id);
+        return -1;
+    }
+    return 0;
+}
+int NicInit()
+{
+    int tout;
+    char mac[6];
+    unsigned int clock = 10; //96,000,000
+    
+    // Power Up the EMAC controller.
+    LPC_SC->PCONP |= 0x40000000;                       
+    
+    // Enable P1 Ethernet Pins.
+    LPC_PINCON->PINSEL2 = 0x50150105;                 
+    LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
+    
+    // Reset all EMAC internal modules.
+    LPC_EMAC->MAC1    = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
+    LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
+    
+    // A short delay after reset.
+    for(tout = 100; tout; tout--) __NOP();             
+    
+    // Initialize MAC control registers.
+    LPC_EMAC->MAC1 = MAC1_PASS_ALL;                   
+    LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
+    LPC_EMAC->MAXF = ETH_FRAME_LEN;
+    LPC_EMAC->CLRT = CLRT_DEF;
+    LPC_EMAC->IPGR = IPGR_DEF;
+    
+    // Enable Reduced MII interface.
+    LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM;    
+    
+    // Set clock and reset
+    LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL;
+    LPC_EMAC->MCFG |= MCFG_RES_MII;
+    
+    // A short delay after reset
+    for(tout = 100; tout; tout--) __NOP();
+    
+    // Set clock
+    LPC_EMAC->MCFG = (clock << 0x2) & MCFG_CLK_SEL;
+    LPC_EMAC->MCMD = 0;
+    
+    // Reset Reduced MII Logic.
+    LPC_EMAC->SUPP = SUPP_RES_RMII;                    
+    
+    // A short delay
+    for (tout = 100; tout; tout--) __NOP();
+    
+    LPC_EMAC->SUPP = 0;
+    
+    //Reset the PHY
+    if (phy_reset()) return -1;
+    
+    //Set the link to auto negotiate
+    NicLinkSetSpeedDuplex(-1, 0);
+    
+    // Set the Ethernet MAC Address registers
+    NicLinkAddress(mac);
+    LPC_EMAC->SA0 = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4];
+    LPC_EMAC->SA1 = ((uint32_t)mac[3] << 8) | (uint32_t)mac[2];
+    LPC_EMAC->SA2 = ((uint32_t)mac[1] << 8) | (uint32_t)mac[0];
+    
+    //Initialise DMA descriptors
+    txdscr_init();
+    rxdscr_init();
+    
+    // Set filter
+    LPC_EMAC->RxFilterCtrl = RFC_UCAST_EN | RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
+                                                      
+    // Enable and clear EMAC interrupts
+    //LPC_EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;
+    // Disable and clear EMAC interrupts
+    LPC_EMAC->IntEnable = 0;
+    LPC_EMAC->IntClear  = 0xFFFF;
+    
+    //Enable receive and transmit
+    LPC_EMAC->Command  |= (CR_RX_EN | CR_TX_EN);
+    LPC_EMAC->MAC1     |= MAC1_REC_EN;
+    
+    //Return success
+    return 0;
+}
+
+void NicFree() {
+    LPC_EMAC->IntEnable &= ~(INT_RX_DONE | INT_TX_DONE);
+    LPC_EMAC->IntClear   =  0xFFFF;
+
+    LPC_SC->PCONP   &= ~0x40000000;       /* Power down the EMAC controller. */
+
+    LPC_PINCON->PINSEL2 &= ~0x50150105;   /* Disable P1 ethernet pins. */
+    LPC_PINCON->PINSEL3  = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000000;
+}