MityDSP Documentation Index

Initializing the MityDSP Network Interface

The MityDSP system allows flexible configuration of hardware and software. Since the hardware in the FPGA can be modified for your particular application, you may also need access to different Ethernet device drivers. The MityDSP net library allows this by using a C++ class derived from a generic Ethernet driver base class. Inside the net module all driver calls are made to a tcNetDrvr base class type object. You specify the actual driver type by creating a driver object from a class derived from tcNetDrvr, then you pass a pointer to the derived driver object to the netif_add function.

Most MityDSP applications can use the stock MAC network driver and FPGA core, which is the tcNetDrvr_B() class, and the example code provided below should be appropriate for initialization of the network/stack API.

For the MityDSP-Pro, applications may use the tcNetDrvr_B() class for use with the legacy MAC FPGA core, or they may use the tcNetDrvr_645x() class which provides an lwIP compatible driver for the on-chip DSP EMAC engine, or both.

Two key parameters that require attention are the tcpip_priority field and the nacb_func field of the tsDSPNetStackInit structure. The tcpip_priority field sets the priority of the network stack, which must be higher than all other threads utilizing the stack. In order to gaurantee known prioritization, this value should be defined by the application. The nacb_func callback function is used by the lwIP stack to notify the user of critical failures associated with using the network. This function should *always* be assigned so that developers are appropriately notified of network issues, as in general the errors raised are user errors (e.g., registering a thread at a priority higher than the stack, registering more threads than allowed by the stack, not registering a thread on the stack, etc.).

See also:
tcNetDrvr_B, DSPNetStackInit, tcNetDrvr_645x

Initializing the MityDSP Network Interface

The following simple example will setup a derived Ethernet driver object designed for the standard MityDSP boards.

 #include <std.h>
 #include <clk.h>

 #include <string_extras.h>
 #include <core/DspFirmware.h>
 #include <core/DspConfig.h>
 #include <core/DspError.h>
 #include <core/DspSpi.h>
 #include <core/DspTimer.h>
 #include <net/DSPNetStack.h>
 #include <net/net_iface.h>
 #include <net/net_drvr/net_drvr_b.h>
 #include <net/DSPNetIFConfigUtil.h>
 
 using namespace MityDSP;
 
 #define READ_CONFIG_FROM_FLASH 1

 // ethernet default init
 #define IP_ADDR_INIT { 192, 168, 0, 192 }
 #define SUBNET_INIT  { 255, 255, 255, 0 }
 #define GATEWAY_INIT { 192, 168, 0, 1 }
 #define MAC_INIT     { 0, 4, 0, 4, 0, 5 }
 
 const int gnNET_TCP_PRIORITY = (TSK_MINPRI + 10);

 unsigned int mnTicksPerMsec = CLK_countspms() / CLK_getprd();
 tcNetDrvr_B *mpNetDrvr = NULL;

 void lwipAssertReport(const char *apMsg)
 {
     tcDspError::report(__FILE__, __LINE__, error, "LWIP ASSERT: %s", apMsg);
 }
 
 
 void lwipStackInit(unsigned int anEnetBase, tcDspSpi *apSpi)
 {
     bool                                 success;
     unsigned char                        g_ip_addr[4]  = IP_ADDR_INIT;
     unsigned char                        g_subnet[4]   = SUBNET_INIT;
     unsigned char                        g_gw_addr[4]  = GATEWAY_INIT;
     tcDspNetIFConfigUtil::tsDspNetConfig netconfig;
     tcDspNetIFConfigUtil*                configutil;
     struct ip_addr                       ipaddr;
     struct ip_addr                       netmask;
     struct ip_addr                       gateway;
     tsDSPNetStackInit                    si;
     tsNetPhyStatus                       phyStatus;
     teNetPhyType                         phyType;
     static struct netif                  netif;
     static tsNetIface                    NetIface;
 
     #ifdef READ_CONFIG_FROM_FLASH

     // Get stored data from FLASH.  This class will generate DHCP enabled defaults if 
     // no valid FLASH configuration has been stored.  Assumes location is at base of 
     // application data area.  Change this per requirements.
     configutil = new tcDspNetIFConfigUtil(mpFlash, tcDspConfig::GetInstance(mpFlash),
                                           tcDspConfig::GetInstance(mpFlash)->GetAppDataOffset());
     configutil->GetConfig(&netconfig);

     #else

     netconfig.mnUseDHCP = true;   // set to true to obtain IP addr via DHCP
     if (useDHCP)
     {
         IP4_ADDR(&netconfig.msIpAddr, 0, 0, 0, 0);
         IP4_ADDR(&netconfig.msNetmask, 0, 0, 0, 0);
         IP4_ADDR(&netconfig.msGateway, 0, 0, 0, 0);
     }
     else
     {
         IP4_ADDR(&netconfig.msIpAddr,  g_ip_addr[0], g_ip_addr[1], g_ip_addr[2], g_ip_addr[3]);
         IP4_ADDR(&netconfig.msNetmask, g_subnet[0],  g_subnet[1],  g_subnet[2],  g_subnet[3]);
         IP4_ADDR(&netconfig.msGateway, g_gw_addr[0], g_gw_addr[1], g_gw_addr[2], g_gw_addr[3]);
     }

     // placeholder, you must launch WINS manually using DspWins.lib         
     sprintf(netconfig.maNetBIOSName,"My BIOS Name");  
     netconfig.mnUseWINS = false;
     sprintf(netconfig.maPolledName,"My Locator Name");  
     sprintf(netconfig.maDescription,"My Locator Description");  
     tcDspConfig::GetInstance(mpFlash)->GetMACAddress((unsigned char*)netconfig.maMACAddress);
     configutil = new tcDspNetIFConfigUtil(tcDspConfig::GetInstance(mpFlash),&netconfig);    

     #endif
 
     // Do low level stack initialization...
     DSPGetNetStackDefaults(&si);
     si.tcpip_priority = gnNET_TCP_PRIORITY; // default priority=5, must be higher than
                                             //   all stack users
     si.nacb_func      = lwipAssertReport;   // set LWIP assert notification so errors
                                             // are displayed while debugging
     DSPNetStackInit(&si);
 
     #ifdef USE_645X_EMAC
     // instantiate the network driver for the C645x on-chip EMAC on HWI vector 8
     mpNetDrvr = new tcNetDrvr_645x(g_mac_addr, 8);
     #else
     // instantiate the network driver (default: use RX and TX DMA, DMA thread prio=14)
     mpNetDrvr = new tcNetDrvr_B(g_mac_addr, (void *)anEnetBase);
     #endif
 
     // set default values for NetIface (prio=5, stack=4K, mbox=10 entries)
     net_iface_set_defaults(&NetIface, (tcNetDrvr *)mpNetDrvr);
     NetIface.mnRxThreadPriority = si.tcpip_priority + 1;  // must be higher than stack
 
     memset(&netif, 0, sizeof(netif));
     netif_add(&netif, &netconfig.msIpAddr, &netconfig.msNetmask, &netconfig.msGateway,
               &NetIface, net_iface_init, tcpip_input);
     netif_set_default(&netif);
 
     // some PHY-specific set-up...
     phyType = mpNetDrvr->GetPhyType();
 
     // for DP83848, make sure auto-MDIX is enabled
     if (phyType == eeNationalDP83848)
     {
         mpNetDrvr->SetMIIRegister(0x19, (mpNetDrvr->GetMIIRegister(0x19) | 0x8000));
     }
 
     // for BCM5221, put LEDs in the proper mode
     if (phyType == eeBroadcomBCM5221)
     {
         mpNetDrvr->SetMIIRegister(0x1A, (mpNetDrvr->GetMIIRegister(0x1A) & ~0xC000));
     }
 
     // If PHY is KS8995, try using the SPI to enable a built-in managed Ethernet switch...
     if (phyType == eeMicrelKS8995)
     {
         tcDspSpi::tuFifoData FifoData;
 
         FifoData.mnLword = 0x00020101;    // 02=write register, 01=register #1, 01=value to write
         if (apSpi) apSpi->WriteData(&FifoData, 1);
     }
 
     if (netconfig.mnUseDHCP)
     {
         if (dhcp_start(&netif) == ERR_OK)
         {
             tcDspError::report(__FILE__, __LINE__, status ,
                                "DHCP Initialized");
         }
         else
         {
             tcDspError::report(__FILE__, __LINE__, warning,
                                "DHCP Initialization Failed");
         }
 
         // Don't allow any more network activity until DHCP completes...
         // NOTE:  This will block the thread indefinitely.  Depending on the
         //        nature of the application, it may be necessary to provide
         //        a timeout, or check for completion at the time the stack is
         //        to be used.  At any rate, do *not* attempt to use an
         //        interface while its IP address is still 0.0.0.0.
         int count=0;
         while (netif_is_up(&netif) == false)
         {
             TSK_sleep(1000 * mnTicksPerMsec);
 
             // Timeout DHCP and assign default IP address
             if (++count > 20)
             {
                 dhcp_stop(&netif);
                 IP4_ADDR(&netconfig.msIpAddr, 
                          g_ip_addr[0], g_ip_addr[1], g_ip_addr[2], g_ip_addr[3]);
                 IP4_ADDR(&netconfig.msNetmask,
                          g_subnet[0],  g_subnet[1],  g_subnet[2],  g_subnet[3]);
                 IP4_ADDR(&netconfig.msGateway,
                          g_gw_addr[0], g_gw_addr[1], g_gw_addr[2], g_gw_addr[3]);
                 netif_set_addr(&netif, netconfig.msIpAddr, &netconfig.msNetmask, 
                                &netconfig.msGateway);
                 netif_set_up(&netif);
                 break;
             }
         }
     }
     else
     {
         netif_set_up(&netif);
     }
 
     // report network settings
     tcDspError::report(__FILE__,__LINE__, status,
                        "Network Address = %d.%d.%d.%d",
                        netif.ip_addr.addr&0xFF,
                        (netif.ip_addr.addr&0xFF00) >> 8,
                        (netif.ip_addr.addr&0xFF0000) >> 16,
                        (netif.ip_addr.addr&0xFF000000) >> 24);
 
     // ...and some basic status
     success = mpNetDrvr->GetPhyStatus(phyStatus);
 
     tcDspError::report(__FILE__,__LINE__, status,
                        "PHY type is %s",
                        ((phyStatus.meType == eeNationalDP83848) ? "National DP83848":
                         ((phyStatus.meType == eeCrystalLanCS8952) ? "Crystal LAN CS8952":
                          ((phyStatus.meType == eeBroadcomBCM5221) ? "Broadcom BCM5221":
                           ((phyStatus.meType == eeMicrelKS8995) ? "Micrel KS8995":
                            "Unknown")))));
 
     if (success)
     {
         tcDspError::report(__FILE__,__LINE__, status,
                            "Link is %s, %s Mbps, %s Duplex, MDI %s",
                            (phyStatus.mbLinkUp ? "Up" : "Down"),
                            ((phyStatus.meSpeed == eeSpeed10Mbps) ? "10":
                             ((phyStatus.meSpeed == eeSpeed100Mbps) ? "100":
                              ((phyStatus.meSpeed == eeSpeed1Gbps) ? "1000": "???"))),
                            (phyStatus.mbFullDuplex ? "Full" : "Half"),
                            (phyStatus.mbMdiSwapped ? "Swapped" : "Normal"));
     }
 
     // get KS8995 status for all 4 ports via SPI
     else if (phyType == eeMicrelKS8995)
     {
         tcDspSpi::tuFifoData FifoData;
 
         // report status for 4 external ports
         for (int port=0; port<4; port++)
         {
             FifoData.mnLword = 0x00031E00 + (port * 0x00001000);
             if (apSpi) apSpi->ReadData(&FifoData, 1);
 
             tcDspError::report(__FILE__,__LINE__, status,
                                "Port %1d: Link is %s, %s Mbps, %s Duplex, MDI %s", port+1,
                                ((FifoData.ms8Bit.mnFifoData & 0x00000020) ? "Up" : "Down"),
                                ((FifoData.ms8Bit.mnFifoData & 0x0000000C) ? "100": "10"),
                                ((FifoData.ms8Bit.mnFifoData & 0x0000000A) ? "Full" : "Half"),
                                ((FifoData.ms8Bit.mnFifoData & 0x00000080) ? "Normal" : "Swapped"));
         }
     }

     // optional, run MityDSPLocator query server 
     mpNetIFConfigUtil->RunQueryServer(&msNetIf);
 
     // this would be a good place to launch the WINS server if desired as well...

     return;
 }

  
Generated on Wed Mar 17 18:24:38 2010 for MityDSP Net by  Doxygen Version 1.6.1
Copyright © 2009, Critical Link LLC, All rights reserved.