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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers nic.c Source File

nic.c

00001 #include <arm_compat.h>
00002 #include <stdint.h>
00003 
00004 #include "nicdefs.h"
00005 #include "semihost.h"
00006 #include "log.h"
00007 
00008 #define NUM_RX_FRAMES       6           // Number of Rx Frames (== packets) was 3
00009 #define NUM_TX_FRAMES       4           // Number of Tx Frames (== packets) was 2
00010 
00011 #define ETH_FRAME_LEN       1536        // Maximum Ethernet Frame Size
00012 /*
00013 Total length is NUM_RX * ((2 * 4) + (2 * 4) + 0x600) + NUM_TX * ((2 * 4) + (1 * 4) + 0x600)
00014                     1  *  1552                              1548    
00015                     
00016 Can fit up to 10 in total
00017 eg 6 * 1552 + 4 * 1548 = 9312 + 6192 = 15504
00018 */
00019 
00020 
00021 __attribute__((section("AHBSRAM1"),aligned(4))) static volatile         uint8_t r_buff[NUM_RX_FRAMES][ETH_FRAME_LEN];
00022 __attribute__((section("AHBSRAM1"),aligned(4))) static volatile         uint8_t t_buff[NUM_TX_FRAMES][ETH_FRAME_LEN];
00023 __attribute__((section("AHBSRAM1"),aligned(4))) static volatile RX_DESC_TypeDef r_desc[NUM_RX_FRAMES];
00024 __attribute__((section("AHBSRAM1"),aligned(8))) static volatile RX_STAT_TypeDef r_stat[NUM_RX_FRAMES]; //Must be aligned on an 8 byte boundary
00025 __attribute__((section("AHBSRAM1"),aligned(4))) static volatile TX_DESC_TypeDef t_desc[NUM_TX_FRAMES];
00026 __attribute__((section("AHBSRAM1"),aligned(4))) static volatile TX_STAT_TypeDef t_stat[NUM_TX_FRAMES];
00027 
00028 char* NicGetReceivedPacketOrNull(int* pSize)
00029 {    
00030     if (RX_PRODUCE_INDEX == RX_CONSUME_INDEX) return NULL;
00031         
00032     uint32_t info = r_stat[RX_CONSUME_INDEX].Info;
00033     *pSize = (info & RINFO_SIZE) + 1 - 4; // exclude checksum
00034         
00035     return (char*)r_buff[RX_CONSUME_INDEX];
00036 }
00037 void NicReleaseReceivedPacket()
00038 {
00039     if (RX_CONSUME_INDEX == RX_DESCRIPTOR_NUMBER) RX_CONSUME_INDEX = 0;
00040     else                                          RX_CONSUME_INDEX++;
00041 }
00042 char* NicGetTransmitPacketOrNull(int* pSize)
00043 {
00044     if (TX_CONSUME_INDEX == 0 && TX_PRODUCE_INDEX == TX_DESCRIPTOR_NUMBER) return NULL;
00045     if (TX_PRODUCE_INDEX == TX_CONSUME_INDEX - 1)                          return NULL;
00046     *pSize = ETH_FRAME_LEN - 4;
00047     return (char*)t_buff[TX_PRODUCE_INDEX];
00048 }
00049 void NicSendTransmitPacket(int size)
00050 {
00051     if (size == 0) return;
00052     t_desc[TX_PRODUCE_INDEX].Ctrl = (size - 1) | (TCTRL_INT | TCTRL_LAST);
00053     if (TX_PRODUCE_INDEX == TX_DESCRIPTOR_NUMBER) TX_PRODUCE_INDEX = 0;
00054     else                                          TX_PRODUCE_INDEX++;
00055 }
00056 
00057 static void txdscr_init()
00058 {
00059     int i;
00060 
00061     for(i = 0; i < NUM_TX_FRAMES; i++)
00062     {
00063         t_desc[i].Packet = (uint32_t)&t_buff[i];
00064         t_desc[i].Ctrl   = 0;
00065         t_stat[i].Info   = 0;
00066     }
00067 
00068     TX_DESCRIPTOR       = (uint32_t)t_desc;         /* Set EMAC Transmit Descriptor Registers. */
00069     TX_STATUS           = (uint32_t)t_stat;
00070     TX_DESCRIPTOR_NUMBER = NUM_TX_FRAMES - 1;
00071 
00072     TX_PRODUCE_INDEX  = 0;                           /* Tx Descriptors Point to 0 */
00073 }
00074 
00075 static void rxdscr_init()
00076 {
00077     int i;
00078 
00079     for(i = 0; i < NUM_RX_FRAMES; i++)
00080     {
00081         r_desc[i].Packet  = (uint32_t)&r_buff[i];
00082         r_desc[i].Ctrl    = RCTRL_INT | (ETH_FRAME_LEN-1);
00083         r_stat[i].Info    = 0;
00084         r_stat[i].HashCRC = 0;
00085     }
00086 
00087     RX_DESCRIPTOR       = (uint32_t)r_desc;        /* Set EMAC Receive Descriptor Registers. */
00088     RX_STATUS           = (uint32_t)r_stat;        //Must be aligned on an 8 byte boundary
00089     RX_DESCRIPTOR_NUMBER = NUM_RX_FRAMES - 1;
00090 
00091     RX_CONSUME_INDEX  = 0;                          /* Rx Descriptors Point to 0 */
00092 }
00093 static int phy_write(unsigned int PhyReg, unsigned short Data)
00094 {
00095     unsigned int timeOut;
00096 
00097     MADR = DP83848C_DEF_ADR | PhyReg;
00098     MWTD = Data;
00099 
00100     // Wait until operation completed
00101     for(timeOut = 0; timeOut < MII_WR_TOUT; timeOut++)
00102     {
00103         if((MIND & MIND_BUSY) == 0)  return 0;
00104     }
00105 
00106     //Timed out
00107     return -1;
00108 }
00109 
00110 static int phy_read(unsigned int PhyReg)
00111 {
00112     unsigned int timeOut;
00113 
00114     MADR = DP83848C_DEF_ADR | PhyReg;
00115     MCMD = MCMD_READ;
00116 
00117     // Wait until operation completed
00118     for(timeOut = 0; timeOut < MII_RD_TOUT; timeOut++)
00119     {
00120         if((MIND & MIND_BUSY) == 0)
00121         {
00122             MCMD = 0;
00123             return MRDD; // Return a 16-bit value.
00124         }
00125     }
00126     return -1;
00127 }
00128 
00129 void NicLinkAddress(char *mac)
00130 {
00131     mac[5] = SA0 >> 8;
00132     mac[4] = SA0 & 0xFF;
00133     mac[3] = SA1 >> 8;
00134     mac[2] = SA1 & 0xFF;
00135     mac[1] = SA2 >> 8;
00136     mac[0] = SA2 & 0xFF;
00137 }
00138 
00139 void NicLinkSetSpeedDuplex(int speed, int duplex)
00140 {
00141     unsigned short phy_data;
00142     int tout;
00143 
00144     if((speed < 0) || (speed > 1)) phy_data = PHY_AUTO_NEG;
00145     else                           phy_data = (((unsigned short) speed << 13) | ((unsigned short) duplex << 8));
00146 
00147     phy_write(PHY_REG_BMCR, phy_data);
00148 
00149     for(tout = 100; tout; tout--) __nop();     /* A short delay */
00150     
00151     phy_data = phy_read(PHY_REG_STS);
00152 
00153     if(phy_data & PHY_STS_DUPLEX)
00154     {
00155         MAC2    |= MAC2_FULL_DUP;
00156         COMMAND |=   CR_FULL_DUP;
00157         IPGT     = IPGT_FULL_DUP;
00158     }
00159     else
00160     {
00161         MAC2    &= ~MAC2_FULL_DUP;
00162         COMMAND &=   ~CR_FULL_DUP;
00163         IPGT     =  IPGT_HALF_DUP;
00164     }
00165 
00166     if(phy_data & PHY_STS_SPEED)
00167     {
00168         SUPP &= ~SUPP_SPEED;
00169     }
00170     else
00171     {
00172         SUPP |= SUPP_SPEED;
00173     }
00174 }
00175 
00176 int NicLinkIsUp(void)
00177 {
00178     return (phy_read(PHY_REG_STS) & PHY_STS_LINK);
00179 }
00180 static int phy_reset()
00181 {
00182     int regv, tout;
00183     
00184     // perform PHY reset
00185     phy_write(PHY_REG_BMCR, PHY_BMCR_RESET);           
00186   
00187     // Wait for hardware reset to end.
00188     for(tout = 0x20000; ; tout--)
00189     {                    
00190         regv = phy_read(PHY_REG_BMCR);
00191         if(regv < 0 || tout == 0)     return -1;  // Error
00192         if(!(regv & PHY_BMCR_RESET))  break;      // Reset complete.
00193     }
00194     uint32_t phy_id  = (phy_read(PHY_REG_IDR1) << 16);
00195     phy_id |= (phy_read(PHY_REG_IDR2) & 0XFFF0);
00196 
00197     //Check is the right PHY
00198     if (phy_id != DP83848C_ID)
00199     {
00200         LogTimeF("Unknown Ethernet PHY (%x)", (unsigned int)phy_id);
00201         return -1;
00202     }
00203     return 0;
00204 }
00205 int NicInit()
00206 {
00207     int tout;
00208     char mac[6];
00209     unsigned int clock = 10; //96,000,000
00210     
00211     // Reset all EMAC internal modules.
00212     MAC1    = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
00213     COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
00214     
00215     // A short delay after reset.
00216     for(tout = 100; tout; tout--) __nop();             
00217     
00218     // Initialize MAC control registers.
00219     MAC1 = MAC1_PASS_ALL;                   
00220     MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
00221     MAXF = ETH_FRAME_LEN;
00222     CLRT = CLRT_DEF;
00223     IPGR = IPGR_DEF;
00224     
00225     // Enable Reduced MII interface.
00226     COMMAND = CR_RMII | CR_PASS_RUNT_FRM;    
00227     
00228     // Set clock and reset
00229     MCFG = (clock << 0x2) & MCFG_CLK_SEL;
00230     MCFG |= MCFG_RES_MII;
00231     
00232     // A short delay after reset
00233     for(tout = 100; tout; tout--) __nop();
00234     
00235     // Set clock
00236     MCFG = (clock << 0x2) & MCFG_CLK_SEL;
00237     MCMD = 0;
00238     
00239     // Reset Reduced MII Logic.
00240     SUPP = SUPP_RES_RMII;                    
00241     
00242     // A short delay
00243     for (tout = 100; tout; tout--) __nop();
00244     
00245     SUPP = 0;
00246     
00247     //Reset the PHY
00248     if (phy_reset()) return -1;
00249     
00250     //Set the link to auto negotiate
00251     NicLinkSetSpeedDuplex(-1, 0);
00252     
00253     // Set the Ethernet MAC Address registers
00254     SemihostMac(mac);
00255     SA0 = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4];
00256     SA1 = ((uint32_t)mac[3] << 8) | (uint32_t)mac[2];
00257     SA2 = ((uint32_t)mac[1] << 8) | (uint32_t)mac[0];
00258     
00259     //Initialise DMA descriptors
00260     txdscr_init();
00261     rxdscr_init();
00262     
00263     // Set filter
00264     RX_FILTER_CTRL = RFC_UCAST_EN | RFC_MCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
00265                                                       
00266     // Disable and clear EMAC interrupts
00267     INT_ENABLE = 0;
00268     INT_CLEAR  = 0xFFFF;
00269     
00270     //Enable receive and transmit
00271     COMMAND  |= (CR_RX_EN | CR_TX_EN);
00272     MAC1     |= MAC1_REC_EN;
00273     
00274     //Return success
00275     return 0;
00276 }