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
link/nic.c
- Committer:
- andrewboyson
- Date:
- 2018-01-27
- Revision:
- 67:b89a81c6ed99
- Parent:
- 64:2f5db0839b09
- Child:
- 70:74c11fb71a15
File content as of revision 67:b89a81c6ed99:
#include <stdint.h> #include "defs.h" #include "nicdefs.h" #include "nicmac.h" #include "log.h" #define NUM_RX_FRAMES 6 // Number of Rx Frames (== packets) was 3 #define NUM_TX_FRAMES 4 // Number of Tx Frames (== packets) was 2 #define ETH_FRAME_LEN 1536 // Maximum Ethernet Frame Size /* Total length is NUM_RX * ((2 * 4) + (2 * 4) + 0x600) + NUM_TX * ((2 * 4) + (1 * 4) + 0x600) 1 * 1552 1548 Can fit up to 10 in total eg 6 * 1552 + 4 * 1548 = 9312 + 6192 = 15504 */ __attribute__((section("AHBSRAM1"),aligned(4))) static volatile uint8_t r_buff[NUM_RX_FRAMES][ETH_FRAME_LEN]; __attribute__((section("AHBSRAM1"),aligned(4))) static volatile uint8_t t_buff[NUM_TX_FRAMES][ETH_FRAME_LEN]; __attribute__((section("AHBSRAM1"),aligned(4))) static volatile RX_DESC_TypeDef r_desc[NUM_RX_FRAMES]; __attribute__((section("AHBSRAM1"),aligned(8))) static volatile RX_STAT_TypeDef r_stat[NUM_RX_FRAMES]; //Must be aligned on an 8 byte boundary __attribute__((section("AHBSRAM1"),aligned(4))) static volatile TX_DESC_TypeDef t_desc[NUM_TX_FRAMES]; __attribute__((section("AHBSRAM1"),aligned(4))) 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) { mac[5] = LPC_EMAC->SA0 >> 8; mac[4] = LPC_EMAC->SA0 & 0xFF; mac[3] = LPC_EMAC->SA1 >> 8; mac[2] = LPC_EMAC->SA1 & 0xFF; mac[1] = LPC_EMAC->SA2 >> 8; mac[0] = LPC_EMAC->SA2 & 0xFF; } 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) { LogTimeF("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 // 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 NicMac(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; // 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; }